omx: Add hack for encoder components that don't allow empty EOS buffers
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Fri, 9 Dec 2011 11:17:29 +0000 (12:17 +0100)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Fri, 9 Dec 2011 11:24:01 +0000 (12:24 +0100)
omx/gstomx.c
omx/gstomx.h
omx/gstomxvideoenc.c

index 385483d..c70d980 100644 (file)
@@ -974,7 +974,7 @@ retry:
           "Output port %u needs reconfiguration but has buffers pending",
           port->index);
       _buf = g_queue_pop_head (port->pending_buffers);
-      g_assert (_buf != NULL);
+
       ret = GST_OMX_ACQUIRE_BUFFER_OK;
       goto done;
     }
@@ -1184,7 +1184,7 @@ gst_omx_port_set_flushing (GstOMXPort * port, gboolean flush)
     signalled = TRUE;
     last_error = OMX_ErrorNone;
     while (signalled && last_error == OMX_ErrorNone && !port->flushed
-        && port->buffers->len != g_queue_get_length (port->pending_buffers)) {
+        && port->buffers->len > g_queue_get_length (port->pending_buffers)) {
       signalled = g_cond_timed_wait (port->port_cond, port->port_lock, timeval);
 
       last_error = gst_omx_component_get_last_error (comp);
@@ -1210,6 +1210,9 @@ gst_omx_port_set_flushing (GstOMXPort * port, gboolean flush)
 
       /* Enqueue all buffers for the component to fill */
       while ((buf = g_queue_pop_head (port->pending_buffers))) {
+        if (!buf)
+          continue;
+
         g_assert (!buf->used);
 
         /* Reset all flags, some implementations don't
@@ -1548,8 +1551,7 @@ gst_omx_port_set_enabled_unlocked (GstOMXPort * port, gboolean enabled)
   signalled = TRUE;
   last_error = OMX_ErrorNone;
   while (signalled && last_error == OMX_ErrorNone && (port->buffers
-          && port->buffers->len !=
-          g_queue_get_length (port->pending_buffers))) {
+          && port->buffers->len > g_queue_get_length (port->pending_buffers))) {
     signalled = g_cond_timed_wait (port->port_cond, port->port_lock, timeval);
     last_error = gst_omx_component_get_last_error (comp);
   }
@@ -1619,6 +1621,9 @@ gst_omx_port_set_enabled_unlocked (GstOMXPort * port, gboolean enabled)
 
       /* Enqueue all buffers for the component to fill */
       while ((buf = g_queue_pop_head (port->pending_buffers))) {
+        if (!buf)
+          continue;
+
         g_assert (!buf->used);
 
         /* Reset all flags, some implementations don't
@@ -1954,6 +1959,8 @@ gst_omx_parse_hacks (gchar ** hacks)
       hacks_flags |= GST_OMX_HACK_SYNCFRAME_FLAG_NOT_USED;
     else if (g_str_equal (*hacks, "no-component-reconfigure"))
       hacks_flags |= GST_OMX_HACK_NO_COMPONENT_RECONFIGURE;
+    else if (g_str_equal (*hacks, "no-empty-eos-buffer"))
+      hacks_flags |= GST_OMX_HACK_NO_EMPTY_EOS_BUFFER;
     else
       GST_WARNING ("Unknown hack: %s", *hacks);
     hacks++;
index 55efb4b..6ef3beb 100644 (file)
@@ -60,6 +60,11 @@ G_BEGIN_DECLS
  */
 #define GST_OMX_HACK_NO_COMPONENT_RECONFIGURE                         G_GUINT64_CONSTANT (0x0000000000000010)
 
+/* If the component does not accept empty EOS buffers.
+ * Happens with Qualcomm's OpenMAX implementation.
+ */
+#define GST_OMX_HACK_NO_EMPTY_EOS_BUFFER                              G_GUINT64_CONSTANT (0x0000000000000020)
+
 
 typedef struct _GstOMXCore GstOMXCore;
 typedef struct _GstOMXPort GstOMXPort;
index 9ac382a..04a41f6 100644 (file)
@@ -858,47 +858,55 @@ gst_omx_video_enc_loop (GstOMXVideoEnc * self)
       return;
   }
 
-  g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK && buf != NULL);
+  g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK);
 
-  GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %lu", buf->omx_buf->nFlags,
-      buf->omx_buf->nTimeStamp);
+  if (buf) {
 
-  /* This prevents a deadlock between the srcpad stream
-   * lock and the videocodec stream lock, if ::reset()
-   * is called at the wrong time
-   */
-  if (gst_omx_port_is_flushing (self->out_port)) {
-    GST_DEBUG_OBJECT (self, "Flushing");
-    gst_omx_port_release_buffer (self->out_port, buf);
-    goto flushing;
-  }
+    GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %lu", buf->omx_buf->nFlags,
+        buf->omx_buf->nTimeStamp);
 
-  GST_BASE_VIDEO_CODEC_STREAM_LOCK (self);
-  frame = _find_nearest_frame (self, buf);
+    /* This prevents a deadlock between the srcpad stream
+     * lock and the videocodec stream lock, if ::reset()
+     * is called at the wrong time
+     */
+    if (gst_omx_port_is_flushing (self->out_port)) {
+      GST_DEBUG_OBJECT (self, "Flushing");
+      gst_omx_port_release_buffer (self->out_port, buf);
+      goto flushing;
+    }
 
-  is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS);
+    GST_BASE_VIDEO_CODEC_STREAM_LOCK (self);
+    frame = _find_nearest_frame (self, buf);
 
-  g_assert (klass->handle_output_frame);
-  flow_ret = klass->handle_output_frame (self, self->out_port, buf, frame);
+    is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS);
 
-  if (is_eos || flow_ret == GST_FLOW_UNEXPECTED) {
-    g_mutex_lock (self->drain_lock);
-    if (self->draining) {
-      GST_DEBUG_OBJECT (self, "Drained");
-      self->draining = FALSE;
-      g_cond_broadcast (self->drain_cond);
-    } else if (flow_ret == GST_FLOW_OK) {
-      GST_DEBUG_OBJECT (self, "Component signalled EOS");
-      flow_ret = GST_FLOW_UNEXPECTED;
+    g_assert (klass->handle_output_frame);
+    flow_ret = klass->handle_output_frame (self, self->out_port, buf, frame);
+
+    if (is_eos || flow_ret == GST_FLOW_UNEXPECTED) {
+      g_mutex_lock (self->drain_lock);
+      if (self->draining) {
+        GST_DEBUG_OBJECT (self, "Drained");
+        self->draining = FALSE;
+        g_cond_broadcast (self->drain_cond);
+      } else if (flow_ret == GST_FLOW_OK) {
+        GST_DEBUG_OBJECT (self, "Component signalled EOS");
+        flow_ret = GST_FLOW_UNEXPECTED;
+      }
+      g_mutex_unlock (self->drain_lock);
+    } else {
+      GST_DEBUG_OBJECT (self, "Finished frame: %s",
+          gst_flow_get_name (flow_ret));
     }
-    g_mutex_unlock (self->drain_lock);
-  } else {
-    GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
-  }
 
-  gst_omx_port_release_buffer (port, buf);
+    gst_omx_port_release_buffer (port, buf);
 
-  self->downstream_flow_ret = flow_ret;
+    self->downstream_flow_ret = flow_ret;
+
+  } else {
+    g_assert ((klass->hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER));
+    flow_ret = GST_FLOW_UNEXPECTED;
+  }
 
   if (flow_ret != GST_FLOW_OK)
     goto flow_error;
@@ -1513,10 +1521,12 @@ static GstFlowReturn
 gst_omx_video_enc_finish (GstBaseVideoEncoder * encoder)
 {
   GstOMXVideoEnc *self;
+  GstOMXVideoEncClass *klass;
   GstOMXBuffer *buf;
   GstOMXAcquireBufferReturn acq_ret;
 
   self = GST_OMX_VIDEO_ENC (encoder);
+  klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
 
   GST_DEBUG_OBJECT (self, "Sending EOS to the component");
 
@@ -1527,6 +1537,18 @@ gst_omx_video_enc_finish (GstBaseVideoEncoder * encoder)
   }
   self->eos = TRUE;
 
+  if ((klass->hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) {
+    GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers");
+
+    /* Insert a NULL into the queue to signal EOS */
+    g_mutex_lock (self->out_port->port_lock);
+    g_queue_push_tail (self->out_port->pending_buffers, NULL);
+    g_cond_broadcast (self->out_port->port_cond);
+    g_mutex_unlock (self->out_port->port_lock);
+
+    return GST_BASE_VIDEO_ENCODER_FLOW_DROPPED;
+  }
+
   /* Make sure to release the base class stream lock, otherwise
    * _loop() can't call _finish_frame() and we might block forever
    * because no input buffers are released */
@@ -1557,11 +1579,14 @@ gst_omx_video_enc_finish (GstBaseVideoEncoder * encoder)
 static GstFlowReturn
 gst_omx_video_enc_drain (GstOMXVideoEnc * self)
 {
+  GstOMXVideoEncClass *klass;
   GstOMXBuffer *buf;
   GstOMXAcquireBufferReturn acq_ret;
 
   GST_DEBUG_OBJECT (self, "Draining component");
 
+  klass = GST_OMX_VIDEO_ENC_GET_CLASS (self);
+
   if (!self->started) {
     GST_DEBUG_OBJECT (self, "Component not started yet");
     return GST_FLOW_OK;
@@ -1574,6 +1599,11 @@ gst_omx_video_enc_drain (GstOMXVideoEnc * self)
     return GST_FLOW_OK;
   }
 
+  if ((klass->hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) {
+    GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers");
+    return GST_FLOW_OK;
+  }
+
   /* Make sure to release the base class stream lock, otherwise
    * _loop() can't call _finish_frame() and we might block forever
    * because no input buffers are released */