omxaudioenc: Add hack for encoder components that don't allow empty EOS buffers
authorJonas Larsson <Jonas.Larsson@palm.com>
Wed, 14 Dec 2011 09:09:34 +0000 (10:09 +0100)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Wed, 14 Dec 2011 09:09:34 +0000 (10:09 +0100)
omx/gstomxaudioenc.c

index 4fb7811..18beb26 100644 (file)
@@ -463,87 +463,106 @@ gst_omx_audio_enc_loop (GstOMXAudioEnc * 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) {
 
-  GST_AUDIO_ENCODER_STREAM_LOCK (self);
-  is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS);
-
-  if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG)
-      && buf->omx_buf->nFilledLen > 0) {
-    GstCaps *caps;
-    GstBuffer *codec_data;
+    GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %lu", buf->omx_buf->nFlags,
+        buf->omx_buf->nTimeStamp);
 
-    caps = gst_caps_copy (GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (self)));
-    codec_data = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
-    memcpy (GST_BUFFER_DATA (codec_data),
-        buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
-        buf->omx_buf->nFilledLen);
-
-    gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
-    if (!gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (self), caps)) {
-      gst_caps_unref (caps);
-      if (buf)
-        gst_omx_port_release_buffer (self->out_port, buf);
-      GST_AUDIO_ENCODER_STREAM_UNLOCK (self);
-      goto caps_failed;
+    /* 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_caps_unref (caps);
-    flow_ret = GST_FLOW_OK;
-  } else if (buf->omx_buf->nFilledLen > 0) {
-    GstBuffer *outbuf;
-    guint n_samples;
 
-    n_samples =
-        klass->get_num_samples (self, self->out_port,
-        gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (self)), buf);
+    GST_AUDIO_ENCODER_STREAM_LOCK (self);
+    is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS);
 
-    if (buf->omx_buf->nFilledLen > 0) {
-      outbuf = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
+    if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG)
+        && buf->omx_buf->nFilledLen > 0) {
+      GstCaps *caps;
+      GstBuffer *codec_data;
 
-      memcpy (GST_BUFFER_DATA (outbuf),
+      caps = gst_caps_copy (GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (self)));
+      codec_data = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
+      memcpy (GST_BUFFER_DATA (codec_data),
           buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
           buf->omx_buf->nFilledLen);
-    } else {
-      outbuf = gst_buffer_new ();
-    }
-
-    gst_buffer_set_caps (outbuf,
-        GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (self)));
 
-    GST_BUFFER_TIMESTAMP (outbuf) =
-        gst_util_uint64_scale (buf->omx_buf->nTimeStamp, GST_SECOND,
-        OMX_TICKS_PER_SECOND);
-    if (buf->omx_buf->nTickCount != 0)
-      GST_BUFFER_DURATION (outbuf) =
-          gst_util_uint64_scale (buf->omx_buf->nTickCount, GST_SECOND,
+      gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data,
+          NULL);
+      if (!gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (self), caps)) {
+        gst_caps_unref (caps);
+        if (buf)
+          gst_omx_port_release_buffer (self->out_port, buf);
+        GST_AUDIO_ENCODER_STREAM_UNLOCK (self);
+        goto caps_failed;
+      }
+      gst_caps_unref (caps);
+      flow_ret = GST_FLOW_OK;
+    } else if (buf->omx_buf->nFilledLen > 0) {
+      GstBuffer *outbuf;
+      guint n_samples;
+
+      n_samples =
+          klass->get_num_samples (self, self->out_port,
+          gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (self)), buf);
+
+      if (buf->omx_buf->nFilledLen > 0) {
+        outbuf = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);
+
+        memcpy (GST_BUFFER_DATA (outbuf),
+            buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
+            buf->omx_buf->nFilledLen);
+      } else {
+        outbuf = gst_buffer_new ();
+      }
+
+      gst_buffer_set_caps (outbuf,
+          GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (self)));
+
+      GST_BUFFER_TIMESTAMP (outbuf) =
+          gst_util_uint64_scale (buf->omx_buf->nTimeStamp, GST_SECOND,
           OMX_TICKS_PER_SECOND);
+      if (buf->omx_buf->nTickCount != 0)
+        GST_BUFFER_DURATION (outbuf) =
+            gst_util_uint64_scale (buf->omx_buf->nTickCount, GST_SECOND,
+            OMX_TICKS_PER_SECOND);
+
+      flow_ret =
+          gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (self),
+          outbuf, n_samples);
+    }
 
-    flow_ret =
-        gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (self),
-        outbuf, n_samples);
-  }
-
-  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;
+    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));
+    GST_AUDIO_ENCODER_STREAM_LOCK (self);
+    flow_ret = GST_FLOW_UNEXPECTED;
+  }
 
   if (flow_ret != GST_FLOW_OK)
     goto flow_error;
@@ -993,8 +1012,10 @@ static gboolean
 gst_omx_audio_enc_event (GstAudioEncoder * encoder, GstEvent * event)
 {
   GstOMXAudioEnc *self;
+  GstOMXAudioEncClass *klass;
 
   self = GST_OMX_AUDIO_ENC (encoder);
+  klass = GST_OMX_AUDIO_ENC_GET_CLASS (self);
 
   if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
     GstOMXBuffer *buf;
@@ -1009,6 +1030,17 @@ gst_omx_audio_enc_event (GstAudioEncoder * encoder, GstEvent * event)
     }
     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 TRUE;
+    }
+
     /* 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 */
@@ -1042,11 +1074,14 @@ gst_omx_audio_enc_event (GstAudioEncoder * encoder, GstEvent * event)
 static GstFlowReturn
 gst_omx_audio_enc_drain (GstOMXAudioEnc * self)
 {
+  GstOMXAudioEncClass *klass;
   GstOMXBuffer *buf;
   GstOMXAcquireBufferReturn acq_ret;
 
   GST_DEBUG_OBJECT (self, "Draining component");
 
+  klass = GST_OMX_AUDIO_ENC_GET_CLASS (self);
+
   if (!self->started) {
     GST_DEBUG_OBJECT (self, "Component not started yet");
     return GST_FLOW_OK;
@@ -1059,6 +1094,11 @@ gst_omx_audio_enc_drain (GstOMXAudioEnc * 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 */