diff options
author | Jan Schmidt <jan@centricular.com> | 2013-12-26 23:21:45 +1100 |
---|---|---|
committer | Jan Schmidt <jan@centricular.com> | 2013-12-27 04:04:45 +1100 |
commit | c24a1254c9f1f73e23a1471ce9dd08f513618c8b (patch) | |
tree | c68e0e95c92fd70529d191e33ac3bd0750a8e829 /gst-libs/gst/audio/gstaudiodecoder.c | |
parent | 01c7fb11ba17bd70bd00ab5c2db6639ea9da3458 (diff) |
audiodecoder: Choose a default initial caps before sending GAP
If there are no caps from the audio decoder when handling a GAP
event - as when one is received right at the start on a DVD without
initial audio - then choose any default caps for downstream and
then send the GAP, so the audio sink has a configured format in
which to start the ringbuffer.
Also, make the audio sink reject a GAP without caps with a clearer
error message.
Fixes bug https://bugzilla.gnome.org/show_bug.cgi?id=603921
Diffstat (limited to 'gst-libs/gst/audio/gstaudiodecoder.c')
-rw-r--r-- | gst-libs/gst/audio/gstaudiodecoder.c | 114 |
1 files changed, 82 insertions, 32 deletions
diff --git a/gst-libs/gst/audio/gstaudiodecoder.c b/gst-libs/gst/audio/gstaudiodecoder.c index c8068716e..7bd338f17 100644 --- a/gst-libs/gst/audio/gstaudiodecoder.c +++ b/gst-libs/gst/audio/gstaudiodecoder.c @@ -1732,6 +1732,86 @@ gst_audio_decoder_do_byte (GstAudioDecoder * dec) dec->priv->ctx.info.rate <= dec->priv->samples_out; } +/* Must be called holding the GST_AUDIO_DECODER_STREAM_LOCK */ +static gboolean +gst_audio_decoder_negotiate_default_caps (GstAudioDecoder * dec) +{ + GstCaps *caps; + + caps = gst_pad_get_current_caps (dec->srcpad); + if (caps && !gst_audio_info_from_caps (&dec->priv->ctx.info, caps)) + return FALSE; + + caps = gst_pad_get_allowed_caps (dec->srcpad); + if (!caps || gst_caps_is_empty (caps) || gst_caps_is_any (caps)) + return FALSE; + + caps = gst_caps_fixate (caps); + if (!caps || !gst_audio_info_from_caps (&dec->priv->ctx.info, caps)) + return FALSE; + + GST_INFO_OBJECT (dec, + "Chose default caps %" GST_PTR_FORMAT " for initial gap", caps); + gst_caps_unref (caps); + + if (!gst_audio_decoder_negotiate_unlocked (dec)) { + GST_INFO_OBJECT (dec, "Failed to negotiate default caps for initial gap"); + gst_pad_mark_reconfigure (dec->srcpad); + return FALSE; + } + + return TRUE; +} + +static gboolean +gst_audio_decoder_handle_gap (GstAudioDecoder * dec, GstEvent * event) +{ + gboolean ret; + GstClockTime timestamp, duration; + + /* Ensure we have caps first */ + GST_AUDIO_DECODER_STREAM_LOCK (dec); + if (!GST_AUDIO_INFO_IS_VALID (&dec->priv->ctx.info)) { + if (!gst_audio_decoder_negotiate_default_caps (dec)) { + GST_ELEMENT_ERROR (dec, STREAM, FORMAT, (NULL), + ("Decoder output not negotiated before GAP event.")); + GST_AUDIO_DECODER_STREAM_UNLOCK (dec); + return FALSE; + } + } + GST_AUDIO_DECODER_STREAM_UNLOCK (dec); + + gst_event_parse_gap (event, ×tamp, &duration); + + /* time progressed without data, see if we can fill the gap with + * some concealment data */ + GST_DEBUG_OBJECT (dec, + "gap event: plc %d, do_plc %d, position %" GST_TIME_FORMAT + " duration %" GST_TIME_FORMAT, + dec->priv->plc, dec->priv->ctx.do_plc, + GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration)); + + if (dec->priv->plc && dec->priv->ctx.do_plc && dec->input_segment.rate > 0.0) { + GstAudioDecoderClass *klass = GST_AUDIO_DECODER_GET_CLASS (dec); + GstBuffer *buf; + + /* hand subclass empty frame with duration that needs covering */ + buf = gst_buffer_new (); + GST_BUFFER_TIMESTAMP (buf) = timestamp; + GST_BUFFER_DURATION (buf) = duration; + /* best effort, not much error handling */ + gst_audio_decoder_handle_frame (dec, klass, buf); + ret = TRUE; + gst_event_unref (event); + } else { + /* sub-class doesn't know how to handle empty buffers, + * so just try sending GAP downstream */ + send_pending_events (dec); + ret = gst_audio_decoder_push_event (dec, event); + } + return ret; +} + static gboolean gst_audio_decoder_sink_eventfunc (GstAudioDecoder * dec, GstEvent * event) { @@ -1819,39 +1899,9 @@ gst_audio_decoder_sink_eventfunc (GstAudioDecoder * dec, GstEvent * event) ret = TRUE; break; } - case GST_EVENT_GAP:{ - GstClockTime timestamp, duration; - gst_event_parse_gap (event, ×tamp, &duration); - - /* time progressed without data, see if we can fill the gap with - * some concealment data */ - GST_DEBUG_OBJECT (dec, - "gap event: plc %d, do_plc %d, position %" GST_TIME_FORMAT - " duration %" GST_TIME_FORMAT, - dec->priv->plc, dec->priv->ctx.do_plc, - GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration)); - if (dec->priv->plc && dec->priv->ctx.do_plc && - dec->input_segment.rate > 0.0) { - GstAudioDecoderClass *klass; - GstBuffer *buf; - - klass = GST_AUDIO_DECODER_GET_CLASS (dec); - /* hand subclass empty frame with duration that needs covering */ - buf = gst_buffer_new (); - GST_BUFFER_TIMESTAMP (buf) = timestamp; - GST_BUFFER_DURATION (buf) = duration; - /* best effort, not much error handling */ - gst_audio_decoder_handle_frame (dec, klass, buf); - ret = TRUE; - gst_event_unref (event); - } else { - /* FIXME: sub-class doesn't know how to handle empty buffers, - * so just try sending GAP downstream */ - send_pending_events (dec); - ret = gst_audio_decoder_push_event (dec, event); - } + case GST_EVENT_GAP: + ret = gst_audio_decoder_handle_gap (dec, event); break; - } case GST_EVENT_FLUSH_STOP: GST_AUDIO_DECODER_STREAM_LOCK (dec); /* prepare for fresh start */ |