コード例 #1
0
static OMX_ERRORTYPE
EventHandler (OMX_HANDLETYPE omx_handle,
              OMX_PTR app_data,
              OMX_EVENTTYPE eEvent,
              OMX_U32 nData1,
              OMX_U32 nData2,
              OMX_PTR pEventData)
{
    GOmxCore *core;

    core = (GOmxCore *) app_data;

    switch (eEvent)
    {
        case OMX_EventCmdComplete:
            {
                OMX_COMMANDTYPE cmd;

                cmd = (OMX_COMMANDTYPE) nData1;

                switch (cmd)
                {
                    case OMX_CommandStateSet:
                        core->omx_state = (OMX_STATETYPE) nData2;
                        g_omx_sem_up (core->state_sem);
                        break;
                    case OMX_CommandFlush:
                        g_omx_sem_up (core->flush_sem);
                        break;
                    default:
                        break;
                }
                break;
            }
        case OMX_EventBufferFlag:
            {
#if 0
                if (nData2 & OMX_BUFFERFLAG_EOS)
                {
                    g_omx_port_set_done (core->ports[1]);
                }
#endif
                break;
            }
        case OMX_EventPortSettingsChanged:
            {
                /** @todo only on the relevant port. */
                if (core->settings_changed_cb)
                {
                    core->settings_changed_cb (core);
                }
            }
        default:
            break;
    }

    return OMX_ErrorNone;
}
コード例 #2
0
/**
 * overrides the default buffer allocation for output port to allow
 * pad_alloc'ing from the srcpad
 */
static GstBuffer *
buffer_alloc (GOmxPort *port, gint len)
{
    GstOmxBaseFilter2 *self = port->core->object;
    GstBuffer *buf;
    GstFlowReturn ret;
	int i;

	for (i = 0; i < NUM_OUTPUTS; i++)
		if (port == self->out_port[i]) break;
	if (i >= NUM_OUTPUTS) return NULL;

#if 1
    /** @todo remove this check */
    if (G_LIKELY (self->in_port->enabled))
    {
        GstCaps *caps = NULL;

        caps = gst_pad_get_negotiated_caps (self->srcpad[i]);

        if (!caps)
        {
            /** @todo We shouldn't be doing this. */
            GOmxCore *gomx = self->gomx;
            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

    ret = gst_pad_alloc_buffer_and_set_caps (
            self->srcpad[i], GST_BUFFER_OFFSET_NONE,
            len, GST_PAD_CAPS (self->srcpad[i]), &buf);

    if (ret == GST_FLOW_OK) return buf;

    return NULL;
}
コード例 #3
0
/* TODO make a util fxn out of this.. since this code is copied all over
 * the place
 */
void check_settings (GOmxPort *port, GstPad *pad)
{
    /* note: specifically DO NOT check port->enabled!  This can be called
     * during buffer allocation in transition-to-enabled while
     * port->enabled is still FALSE
     */
    GOmxCore *gomx = port->core;
    GstCaps *caps = NULL;

    caps = gst_pad_get_negotiated_caps (pad);

    if (!caps)
    {
        /** @todo We shouldn't be doing this. */
        GST_WARNING_OBJECT (gomx->object, "faking settings changed notification");
        if (gomx->settings_changed_cb)
            gomx->settings_changed_cb (gomx);
    }
    else
    {
        GST_LOG_OBJECT (gomx->object, "caps already fixed: %" GST_PTR_FORMAT, caps);
        gst_caps_unref (caps);
    }
}
コード例 #4
0
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;
}
コード例 #5
0
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->ready)
    {
        g_error ("not ready");
        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");
            ret = GST_FLOW_WRONG_STATE;
            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;

            /** @todo we need to move all the caps handling to one single
             * place, in the output loop probably. */
            if (G_UNLIKELY (omx_buffer->nFlags & 0x80))
            {
                GstCaps *caps = NULL;
                GstStructure *structure;
                GValue value = { 0 };

                caps = gst_pad_get_negotiated_caps (self->srcpad);
                caps = gst_caps_make_writable (caps);
                structure = gst_caps_get_structure (caps, 0);

                g_value_init (&value, GST_TYPE_BUFFER);
                buf = gst_buffer_new_and_alloc (omx_buffer->nFilledLen);
                memcpy (GST_BUFFER_DATA (buf), omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
                gst_value_set_buffer (&value, buf);
                gst_buffer_unref (buf);
                gst_structure_set_value (structure, "codec_data", &value);
                g_value_unset (&value);

                gst_pad_set_caps (self->srcpad, caps);
            }
            else 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. */
                ret = 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");
                        /* If pAppPrivate is NULL, it means it was a dummy
                         * allocation, free it. */
                        if (!omx_buffer->pAppPrivate)
                        {
                            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");
            gst_pad_push_event (self->srcpad, gst_event_new_eos ());
            ret = GST_FLOW_UNEXPECTED;
            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 (gomx->omx_error != OMX_ErrorNone)
        ret = GST_FLOW_ERROR;

    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);
}
コード例 #6
0
ファイル: gstomx_util.c プロジェクト: lhzhang/gst-openmax
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;
}
コード例 #7
0
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");

  /* do not bother if we have been setup to bail out */
  if ((ret = g_atomic_int_get (&self->last_pad_push_return)) != GST_FLOW_OK)
    goto leave;

  if (!self->ready) {
    g_error ("not ready");
    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");
      ret = GST_FLOW_WRONG_STATE;
      goto leave;
    }

    log_buffer (self, omx_buffer);

    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);

#ifdef ANDROID
        if (!caps || gomx->settings_changed) {
#else
        if (!caps) {
#endif
                    /** @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);
#ifdef ANDROID
          gomx->settings_changed = FALSE;
#endif
        } 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;

            /** @todo we need to move all the caps handling to one single
             * place, in the output loop probably. */
      if (G_UNLIKELY (omx_buffer->nFlags & 0x80)) {
        GstCaps *caps = NULL;
        GstStructure *structure;
        GValue value = { 0, {{0}
            }
        };

        caps = gst_pad_get_negotiated_caps (self->srcpad);
        caps = gst_caps_make_writable (caps);
        structure = gst_caps_get_structure (caps, 0);

        g_value_init (&value, GST_TYPE_BUFFER);
        buf = gst_buffer_new_and_alloc (omx_buffer->nFilledLen);
        memcpy (GST_BUFFER_DATA (buf),
            omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen);
        gst_value_set_buffer (&value, buf);
        gst_buffer_unref (buf);
        gst_structure_set_value (structure, "codec_data", &value);
        g_value_unset (&value);

        gst_pad_set_caps (self->srcpad, caps);
      } else 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. */
        ret = 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");
            /* If pAppPrivate is NULL, it means it was a dummy
             * allocation, free it. */
            if (!omx_buffer->pAppPrivate) {
              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 %lu",
              omx_buffer->nFilledLen);
        }
      }
    } else {
      GST_WARNING_OBJECT (self, "empty buffer");
    }

    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");
    }

    if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) {
      GST_DEBUG_OBJECT (self, "got eos");
      gst_pad_push_event (self->srcpad, gst_event_new_eos ());
      omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
      ret = GST_FLOW_UNEXPECTED;
    }

    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 (gomx->omx_error != OMX_ErrorNone)
    ret = GST_FLOW_ERROR;

  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);
}

static GstFlowReturn
pad_chain (GstPad * pad, GstBuffer * buf)
{
  GOmxCore *gomx;
  GOmxPort *in_port;
  GstOmxBaseFilter *self;
  GstFlowReturn ret = GST_FLOW_OK;

  self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad));

  gomx = self->gomx;

  GST_LOG_OBJECT (self, "begin");
  GST_LOG_OBJECT (self, "gst_buffer: size=%u", GST_BUFFER_SIZE (buf));

  GST_LOG_OBJECT (self, "state: %d", gomx->omx_state);

  if (G_UNLIKELY (gomx->omx_state == OMX_StateLoaded)) {
    g_mutex_lock (self->ready_lock);

    GST_INFO_OBJECT (self, "omx: prepare");

        /** @todo this should probably go after doing preparations. */
    if (self->omx_setup) {
      self->omx_setup (self);
    }

    setup_ports (self);

    g_omx_core_prepare (self->gomx);

    if (gomx->omx_state == OMX_StateIdle) {
      self->ready = TRUE;
      GST_INFO_OBJECT (self, "start srcpad task");
      gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
    }

    g_mutex_unlock (self->ready_lock);

    if (gomx->omx_state != OMX_StateIdle)
      goto out_flushing;
  }

#ifdef ANDROID
  if (gomx->settings_changed) {
    GST_DEBUG_OBJECT (self, "settings changed called from streaming thread... Android");
    if (gomx->settings_changed_cb)
      gomx->settings_changed_cb (gomx);

    gomx->settings_changed = FALSE;
  }
#endif

  in_port = self->in_port;

  if (G_LIKELY (in_port->enabled)) {
    guint buffer_offset = 0;

    if (G_UNLIKELY (gomx->omx_state == OMX_StateIdle)) {
      GST_INFO_OBJECT (self, "omx: play");
      g_omx_core_start (gomx);

      if (gomx->omx_state != OMX_StateExecuting)
        goto out_flushing;

      /* send buffer with codec data flag */
            /** @todo move to util */
      if (self->codec_data) {
        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 |= 0x00000080;     /* codec data flag */

          omx_buffer->nFilledLen = GST_BUFFER_SIZE (self->codec_data);
          memcpy (omx_buffer->pBuffer + omx_buffer->nOffset,
              GST_BUFFER_DATA (self->codec_data), omx_buffer->nFilledLen);

          GST_LOG_OBJECT (self, "release_buffer");
          g_omx_port_release_buffer (in_port, omx_buffer);
        }
      }
    }

    if (G_UNLIKELY (gomx->omx_state != OMX_StateExecuting)) {
      GST_ERROR_OBJECT (self, "Whoa! very wrong");
    }

    while (G_LIKELY (buffer_offset < GST_BUFFER_SIZE (buf))) {
      OMX_BUFFERHEADERTYPE *omx_buffer;

      if (self->last_pad_push_return != GST_FLOW_OK ||
          !(gomx->omx_state == OMX_StateExecuting ||
              gomx->omx_state == OMX_StatePause)) {
        goto out_flushing;
      }

      GST_LOG_OBJECT (self, "request buffer");
      omx_buffer = g_omx_port_request_buffer (in_port);

      GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer);

      if (G_LIKELY (omx_buffer)) {
        log_buffer (self, omx_buffer);

        if (omx_buffer->nOffset == 0 && self->share_input_buffer) {
          {
            GstBuffer *old_buf;
            old_buf = omx_buffer->pAppPrivate;

            if (old_buf) {
              gst_buffer_unref (old_buf);
            } else if (omx_buffer->pBuffer) {
              g_free (omx_buffer->pBuffer);
            }
          }

          omx_buffer->pBuffer = GST_BUFFER_DATA (buf);
          omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf);
          omx_buffer->nFilledLen = GST_BUFFER_SIZE (buf);
          omx_buffer->pAppPrivate = buf;
        } else {
          omx_buffer->nFilledLen = MIN (GST_BUFFER_SIZE (buf) - buffer_offset,
              omx_buffer->nAllocLen - omx_buffer->nOffset);
          memcpy (omx_buffer->pBuffer + omx_buffer->nOffset,
              GST_BUFFER_DATA (buf) + buffer_offset, omx_buffer->nFilledLen);
        }

        if (self->use_timestamps) {
          GstClockTime timestamp_offset = 0;

          if (buffer_offset && GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE) {
            timestamp_offset = gst_util_uint64_scale_int (buffer_offset,
                GST_BUFFER_DURATION (buf), GST_BUFFER_SIZE (buf));
          }

          omx_buffer->nTimeStamp =
              gst_util_uint64_scale_int (GST_BUFFER_TIMESTAMP (buf) +
              timestamp_offset, OMX_TICKS_PER_SECOND, GST_SECOND);
        }

        buffer_offset += omx_buffer->nFilledLen;
#ifdef ANDROID
        omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
        log_buffer (self, omx_buffer);
#endif

        GST_LOG_OBJECT (self, "release_buffer");
                /** @todo untaint buffer */
        g_omx_port_release_buffer (in_port, omx_buffer);
      } else {
        GST_WARNING_OBJECT (self, "null buffer");
        ret = GST_FLOW_WRONG_STATE;
        goto out_flushing;
      }
    }
  } else {
    GST_WARNING_OBJECT (self, "done");
    ret = GST_FLOW_UNEXPECTED;
  }

  if (!self->share_input_buffer) {
    gst_buffer_unref (buf);
  }

leave:

  GST_LOG_OBJECT (self, "end");

  return ret;

  /* special conditions */
out_flushing:
  {
    const gchar *error_msg = NULL;

    if (gomx->omx_error) {
      error_msg = "Error from OpenMAX component";
    } else if (gomx->omx_state != OMX_StateExecuting &&
        gomx->omx_state != OMX_StatePause) {
      error_msg = "OpenMAX component in wrong state";
    }

    if (error_msg) {
      GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("%s", error_msg));
      ret = GST_FLOW_ERROR;
    }

    gst_buffer_unref (buf);

    goto leave;
  }
}
コード例 #8
0
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;
}