/** * Utility function to handle transferring Gstreamer timestamp to OMX * timestamp. This function handles discontinuities and timestamp * renormalization. * * @omx_buffer the destination OMX buffer for the timestamp * @buffer the source Gstreamer buffer for the timestamp * @normalize should this buffer be the one that we renormalize on * (iff normalization is required)? (ie. with TI OMX, you should * only re-normalize on a video buffer) */ gboolean gst_goo_timestamp_gst2omx ( OMX_BUFFERHEADERTYPE* omx_buffer, GstBuffer* buffer, gboolean normalize) { GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer); if (GST_GOO_UTIL_IS_DISCONT (buffer)) { needs_normalization = TRUE; GST_DEBUG ("needs_normalization"); } if (needs_normalization && normalize) { GST_INFO ("Setting OMX_BUFFER_STARTTIME.."); omx_buffer->nFlags |= OMX_BUFFERFLAG_STARTTIME; omx_normalize_timestamp = GST2OMX_TIMESTAMP ((gint64)timestamp); needs_normalization = FALSE; GST_DEBUG ("omx_normalize_timestamp=%lld", omx_normalize_timestamp); } /* transfer timestamp to openmax */ if (GST_CLOCK_TIME_IS_VALID (timestamp)) { omx_buffer->nTimeStamp = GST2OMX_TIMESTAMP ((gint64)timestamp) - omx_normalize_timestamp; GST_INFO ("OMX timestamp = %lld (%lld - %lld)", omx_buffer->nTimeStamp, GST2OMX_TIMESTAMP ((gint64)timestamp), omx_normalize_timestamp); return TRUE; } else { GST_WARNING ("Invalid timestamp!"); return FALSE; } }
static GstFlowReturn gst_goo_encjpeg_chain (GstPad* pad, GstBuffer* buffer) { GST_LOG (""); GstGooEncJpeg* self = GST_GOO_ENCJPEG (gst_pad_get_parent (pad)); GstGooEncJpegPrivate* priv = GST_GOO_ENCJPEG_GET_PRIVATE (self); GstFlowReturn ret = GST_FLOW_OK; GstGooAdapter* adapter = self->adapter; OMX_BUFFERHEADERTYPE* omx_buffer = NULL; GstClockTime timestamp, duration; guint64 offset, offsetend; GstBuffer* outbuf = NULL; if (goo_port_is_tunneled (self->inport)) { GST_INFO ("Inport is tunneled"); ret = GST_FLOW_OK; priv->incount++; goto process_output; } if (goo_port_is_eos (self->inport)) { GST_INFO ("port is eos"); ret = GST_FLOW_UNEXPECTED; goto fail; } if (self->component->cur_state != OMX_StateExecuting) { goto fail; } /* let's copy the timestamp meta data */ timestamp = GST_BUFFER_TIMESTAMP (buffer); duration = GST_BUFFER_DURATION (buffer); offset = GST_BUFFER_OFFSET (buffer); offsetend = GST_BUFFER_OFFSET_END (buffer); if (GST_IS_GOO_BUFFER (buffer) && goo_port_is_my_buffer (self->inport, GST_GOO_BUFFER (buffer)->omx_buffer)) { GST_INFO ("My own OMX buffer"); priv->incount++; gst_buffer_unref (buffer); /* let's push the buffer to omx */ ret = GST_FLOW_OK; } else if (GST_IS_GOO_BUFFER (buffer) && !goo_port_is_my_buffer (self->inport, GST_GOO_BUFFER (buffer)->omx_buffer)) { GST_INFO ("Other OMX buffer"); if (GST_BUFFER_SIZE (buffer) != priv->omxbufsiz) { GST_ELEMENT_ERROR (self, STREAM, FORMAT, ("Frame is incomplete (%u!=%u)", GST_BUFFER_SIZE (buffer), priv->omxbufsiz), ("Frame is incomplete (%u!=%u)", GST_BUFFER_SIZE (buffer), priv->omxbufsiz)); ret = GST_FLOW_ERROR; } omx_buffer = goo_port_grab_buffer (self->inport); memcpy (omx_buffer->pBuffer, GST_BUFFER_DATA (buffer), priv->omxbufsiz); omx_buffer->nFilledLen = priv->omxbufsiz; priv->incount++; goo_component_release_buffer (self->component, omx_buffer); gst_buffer_unref (buffer); ret = GST_FLOW_OK; } else { if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { gst_goo_adapter_clear (adapter); } GST_LOG ("size = %d bytes", GST_BUFFER_SIZE (buffer)); gst_goo_adapter_push (adapter, buffer); guint tmp = priv->incount; while (gst_goo_adapter_available (adapter) >= priv->omxbufsiz && ret == GST_FLOW_OK) { GST_DEBUG ("Pushing data to OMX"); OMX_BUFFERHEADERTYPE* omx_buffer; omx_buffer = goo_port_grab_buffer (self->inport); gst_goo_adapter_peek (adapter, priv->omxbufsiz, omx_buffer); omx_buffer->nFilledLen = priv->omxbufsiz; gst_goo_adapter_flush (adapter, priv->omxbufsiz); priv->incount++; goo_component_release_buffer (self->component, omx_buffer); ret = GST_FLOW_OK; } if (tmp == priv->incount) { goto done; } } process_output: if (goo_port_is_tunneled (self->outport)) { outbuf = gst_ghost_buffer_new (); GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_READONLY); GST_BUFFER_DATA (outbuf) = NULL; GST_BUFFER_SIZE (outbuf) = 0; GST_BUFFER_TIMESTAMP (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = duration; GST_BUFFER_OFFSET (outbuf) = offset; GST_BUFFER_OFFSET_END (outbuf) = offsetend; gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad)); gst_pad_push (self->srcpad, outbuf); goto done; } GST_DEBUG ("Poping out buffer from OMX"); omx_buffer = goo_port_grab_buffer (self->outport); if (omx_buffer->nFilledLen <= 0) { ret = GST_FLOW_ERROR; goto done; } if (gst_pad_alloc_buffer (self->srcpad, priv->outcount, omx_buffer->nFilledLen, GST_PAD_CAPS (self->srcpad), &outbuf) == GST_FLOW_OK) { priv->outcount++; /* if the buffer is a goo buffer of the peer element */ if (GST_IS_GOO_BUFFER (outbuf)) { GST_INFO ("It is a OMX buffer!"); memcpy (GST_GOO_BUFFER (outbuf)->omx_buffer->pBuffer, omx_buffer->pBuffer, omx_buffer->nFilledLen); GST_GOO_BUFFER (outbuf)->omx_buffer->nFilledLen = omx_buffer->nFilledLen; GST_GOO_BUFFER (outbuf)->omx_buffer->nFlags = omx_buffer->nFlags; GST_GOO_BUFFER (outbuf)->omx_buffer->nTimeStamp = GST2OMX_TIMESTAMP (timestamp); goo_component_release_buffer (self->component, omx_buffer); } else { /* @fixme! */ /* we do this because there is a buffer extarbation * when a filesink is used. * Maybe using multiple buffers it could be solved. */ memcpy (GST_BUFFER_DATA (outbuf), omx_buffer->pBuffer, omx_buffer->nFilledLen); goo_component_release_buffer (self->component, omx_buffer); /* gst_buffer_unref (outbuf); */ /* outbuf = GST_BUFFER (gst_goo_buffer_new ()); */ /* gst_goo_buffer_set_data (outbuf, */ /* self->component, */ /* omx_buffer); */ } GST_BUFFER_TIMESTAMP (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = duration; GST_BUFFER_OFFSET (outbuf) = offset; GST_BUFFER_OFFSET_END (outbuf) = offsetend; gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad)); g_signal_emit (G_OBJECT (self), gst_goo_encjpeg_signals[FRAME_ENCODED], 0); ret = gst_pad_push (self->srcpad, outbuf); if (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS || goo_port_is_eos (self->outport)) { GST_INFO ("EOS flag found in output buffer (%d)", omx_buffer->nFilledLen); goo_component_set_done (self->component); } goto done; } else { ret = GST_FLOW_ERROR; goto done; } fail: gst_buffer_unref (buffer); gst_goo_adapter_clear (adapter); done: gst_object_unref (self); return ret; }