static gboolean handle_event (GstBaseSrc * gst_base, GstEvent * event) { GstOmxBaseSrc *self; self = GST_OMX_BASE_SRC (gst_base); GST_LOG_OBJECT (self, "begin"); GST_DEBUG_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: /* Close the output port. */ g_omx_core_set_done (self->gomx); break; case GST_EVENT_NEWSEGMENT: break; default: break; } GST_LOG_OBJECT (self, "end"); return true; }
static gboolean handle_event (GstBaseSink *gst_base, GstEvent *event) { GstOmxBaseSink *self; GOmxCore *gomx; GOmxPort *in_port; self = GST_OMX_BASE_SINK (gst_base); gomx = self->gomx; in_port = self->in_port; GST_LOG_OBJECT (self, "begin"); GST_DEBUG_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: /* Close the inpurt port. */ g_omx_core_set_done (gomx); break; case GST_EVENT_FLUSH_START: /* unlock loops */ g_omx_port_pause (in_port); /* flush all buffers */ OMX_SendCommand (gomx->omx_handle, OMX_CommandFlush, OMX_ALL, NULL); break; case GST_EVENT_FLUSH_STOP: g_sem_down (gomx->flush_sem); g_omx_port_resume (in_port); break; default: break; } GST_LOG_OBJECT (self, "end"); return TRUE; }
static GstFlowReturn create (GstBaseSrc * gst_base, guint64 offset, guint length, GstBuffer ** ret_buf) { GOmxCore *gomx; GOmxPort *out_port; GstOmxBaseSrc *self; GstFlowReturn ret = GST_FLOW_OK; self = GST_OMX_BASE_SRC (gst_base); gomx = self->gomx; GST_LOG_OBJECT (self, "begin"); GST_LOG_OBJECT (self, "state: %d", gomx->omx_state); if (gomx->omx_state == OMX_StateLoaded) { GST_INFO_OBJECT (self, "omx: prepare"); setup_ports (self); g_omx_core_prepare (self->gomx); } out_port = self->out_port; while (out_port->enabled) { switch (gomx->omx_state) { case OMX_StateIdle: { GST_INFO_OBJECT (self, "omx: play"); g_omx_core_start (gomx); } break; default: break; } switch (gomx->omx_state) { case OMX_StateExecuting: /* OK */ break; default: GST_ERROR_OBJECT (self, "Whoa! very wrong"); break; } { OMX_BUFFERHEADERTYPE *omx_buffer; GST_LOG_OBJECT (self, "request_buffer"); omx_buffer = g_omx_port_request_buffer (out_port); if (omx_buffer) { GST_DEBUG_OBJECT (self, "omx_buffer: size=%lu, len=%lu, offset=%lu", omx_buffer->nAllocLen, omx_buffer->nFilledLen, omx_buffer->nOffset); if (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS) { GST_INFO_OBJECT (self, "got eos"); g_omx_core_set_done (gomx); break; } if (omx_buffer->nFilledLen > 0) { GstBuffer *buf; if (out_port->enabled) { GstCaps *caps = NULL; caps = gst_pad_get_negotiated_caps (gst_base->srcpad); if (!caps) { /** @todo We shouldn't be doing this. */ GST_WARNING_OBJECT (self, "somebody didn't do his work"); gomx->settings_changed_cb (gomx); } else { GST_LOG_OBJECT (self, "caps already fixed"); gst_caps_unref (caps); } } buf = omx_buffer->pAppPrivate; if (buf && !(omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) { GST_BUFFER_SIZE (buf) = omx_buffer->nFilledLen; #if 0 if (self->use_timestamps) { GST_BUFFER_TIMESTAMP (buf) = omx_buffer->nTimeStamp * (GST_SECOND / OMX_TICKS_PER_SECOND); } #endif omx_buffer->pAppPrivate = NULL; omx_buffer->pBuffer = NULL; omx_buffer->nFilledLen = 0; *ret_buf = buf; gst_buffer_unref (buf); } else { /* This is only meant for the first OpenMAX buffers, * which need to be pre-allocated. */ /* Also for the very last one. */ gst_pad_alloc_buffer_and_set_caps (gst_base->srcpad, GST_BUFFER_OFFSET_NONE, omx_buffer->nFilledLen, GST_PAD_CAPS (gst_base->srcpad), &buf); if (buf) { GST_WARNING_OBJECT (self, "couldn't zero-copy"); memcpy (GST_BUFFER_DATA (buf), omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen); #if 0 if (self->use_timestamps) { GST_BUFFER_TIMESTAMP (buf) = omx_buffer->nTimeStamp * (GST_SECOND / OMX_TICKS_PER_SECOND); } #endif omx_buffer->nFilledLen = 0; g_free (omx_buffer->pBuffer); omx_buffer->pBuffer = NULL; *ret_buf = buf; } else { GST_ERROR_OBJECT (self, "whoa!"); } } if (!omx_buffer->pBuffer) { GstBuffer *new_buf; GstFlowReturn result; GST_LOG_OBJECT (self, "allocate buffer"); result = gst_pad_alloc_buffer_and_set_caps (gst_base->srcpad, GST_BUFFER_OFFSET_NONE, omx_buffer->nAllocLen, GST_PAD_CAPS (gst_base->srcpad), &new_buf); if (result == GST_FLOW_OK) { gst_buffer_ref (new_buf); omx_buffer->pAppPrivate = new_buf; omx_buffer->pBuffer = GST_BUFFER_DATA (new_buf); omx_buffer->nAllocLen = GST_BUFFER_SIZE (new_buf); } else { GST_WARNING_OBJECT (self, "could not allocate buffer"); omx_buffer->pBuffer = g_malloc (omx_buffer->nAllocLen); } } GST_LOG_OBJECT (self, "release_buffer"); g_omx_port_release_buffer (out_port, omx_buffer); break; } else { GST_WARNING_OBJECT (self, "empty buffer"); GST_LOG_OBJECT (self, "release_buffer"); g_omx_port_release_buffer (out_port, omx_buffer); continue; } } else { GST_WARNING_OBJECT (self, "null buffer"); /* ret = GST_FLOW_ERROR; */ break; } } } if (!out_port->enabled) { GST_WARNING_OBJECT (self, "done"); ret = GST_FLOW_UNEXPECTED; } GST_LOG_OBJECT (self, "end"); return ret; }
static OMX_ERRORTYPE EventHandler (OMX_HANDLETYPE omx_handle, OMX_PTR app_data, OMX_EVENTTYPE event, OMX_U32 data_1, OMX_U32 data_2, OMX_PTR event_data) { GOmxCore *core; core = (GOmxCore *) app_data; switch (event) { case OMX_EventCmdComplete: { OMX_COMMANDTYPE cmd; cmd = (OMX_COMMANDTYPE) data_1; GST_DEBUG_OBJECT (core->object, "OMX_EventCmdComplete: %d", cmd); switch (cmd) { case OMX_CommandStateSet: complete_change_state (core, data_2); break; case OMX_CommandFlush: g_sem_up (core->flush_sem); break; case OMX_CommandPortDisable: case OMX_CommandPortEnable: g_sem_up (core->port_sem); default: break; } break; } case OMX_EventBufferFlag: { GST_DEBUG_OBJECT (core->object, "OMX_EventBufferFlag"); if (data_2 & OMX_BUFFERFLAG_EOS) { g_omx_core_set_done (core); } break; } case OMX_EventPortSettingsChanged: { GST_DEBUG_OBJECT (core->object, "OMX_EventPortSettingsChanged"); /** @todo only on the relevant port. */ if (core->settings_changed_cb) { core->settings_changed_cb (core); } break; } case OMX_EventError: { core->omx_error = data_1; GST_ERROR_OBJECT (core->object, "unrecoverable error: %s (0x%lx)", omx_error_to_str (data_1), data_1); /* component might leave us waiting for buffers, unblock */ g_omx_core_flush_start (core); /* unlock wait_for_state */ g_mutex_lock (core->omx_state_mutex); g_cond_signal (core->omx_state_condition); g_mutex_unlock (core->omx_state_mutex); break; } default: break; } return OMX_ErrorNone; }
static gboolean pad_event (GstPad *pad, GstEvent *event) { GstOmxBaseFilter *self; GOmxCore *gomx; GOmxPort *in_port; GOmxPort *out_port; gboolean ret; self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad)); gomx = self->gomx; in_port = self->in_port; out_port = self->out_port; GST_LOG_OBJECT (self, "begin"); GST_INFO_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: if (self->initialized) { /* send buffer with eos flag */ /** @todo move to util */ { OMX_BUFFERHEADERTYPE *omx_buffer; GST_LOG_OBJECT (self, "request buffer"); omx_buffer = g_omx_port_request_buffer (in_port); if (G_LIKELY (omx_buffer)) { omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS; GST_LOG_OBJECT (self, "release_buffer"); /* foo_buffer_untaint (omx_buffer); */ g_omx_port_release_buffer (in_port, omx_buffer); } else { g_omx_core_set_done (gomx); } } /* Wait for the output port to get the EOS. */ g_omx_core_wait_for_done (gomx); } ret = gst_pad_push_event (self->srcpad, event); break; case GST_EVENT_FLUSH_START: gst_pad_push_event (self->srcpad, event); self->last_pad_push_return = GST_FLOW_WRONG_STATE; g_omx_core_flush_start (gomx); gst_pad_pause_task (self->srcpad); ret = TRUE; break; case GST_EVENT_FLUSH_STOP: gst_pad_push_event (self->srcpad, event); self->last_pad_push_return = GST_FLOW_OK; g_omx_core_flush_stop (gomx); gst_pad_start_task (self->srcpad, output_loop, self->srcpad); ret = TRUE; break; case GST_EVENT_NEWSEGMENT: ret = gst_pad_push_event (self->srcpad, event); break; default: ret = gst_pad_push_event (self->srcpad, event); break; } GST_LOG_OBJECT (self, "end"); return ret; }
static void output_loop (gpointer data) { GstPad *pad; GOmxCore *gomx; GOmxPort *out_port; GstOmxBaseFilter *self; GstFlowReturn ret = GST_FLOW_OK; pad = data; self = GST_OMX_BASE_FILTER (gst_pad_get_parent (pad)); gomx = self->gomx; GST_LOG_OBJECT (self, "begin"); if (!self->initialized) { g_error ("not initialized"); return; } out_port = self->out_port; if (G_LIKELY (out_port->enabled)) { OMX_BUFFERHEADERTYPE *omx_buffer = NULL; GST_LOG_OBJECT (self, "request buffer"); omx_buffer = g_omx_port_request_buffer (out_port); GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer); if (G_UNLIKELY (!omx_buffer)) { GST_WARNING_OBJECT (self, "null buffer: leaving"); goto leave; } GST_DEBUG_OBJECT (self, "omx_buffer: size=%lu, len=%lu, flags=%lu, offset=%lu, timestamp=%lld", omx_buffer->nAllocLen, omx_buffer->nFilledLen, omx_buffer->nFlags, omx_buffer->nOffset, omx_buffer->nTimeStamp); if (G_LIKELY (omx_buffer->nFilledLen > 0)) { GstBuffer *buf; #if 1 /** @todo remove this check */ if (G_LIKELY (self->in_port->enabled)) { GstCaps *caps = NULL; caps = gst_pad_get_negotiated_caps (self->srcpad); if (!caps) { /** @todo We shouldn't be doing this. */ GST_WARNING_OBJECT (self, "faking settings changed notification"); if (gomx->settings_changed_cb) gomx->settings_changed_cb (gomx); } else { GST_LOG_OBJECT (self, "caps already fixed: %" GST_PTR_FORMAT, caps); gst_caps_unref (caps); } } #endif /* buf is always null when the output buffer pointer isn't shared. */ buf = omx_buffer->pAppPrivate; if (buf && !(omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) { GST_BUFFER_SIZE (buf) = omx_buffer->nFilledLen; if (self->use_timestamps) { GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (omx_buffer->nTimeStamp, GST_SECOND, OMX_TICKS_PER_SECOND); } omx_buffer->pAppPrivate = NULL; omx_buffer->pBuffer = NULL; ret = push_buffer (self, buf); gst_buffer_unref (buf); } else { /* This is only meant for the first OpenMAX buffers, * which need to be pre-allocated. */ /* Also for the very last one. */ gst_pad_alloc_buffer_and_set_caps (self->srcpad, GST_BUFFER_OFFSET_NONE, omx_buffer->nFilledLen, GST_PAD_CAPS (self->srcpad), &buf); if (G_LIKELY (buf)) { memcpy (GST_BUFFER_DATA (buf), omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen); if (self->use_timestamps) { GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (omx_buffer->nTimeStamp, GST_SECOND, OMX_TICKS_PER_SECOND); } if (self->share_output_buffer) { GST_WARNING_OBJECT (self, "couldn't zero-copy"); g_free (omx_buffer->pBuffer); omx_buffer->pBuffer = NULL; } ret = push_buffer (self, buf); } else { GST_WARNING_OBJECT (self, "couldn't allocate buffer of size %d", omx_buffer->nFilledLen); } } } else { GST_WARNING_OBJECT (self, "empty buffer"); } if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) { GST_DEBUG_OBJECT (self, "got eos"); g_omx_core_set_done (gomx); goto leave; } if (self->share_output_buffer && !omx_buffer->pBuffer && omx_buffer->nOffset == 0) { GstBuffer *buf; GstFlowReturn result; GST_LOG_OBJECT (self, "allocate buffer"); result = gst_pad_alloc_buffer_and_set_caps (self->srcpad, GST_BUFFER_OFFSET_NONE, omx_buffer->nAllocLen, GST_PAD_CAPS (self->srcpad), &buf); if (G_LIKELY (result == GST_FLOW_OK)) { gst_buffer_ref (buf); omx_buffer->pAppPrivate = buf; omx_buffer->pBuffer = GST_BUFFER_DATA (buf); omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf); } else { GST_WARNING_OBJECT (self, "could not pad allocate buffer, using malloc"); omx_buffer->pBuffer = g_malloc (omx_buffer->nAllocLen); } } if (self->share_output_buffer && !omx_buffer->pBuffer) { GST_ERROR_OBJECT (self, "no input buffer to share"); } omx_buffer->nFilledLen = 0; GST_LOG_OBJECT (self, "release_buffer"); g_omx_port_release_buffer (out_port, omx_buffer); } leave: self->last_pad_push_return = ret; if (ret != GST_FLOW_OK) { GST_INFO_OBJECT (self, "pause task, reason: %s", gst_flow_get_name (ret)); gst_pad_pause_task (self->srcpad); } GST_LOG_OBJECT (self, "end"); gst_object_unref (self); }
/* protected helper method which can be used by derived classes: */ GstFlowReturn gst_omx_base_src_create_from_port (GstOmxBaseSrc *self, GOmxPort *out_port, GstBuffer **ret_buf) { GOmxCore *gomx; GstFlowReturn ret = GST_FLOW_OK; gomx = self->gomx; GST_LOG_OBJECT (self, "begin"); if (out_port->enabled) { if (G_UNLIKELY (gomx->omx_state == OMX_StateIdle)) { GST_INFO_OBJECT (self, "omx: play"); g_omx_core_start (gomx); } if (G_UNLIKELY (gomx->omx_state != OMX_StateExecuting)) { GST_ERROR_OBJECT (self, "Whoa! very wrong"); ret = GST_FLOW_ERROR; goto beach; } while (out_port->enabled) { gpointer obj = g_omx_port_recv (out_port); if (G_UNLIKELY (!obj)) { ret = GST_FLOW_ERROR; break; } if (G_LIKELY (GST_IS_BUFFER (obj))) { GstBuffer *buf = GST_BUFFER (obj); if (G_LIKELY (GST_BUFFER_SIZE (buf) > 0)) { PRINT_BUFFER (self, buf); *ret_buf = buf; break; } } else if (GST_IS_EVENT (obj)) { GST_INFO_OBJECT (self, "got eos"); g_omx_core_set_done (gomx); break; } } } if (!out_port->enabled) { GST_WARNING_OBJECT (self, "done"); ret = GST_FLOW_UNEXPECTED; } beach: GST_LOG_OBJECT (self, "end"); return ret; }
static OMX_ERRORTYPE EventHandler (OMX_HANDLETYPE omx_handle, OMX_PTR app_data, OMX_EVENTTYPE event, OMX_U32 data_1, OMX_U32 data_2, OMX_PTR event_data) { GOmxCore *core; core = (GOmxCore *) app_data; switch (event) { case OMX_EventCmdComplete: { OMX_COMMANDTYPE cmd; cmd = (OMX_COMMANDTYPE) data_1; GST_DEBUG_OBJECT (core->object, "OMX_EventCmdComplete: %d", cmd); switch (cmd) { case OMX_CommandStateSet: complete_change_state (core, data_2); break; case OMX_CommandFlush: g_sem_up (core->flush_sem); break; case OMX_CommandPortDisable: case OMX_CommandPortEnable: g_sem_up (core->port_sem); default: break; } break; } case OMX_EventBufferFlag: { GST_DEBUG_OBJECT (core->object, "OMX_EventBufferFlag"); if (data_2 & OMX_BUFFERFLAG_EOS) { g_omx_core_set_done (core); } break; } case OMX_EventPortSettingsChanged: { GST_DEBUG_OBJECT (core->object, "OMX_EventPortSettingsChanged"); /** @todo only on the relevant port. */ if (core->settings_changed_cb) { core->settings_changed_cb (core); } break; } case OMX_EventIndexSettingChanged: { GST_DEBUG_OBJECT (core->object, "OMX_EventIndexSettingsChanged"); if (core->index_settings_changed_cb) { core->index_settings_changed_cb (core, data_1, data_2); } break; } case OMX_EventError: { core->omx_error = data_1; GST_ERROR_OBJECT (core->object, "unrecoverable error: %s (0x%lx)", g_omx_error_to_str (data_1), data_1); /* component might leave us waiting for buffers, unblock */ g_omx_core_flush_start (core); /* unlock wait_for_state */ g_mutex_lock (core->omx_state_mutex); g_cond_signal (core->omx_state_condition); g_mutex_unlock (core->omx_state_mutex); break; } #ifdef USE_OMXTICORE case OMX_TI_EventBufferRefCount: { OMX_BUFFERHEADERTYPE *omx_buffer = (OMX_BUFFERHEADERTYPE *)data_1; GOmxPort *port = get_port (core, omx_buffer->nOutputPortIndex); GST_DEBUG_OBJECT (core->object, "unref: omx_buffer=%p, pAppPrivate=%p, pBuffer=%p", omx_buffer, omx_buffer->pAppPrivate, omx_buffer->pBuffer); g_mutex_lock (core->omx_state_mutex); omx_buffer->nFlags |= GST_BUFFERFLAG_UNREF_CHECK; g_mutex_unlock (core->omx_state_mutex); g_omx_port_push_buffer (port, omx_buffer); break; } #endif default: GST_WARNING_OBJECT (core->object, "unhandled event: %d", event); break; } return OMX_ErrorNone; }