omxaudiodec: Add an output adapter for chunking the output into codec frames
authorSebastian Dröge <sebastian@centricular.com>
Tue, 19 May 2015 15:21:40 +0000 (18:21 +0300)
committerSebastian Dröge <sebastian@centricular.com>
Tue, 19 May 2015 16:14:42 +0000 (19:14 +0300)
Otherwise the base class will be confused.
See https://bugzilla.gnome.org/show_bug.cgi?id=685730

omx/gstomxaudiodec.c
omx/gstomxaudiodec.h

index 44fdf89..e095cf3 100644 (file)
@@ -105,6 +105,8 @@ gst_omx_audio_dec_init (GstOMXAudioDec * self)
 
   g_mutex_init (&self->drain_lock);
   g_cond_init (&self->drain_cond);
+
+  self->output_adapter = gst_adapter_new ();
 }
 
 static gboolean
@@ -219,6 +221,10 @@ gst_omx_audio_dec_finalize (GObject * object)
   g_mutex_clear (&self->drain_lock);
   g_cond_clear (&self->drain_cond);
 
+  if (self->output_adapter)
+    gst_object_unref (self->output_adapter);
+  self->output_adapter = NULL;
+
   G_OBJECT_CLASS (gst_omx_audio_dec_parent_class)->finalize (object);
 }
 
@@ -286,11 +292,13 @@ gst_omx_audio_dec_change_state (GstElement * element, GstStateChange transition)
 static void
 gst_omx_audio_dec_loop (GstOMXAudioDec * self)
 {
+  GstOMXAudioDecClass *klass = GST_OMX_AUDIO_DEC_GET_CLASS (self);
   GstOMXPort *port = self->dec_out_port;
   GstOMXBuffer *buf = NULL;
   GstFlowReturn flow_ret = GST_FLOW_OK;
   GstOMXAcquireBufferReturn acq_return;
   OMX_ERRORTYPE err;
+  gint spf;
 
   acq_return = gst_omx_port_acquire_buffer (port, &buf);
   if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) {
@@ -485,11 +493,11 @@ gst_omx_audio_dec_loop (GstOMXAudioDec * self)
 
   GST_AUDIO_DECODER_STREAM_LOCK (self);
 
+  spf = klass->get_samples_per_frame (self, self->dec_out_port);
+
   if (buf->omx_buf->nFilledLen > 0) {
     GstBuffer *outbuf;
-    gint nframes, spf;
     GstMapInfo minfo;
-    GstOMXAudioDecClass *klass = GST_OMX_AUDIO_DEC_GET_CLASS (self);
 
     GST_DEBUG_OBJECT (self, "Handling output data");
 
@@ -524,31 +532,37 @@ gst_omx_audio_dec_loop (GstOMXAudioDec * self)
     }
     gst_buffer_unmap (outbuf, &minfo);
 
-    nframes = 1;
-    spf = klass->get_samples_per_frame (self, self->dec_out_port);
     if (spf != -1) {
-      nframes = buf->omx_buf->nFilledLen / self->info.bpf;
-      if (nframes % spf != 0)
-        GST_WARNING_OBJECT (self, "Output buffer does not contain an integer "
-            "number of input frames (frames: %d, spf: %d)", nframes, spf);
-      nframes = (nframes + spf - 1) / spf;
+      gst_adapter_push (self->output_adapter, outbuf);
+    } else {
+      flow_ret =
+          gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (self), outbuf, 1);
     }
-
-    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_decoder_finish_frame (GST_AUDIO_DECODER (self), outbuf,
-        nframes);
   }
 
   GST_DEBUG_OBJECT (self, "Read frame from component");
 
+  if (spf != -1) {
+    GstBuffer *outbuf;
+    guint avail = gst_adapter_available (self->output_adapter);
+    guint nframes;
+
+    /* We take a multiple of codec frames and push
+     * them downstream
+     */
+    avail /= self->info.bpf;
+    nframes = avail / spf;
+    avail = nframes * spf;
+    avail *= self->info.bpf;
+
+    if (avail > 0) {
+      outbuf = gst_adapter_take_buffer (self->output_adapter, avail);
+      flow_ret =
+          gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (self), outbuf,
+          nframes);
+    }
+  }
+
   GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
 
   if (buf) {
@@ -590,6 +604,27 @@ flushing:
 
 eos:
   {
+    spf = klass->get_samples_per_frame (self, self->dec_out_port);
+    if (spf != -1) {
+      GstBuffer *outbuf;
+      guint avail = gst_adapter_available (self->output_adapter);
+      guint nframes;
+
+      /* On EOS we take the complete adapter content, no matter
+       * if it is a multiple of the codec frame size or not.
+       */
+      avail /= self->info.bpf;
+      nframes = (avail + spf - 1) / spf;
+      avail *= self->info.bpf;
+
+      if (avail > 0) {
+        outbuf = gst_adapter_take_buffer (self->output_adapter, avail);
+        flow_ret =
+            gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (self), outbuf,
+            nframes);
+      }
+    }
+
     g_mutex_lock (&self->drain_lock);
     if (self->draining) {
       GST_DEBUG_OBJECT (self, "Drained");
@@ -727,6 +762,9 @@ gst_omx_audio_dec_stop (GstAudioDecoder * decoder)
   g_cond_broadcast (&self->drain_cond);
   g_mutex_unlock (&self->drain_lock);
 
+  gst_adapter_flush (self->output_adapter,
+      gst_adapter_available (self->output_adapter));
+
   gst_omx_component_get_state (self->dec, 5 * GST_SECOND);
 
   gst_buffer_replace (&self->codec_data, NULL);
@@ -965,6 +1003,8 @@ gst_omx_audio_dec_flush (GstAudioDecoder * decoder, gboolean hard)
   }
 
   /* Reset our state */
+  gst_adapter_flush (self->output_adapter,
+      gst_adapter_available (self->output_adapter));
   self->last_upstream_ts = 0;
   self->downstream_flow_ret = GST_FLOW_OK;
   self->started = FALSE;
@@ -1328,6 +1368,8 @@ gst_omx_audio_dec_drain (GstOMXAudioDec * self)
   g_mutex_unlock (&self->drain_lock);
   GST_AUDIO_DECODER_STREAM_LOCK (self);
 
+  gst_adapter_flush (self->output_adapter,
+      gst_adapter_available (self->output_adapter));
   self->started = FALSE;
 
   return GST_FLOW_OK;
index 5cefd88..0f4adc6 100644 (file)
@@ -76,6 +76,8 @@ struct _GstOMXAudioDec
   /* TRUE if EOS buffers shouldn't be forwarded */
   gboolean draining;
 
+  GstAdapter *output_adapter;
+
   GstFlowReturn downstream_flow_ret;
 };