gst-plugins-good: speexdec: Get and use streamheader from the caps if possible

Sebastian Dröge slomo at kemper.freedesktop.org
Thu Mar 24 01:00:38 PDT 2011


Module: gst-plugins-good
Branch: master
Commit: 85ace6d413f2b0ea24af955dc28b499149b584b5
URL:    http://cgit.freedesktop.org/gstreamer/gst-plugins-good/commit/?id=85ace6d413f2b0ea24af955dc28b499149b584b5

Author: Sebastian Dröge <sebastian.droege at collabora.co.uk>
Date:   Wed Mar 23 16:34:16 2011 +0100

speexdec: Get and use streamheader from the caps if possible

This allows playback of streams where the streamheader buffers
were dropped from the stream for some reason.

---

 ext/speex/gstspeexdec.c |   89 +++++++++++++++++++++++++++++++++++++++++-----
 ext/speex/gstspeexdec.h |    3 ++
 2 files changed, 82 insertions(+), 10 deletions(-)

diff --git a/ext/speex/gstspeexdec.c b/ext/speex/gstspeexdec.c
index 0c8c343..46f774b 100644
--- a/ext/speex/gstspeexdec.c
+++ b/ext/speex/gstspeexdec.c
@@ -86,6 +86,7 @@ static GstStateChangeReturn speex_dec_change_state (GstElement * element,
 static gboolean speex_dec_src_event (GstPad * pad, GstEvent * event);
 static gboolean speex_dec_src_query (GstPad * pad, GstQuery * query);
 static gboolean speex_dec_sink_query (GstPad * pad, GstQuery * query);
+static gboolean speex_dec_sink_setcaps (GstPad * pad, GstCaps * caps);
 static const GstQueryType *speex_get_src_query_types (GstPad * pad);
 static const GstQueryType *speex_get_sink_query_types (GstPad * pad);
 static gboolean speex_dec_convert (GstPad * pad,
@@ -100,6 +101,11 @@ static void gst_speex_dec_set_property (GObject * object, guint prop_id,
 static GstFlowReturn speex_dec_chain_parse_data (GstSpeexDec * dec,
     GstBuffer * buf, GstClockTime timestamp, GstClockTime duration);
 
+static GstFlowReturn speex_dec_chain_parse_header (GstSpeexDec * dec,
+    GstBuffer * buf);
+static GstFlowReturn speex_dec_chain_parse_comments (GstSpeexDec * dec,
+    GstBuffer * buf);
+
 static void
 gst_speex_dec_base_init (gpointer g_class)
 {
@@ -148,6 +154,9 @@ gst_speex_dec_reset (GstSpeexDec * dec)
   dec->header = NULL;
   speex_bits_destroy (&dec->bits);
 
+  gst_buffer_replace (&dec->streamheader, NULL);
+  gst_buffer_replace (&dec->vorbiscomment, NULL);
+
   if (dec->stereo) {
     speex_stereo_state_destroy (dec->stereo);
     dec->stereo = NULL;
@@ -172,6 +181,8 @@ gst_speex_dec_init (GstSpeexDec * dec, GstSpeexDecClass * g_class)
       GST_DEBUG_FUNCPTR (speex_get_sink_query_types));
   gst_pad_set_query_function (dec->sinkpad,
       GST_DEBUG_FUNCPTR (speex_dec_sink_query));
+  gst_pad_set_setcaps_function (dec->sinkpad,
+      GST_DEBUG_FUNCPTR (speex_dec_sink_setcaps));
   gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
 
   dec->srcpad =
@@ -191,6 +202,46 @@ gst_speex_dec_init (GstSpeexDec * dec, GstSpeexDecClass * g_class)
 }
 
 static gboolean
+speex_dec_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+  GstSpeexDec *dec = GST_SPEEX_DEC (gst_pad_get_parent (pad));
+  gboolean ret = TRUE;
+  GstStructure *s;
+  const GValue *streamheader;
+
+  s = gst_caps_get_structure (caps, 0);
+  if ((streamheader = gst_structure_get_value (s, "streamheader")) &&
+      G_VALUE_HOLDS (streamheader, GST_TYPE_ARRAY) &&
+      gst_value_array_get_size (streamheader) >= 2) {
+    const GValue *header, *vorbiscomment;
+    GstBuffer *buf;
+    GstFlowReturn res = GST_FLOW_OK;
+
+    header = gst_value_array_get_value (streamheader, 0);
+    if (header && G_VALUE_HOLDS (header, GST_TYPE_BUFFER)) {
+      buf = gst_value_get_buffer (header);
+      res = speex_dec_chain_parse_header (dec, buf);
+      if (res != GST_FLOW_OK)
+        goto done;
+      gst_buffer_replace (&dec->streamheader, buf);
+    }
+
+    vorbiscomment = gst_value_array_get_value (streamheader, 1);
+    if (vorbiscomment && G_VALUE_HOLDS (vorbiscomment, GST_TYPE_BUFFER)) {
+      buf = gst_value_get_buffer (vorbiscomment);
+      res = speex_dec_chain_parse_comments (dec, buf);
+      if (res != GST_FLOW_OK)
+        goto done;
+      gst_buffer_replace (&dec->vorbiscomment, buf);
+    }
+  }
+
+done:
+  gst_object_unref (dec);
+  return ret;
+}
+
+static gboolean
 speex_dec_convert (GstPad * pad,
     GstFormat src_format, gint64 src_value,
     GstFormat * dest_format, gint64 * dest_value)
@@ -760,19 +811,37 @@ speex_dec_chain (GstPad * pad, GstBuffer * buf)
 
   dec = GST_SPEEX_DEC (gst_pad_get_parent (pad));
 
-  switch (dec->packetno) {
-    case 0:
-      res = speex_dec_chain_parse_header (dec, buf);
-      break;
-    case 1:
-      res = speex_dec_chain_parse_comments (dec, buf);
-      break;
-    default:
-    {
+  /* If we have the streamheader and vorbiscomment from the caps already
+   * ignore them here */
+  if (dec->streamheader && dec->vorbiscomment) {
+    if (GST_BUFFER_SIZE (dec->streamheader) == GST_BUFFER_SIZE (buf)
+        && memcmp (GST_BUFFER_DATA (dec->streamheader), GST_BUFFER_DATA (buf),
+            GST_BUFFER_SIZE (buf)) == 0) {
+      res = GST_FLOW_OK;
+    } else if (GST_BUFFER_SIZE (dec->vorbiscomment) == GST_BUFFER_SIZE (buf)
+        && memcmp (GST_BUFFER_DATA (dec->vorbiscomment), GST_BUFFER_DATA (buf),
+            GST_BUFFER_SIZE (buf)) == 0) {
+      res = GST_FLOW_OK;
+    } else {
       res =
           speex_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf),
           GST_BUFFER_DURATION (buf));
-      break;
+    }
+  } else {
+    /* Otherwise fall back to packet counting and assume that the
+     * first two packets are the headers. */
+    switch (dec->packetno) {
+      case 0:
+        res = speex_dec_chain_parse_header (dec, buf);
+        break;
+      case 1:
+        res = speex_dec_chain_parse_comments (dec, buf);
+        break;
+      default:
+        res =
+            speex_dec_chain_parse_data (dec, buf, GST_BUFFER_TIMESTAMP (buf),
+            GST_BUFFER_DURATION (buf));
+        break;
     }
   }
 
diff --git a/ext/speex/gstspeexdec.h b/ext/speex/gstspeexdec.h
index 6419a6e..660d805 100644
--- a/ext/speex/gstspeexdec.h
+++ b/ext/speex/gstspeexdec.h
@@ -68,6 +68,9 @@ struct _GstSpeexDec {
   guint64               packetno;
 
   GstSegment            segment;    /* STREAM LOCK */
+
+  GstBuffer             *streamheader;
+  GstBuffer             *vorbiscomment;
 };
 
 struct _GstSpeexDecClass {



More information about the gstreamer-commits mailing list