From 85ace6d413f2b0ea24af955dc28b499149b584b5 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 23 Mar 2011 16:34:16 +0100 Subject: [PATCH] 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 0c8c3434e..46f774b8f 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 = @@ -190,6 +201,46 @@ gst_speex_dec_init (GstSpeexDec * dec, GstSpeexDecClass * g_class) gst_speex_dec_reset (dec); } +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, @@ -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 6419a6ecf..660d8053d 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 { -- 2.34.1