avauddec: accumulate buffers from a single input to push it all at once
authorThiago Santos <thiago.sousa.santos@collabora.com>
Mon, 3 Dec 2012 19:38:53 +0000 (16:38 -0300)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 17 Dec 2012 14:56:03 +0000 (15:56 +0100)
The base audio decoder wants a 1:1 mapping for input and output
buffers, so this decoder must accumulate data in an adapter and push
it all at once after all input has been processed.

https://bugzilla.gnome.org/show_bug.cgi?id=689565

ext/libav/gstavauddec.c
ext/libav/gstavauddec.h

index 8834354a8bdbb5e0686b7935ff549a7cd576b036..570b9b5f606b5c7f22e9ac8a9b8484dcf012bc05 100644 (file)
@@ -54,6 +54,8 @@ static gboolean gst_ffmpegauddec_negotiate (GstFFMpegAudDec * ffmpegdec,
     gboolean force);
 
 static void gst_ffmpegauddec_drain (GstFFMpegAudDec * ffmpegdec);
+static GstFlowReturn
+gst_ffmpegauddec_push_output_buffer (GstFFMpegAudDec * ffmpegdec);
 
 #define GST_FFDEC_PARAMS_QDATA g_quark_from_static_string("avdec-params")
 
@@ -138,6 +140,8 @@ gst_ffmpegauddec_init (GstFFMpegAudDec * ffmpegdec)
   ffmpegdec->context = avcodec_alloc_context3 (klass->in_plugin);
   ffmpegdec->opened = FALSE;
 
+  ffmpegdec->adapter = gst_adapter_new ();
+
   gst_audio_decoder_set_drainable (GST_AUDIO_DECODER (ffmpegdec), TRUE);
   gst_audio_decoder_set_needs_format (GST_AUDIO_DECODER (ffmpegdec), TRUE);
 }
@@ -151,6 +155,9 @@ gst_ffmpegauddec_finalize (GObject * object)
     av_free (ffmpegdec->context);
   ffmpegdec->context = NULL;
 
+  gst_object_unref (ffmpegdec->adapter);
+  ffmpegdec->adapter = NULL;
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -164,6 +171,7 @@ gst_ffmpegauddec_close (GstFFMpegAudDec * ffmpegdec)
   GST_LOG_OBJECT (ffmpegdec, "closing libav codec");
 
   gst_caps_replace (&ffmpegdec->last_caps, NULL);
+  gst_adapter_clear (ffmpegdec->adapter);
 
   if (ffmpegdec->opened)
     gst_ffmpeg_avcodec_close (ffmpegdec->context);
@@ -601,11 +609,9 @@ gst_ffmpegauddec_frame (GstFFMpegAudDec * ffmpegdec,
   }
 
   if (outbuf) {
-    GST_LOG_OBJECT (ffmpegdec, "Decoded data, now pushing buffer %p", outbuf);
+    GST_LOG_OBJECT (ffmpegdec, "Decoded data, now storing buffer %p", outbuf);
 
-    *ret =
-        gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (ffmpegdec), outbuf,
-        1);
+    gst_adapter_push (ffmpegdec->adapter, outbuf);
   } else {
     GST_DEBUG_OBJECT (ffmpegdec, "We didn't get a decoded buffer");
   }
@@ -642,6 +648,7 @@ gst_ffmpegauddec_drain (GstFFMpegAudDec * ffmpegdec)
         break;
     } while (try++ < 10);
   }
+  gst_ffmpegauddec_push_output_buffer (ffmpegdec);
 }
 
 static void
@@ -739,6 +746,8 @@ gst_ffmpegauddec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf)
   gst_buffer_unmap (inbuf, &map);
   gst_buffer_unref (inbuf);
 
+  gst_ffmpegauddec_push_output_buffer (ffmpegdec);
+
   if (bsize > 0) {
     GST_DEBUG_OBJECT (ffmpegdec, "Dropping %d bytes of data", bsize);
   }
@@ -756,6 +765,21 @@ not_negotiated:
   }
 }
 
+static GstFlowReturn
+gst_ffmpegauddec_push_output_buffer (GstFFMpegAudDec * ffmpegdec)
+{
+  GstBuffer *outbuf;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  if (gst_adapter_available (ffmpegdec->adapter) > 0) {
+    outbuf = gst_adapter_take_buffer (ffmpegdec->adapter,
+        gst_adapter_available (ffmpegdec->adapter));
+    ret = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (ffmpegdec), outbuf,
+        1);
+  }
+  return ret;
+}
+
 gboolean
 gst_ffmpegauddec_register (GstPlugin * plugin)
 {
index 6ce4d507c8df237630036c1bb6d71511dec986d3..7948c16a6f28798c35a6c161c4dfe40ac8dd70a5 100644 (file)
@@ -38,6 +38,9 @@ struct _GstFFMpegAudDec
   /* prevent reopening the decoder on GST_EVENT_CAPS when caps are same as last time. */
   GstCaps *last_caps;
 
+  /* Stores current buffers to push as GstAudioDecoder wants 1:1 mapping for input/output buffers */
+  GstAdapter *adapter;
+
   /* current output format */
   GstAudioInfo info;
   GstAudioChannelPosition ffmpeg_layout[64];