mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-09 17:44:14 +00:00
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.
This commit is contained in:
parent
87e1b06cac
commit
85ace6d413
2 changed files with 82 additions and 10 deletions
ext/speex
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,9 @@ struct _GstSpeexDec {
|
|||
guint64 packetno;
|
||||
|
||||
GstSegment segment; /* STREAM LOCK */
|
||||
|
||||
GstBuffer *streamheader;
|
||||
GstBuffer *vorbiscomment;
|
||||
};
|
||||
|
||||
struct _GstSpeexDecClass {
|
||||
|
|
Loading…
Reference in a new issue