/* Send a payload buffer to a connected port/client */ static MMAL_STATUS_T mmal_port_clock_forward_payload(MMAL_PORT_T *port, const MMAL_CLOCK_PAYLOAD_T *payload) { MMAL_STATUS_T status; MMAL_BUFFER_HEADER_T *buffer; buffer = mmal_queue_get(port->priv->module->queue); if (!buffer) { LOG_ERROR("no free buffers available"); return MMAL_ENOSPC; } status = mmal_buffer_header_mem_lock(buffer); if (status != MMAL_SUCCESS) { LOG_ERROR("failed to lock buffer %s", mmal_status_to_string(status)); mmal_queue_put_back(port->priv->module->queue, buffer); goto end; } buffer->length = sizeof(MMAL_CLOCK_PAYLOAD_T); memcpy(buffer->data, payload, buffer->length); mmal_buffer_header_mem_unlock(buffer); mmal_port_buffer_header_callback(port, buffer); end: return status; }
/** Flush a port */ MMAL_STATUS_T mmal_port_flush(MMAL_PORT_T *port) { MMAL_BUFFER_HEADER_T *buffer = 0; MMAL_STATUS_T status; if (!port || !port->priv) return MMAL_EINVAL; LOG_TRACE("%s(%i:%i) port %p", port->component->name, (int)port->type, (int)port->index, port); if (!port->priv->pf_flush) return MMAL_ENOSYS; mmal_component_action_lock(port->component); LOCK_SENDING(port); status = port->priv->pf_flush(port); if (status == MMAL_SUCCESS) { /* Flush our internal queue */ buffer = port->priv->core->queue_first; port->priv->core->queue_first = 0; port->priv->core->queue_last = &port->priv->core->queue_first; } UNLOCK_SENDING(port); mmal_component_action_unlock(port->component); while (buffer) { MMAL_BUFFER_HEADER_T *next = buffer->next; mmal_port_buffer_header_callback(port, buffer); buffer = next; } return status; }
/** Send a buffer header to a port */ static MMAL_STATUS_T splitter_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { MMAL_COMPONENT_T *component = port->component; MMAL_COMPONENT_MODULE_T *module = component->priv->module; MMAL_PORT_T *in_port, *out_port; MMAL_BUFFER_HEADER_T *in; MMAL_STATUS_T status; unsigned int i; mmal_queue_put(port->priv->module->queue, buffer); if (module->error) return MMAL_SUCCESS; /* Just do nothing */ /* Get input buffer header */ in_port = component->input[0]; in = mmal_queue_get(in_port->priv->module->queue); if (!in) return MMAL_SUCCESS; /* Nothing to do */ for (i = 0; i < component->output_num; i++) { out_port = component->output[i]; status = splitter_send_output(in, out_port); if (status != MMAL_SUCCESS && status != MMAL_EAGAIN) goto error; if (status == MMAL_SUCCESS) module->sent_flags |= (1<<i); } /* Check if we're done with the input buffer */ if ((module->sent_flags & module->enabled_flags) == module->enabled_flags) { in->length = 0; /* Consume the input buffer */ mmal_port_buffer_header_callback(in_port, in); module->sent_flags = 0; return MMAL_SUCCESS; } /* We're not done yet so put the buffer back in the queue */ mmal_queue_put(in_port->priv->module->queue, in); return MMAL_SUCCESS; error: mmal_queue_put(in_port->priv->module->queue, in); status = mmal_event_error_send(port->component, status); if (status != MMAL_SUCCESS) { LOG_ERROR("unable to send an error event buffer (%i)", (int)status); return MMAL_SUCCESS; } module->error = 1; return MMAL_SUCCESS; }
static MMAL_STATUS_T mmal_port_disable_internal(MMAL_PORT_T *port) { MMAL_PORT_PRIVATE_CORE_T* core = port->priv->core; MMAL_STATUS_T status = MMAL_SUCCESS; MMAL_BUFFER_HEADER_T *buffer; LOCK_PORT(port); if (!port->is_enabled) goto end; LOCK_SENDING(port); port->is_enabled = 0; UNLOCK_SENDING(port); mmal_component_action_lock(port->component); if (core->pool_for_connection) mmal_pool_callback_set(core->pool_for_connection, NULL, NULL); status = port->priv->pf_disable(port); mmal_component_action_unlock(port->component); if (status != MMAL_SUCCESS) { LOG_ERROR("port %p could not be disabled (%s)", port->name, mmal_status_to_string(status)); LOCK_SENDING(port); port->is_enabled = 1; UNLOCK_SENDING(port); goto end; } /* Flush our internal queue */ buffer = port->priv->core->queue_first; while (buffer) { MMAL_BUFFER_HEADER_T *next = buffer->next; mmal_port_buffer_header_callback(port, buffer); buffer = next; } port->priv->core->queue_first = 0; port->priv->core->queue_last = &port->priv->core->queue_first; /* Wait for all the buffers to have come back from the component */ LOG_DEBUG("%s waiting for %i buffers left in transit", port->name, (int)IN_TRANSIT_COUNT(port)); IN_TRANSIT_WAIT(port); LOG_DEBUG("%s has no buffers left in transit", port->name); port->priv->core->buffer_header_callback = NULL; end: UNLOCK_PORT(port); return status; }
static MMAL_STATUS_T mmal_port_clock_flush(MMAL_PORT_T *port) { MMAL_BUFFER_HEADER_T *buffer; /* Flush empty buffers */ buffer = mmal_queue_get(port->priv->module->queue); while (buffer) { mmal_port_buffer_header_callback(port, buffer); buffer = mmal_queue_get(port->priv->module->queue); } return MMAL_SUCCESS; }
/** Flush a port */ static MMAL_STATUS_T sdl_port_flush(MMAL_PORT_T *port) { MMAL_COMPONENT_T *component = port->component; MMAL_COMPONENT_MODULE_T *module = component->priv->module; MMAL_BUFFER_HEADER_T *buffer; /* Flush buffers that our component is holding on to. * If the reading thread is holding onto a buffer it will send it back ASAP as well * so no need to care about that. */ while((buffer = mmal_queue_get(module->queue))) mmal_port_buffer_header_callback(port, buffer); return MMAL_SUCCESS; }
/** Flush a port */ static MMAL_STATUS_T splitter_port_flush(MMAL_PORT_T *port) { MMAL_PORT_MODULE_T *port_module = port->priv->module; MMAL_BUFFER_HEADER_T *buffer; /* Flush buffers that our component is holding on to */ buffer = mmal_queue_get(port_module->queue); while(buffer) { mmal_port_buffer_header_callback(port, buffer); buffer = mmal_queue_get(port_module->queue); } if (port->type == MMAL_PORT_TYPE_INPUT) port->component->priv->module->sent_flags = 0; return MMAL_SUCCESS; }
/* Process buffers received from other clock ports */ static MMAL_STATUS_T mmal_port_clock_process_buffer(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { MMAL_STATUS_T status = MMAL_SUCCESS; MMAL_CLOCK_PAYLOAD_T payload; if (buffer->length != sizeof(MMAL_CLOCK_PAYLOAD_T)) { LOG_ERROR("invalid buffer length %d", buffer->length); return MMAL_EINVAL; } mmal_buffer_header_mem_lock(buffer); memcpy(&payload, buffer->data, sizeof(MMAL_CLOCK_PAYLOAD_T)); mmal_buffer_header_mem_unlock(buffer); if (payload.magic != MMAL_CLOCK_PAYLOAD_MAGIC) { LOG_ERROR("buffer corrupt (magic %4.4s)", (char*)&payload.magic); return MMAL_EINVAL; } LOG_TRACE("port %s length %d id %4.4s time %"PRIi64, port->name, buffer->length, (char*)&payload.id, payload.time); switch (payload.id) { case MMAL_CLOCK_PAYLOAD_TIME: mmal_clock_media_time_set(port->priv->module->clock, payload.time); break; case MMAL_CLOCK_PAYLOAD_SCALE: mmal_clock_scale_set(port->priv->module->clock, payload.data.scale); break; default: LOG_ERROR("invalid id %4.4s", (char*)&payload.id); status = MMAL_EINVAL; break; } /* Finished with the buffer, so return it */ buffer->length = 0; mmal_port_buffer_header_callback(port, buffer); return status; }
/** Send a buffer header to a port */ static MMAL_STATUS_T splitter_send_output(MMAL_BUFFER_HEADER_T *buffer, MMAL_PORT_T *out_port) { MMAL_BUFFER_HEADER_T *out; MMAL_STATUS_T status; /* Get a buffer header from output port */ out = mmal_queue_get(out_port->priv->module->queue); if (!out) return MMAL_EAGAIN; /* Copy our input buffer header */ status = mmal_buffer_header_replicate(out, buffer); if (status != MMAL_SUCCESS) goto error; /* Send buffer back */ mmal_port_buffer_header_callback(out_port, out); return MMAL_SUCCESS; error: mmal_queue_put_back(out_port->priv->module->queue, out); return status; }
static MMAL_BOOL_T sdl_do_processing(MMAL_COMPONENT_T *component) { MMAL_PORT_T *port = component->input[0]; MMAL_COMPONENT_MODULE_T *module = component->priv->module; unsigned int width = port->format->es->video.width; unsigned int height = port->format->es->video.height; MMAL_BUFFER_HEADER_T *buffer; uint8_t *src_plane[3]; uint32_t *src_pitch; unsigned int i, line; MMAL_BOOL_T eos; SDL_Rect rect; buffer = mmal_queue_get(module->queue); if (!buffer) return 0; eos = buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS; /* Handle event buffers */ if (buffer->cmd) { MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(buffer); if (event) { mmal_format_copy(port->format, event->format); module->status = port->priv->pf_set_format(port); if (module->status != MMAL_SUCCESS) { LOG_ERROR("format not set on port %p", port); if (mmal_event_error_send(port->component, module->status) != MMAL_SUCCESS) LOG_ERROR("unable to send an error event buffer"); } } else { LOG_ERROR("discarding event %i on port %p", (int)buffer->cmd, port); } buffer->length = 0; mmal_port_buffer_header_callback(port, buffer); return 1; } if (module->status != MMAL_SUCCESS) return 1; /* Ignore empty buffers */ if (!buffer->length) goto end; // FIXME: sanity check the size of the buffer /* Blit the buffer onto the overlay. */ src_pitch = buffer->type->video.pitch; src_plane[0] = buffer->data + buffer->type->video.offset[0]; src_plane[1] = buffer->data + buffer->type->video.offset[2]; src_plane[2] = buffer->data + buffer->type->video.offset[1]; SDL_LockYUVOverlay(module->sdl_overlay); for (i=0; i<3; i++) { uint8_t *src = src_plane[i]; uint8_t *dst = module->sdl_overlay->pixels[i]; if(i == 1) {width /= 2; height /= 2;} for(line = 0; line < height; line++) { memcpy(dst, src, width); src += src_pitch[i]; dst += module->sdl_overlay->pitches[i]; } } SDL_UnlockYUVOverlay(module->sdl_overlay); width = port->format->es->video.width; height = port->format->es->video.height; rect.x = module->display_region.x; rect.w = module->display_region.width; height = rect.w * height / width; rect.y = module->display_region.y + (module->display_region.height - height) / 2; rect.h = height; SDL_DisplayYUVOverlay(module->sdl_overlay, &rect); end: buffer->offset = buffer->length = 0; mmal_port_buffer_header_callback(port, buffer); /* Generate EOS events */ if (eos) mmal_event_eos_send(port); return 1; }