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