summaryrefslogtreecommitdiff
path: root/gst-libs/gst/audio/gstaudiodecoder.c
diff options
context:
space:
mode:
authorJan Schmidt <jan@centricular.com>2013-12-26 23:21:45 +1100
committerJan Schmidt <jan@centricular.com>2013-12-27 04:04:45 +1100
commitc24a1254c9f1f73e23a1471ce9dd08f513618c8b (patch)
treec68e0e95c92fd70529d191e33ac3bd0750a8e829 /gst-libs/gst/audio/gstaudiodecoder.c
parent01c7fb11ba17bd70bd00ab5c2db6639ea9da3458 (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.c114
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
@@ -1729,12 +1729,92 @@ static inline gboolean
gst_audio_decoder_do_byte (GstAudioDecoder * dec)
{
return dec->priv->ctx.do_estimate_rate && dec->priv->ctx.info.bpf &&
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, &timestamp, &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)
{
gboolean ret;
switch (GST_EVENT_TYPE (event)) {
@@ -1816,45 +1896,15 @@ gst_audio_decoder_sink_eventfunc (GstAudioDecoder * dec, GstEvent * event)
g_list_append (dec->priv->pending_events, event);
GST_AUDIO_DECODER_STREAM_UNLOCK (dec);
ret = TRUE;
break;
}
- case GST_EVENT_GAP:{
- GstClockTime timestamp, duration;
- gst_event_parse_gap (event, &timestamp, &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 */
gst_audio_decoder_flush (dec, TRUE);
g_list_foreach (dec->priv->pending_events, (GFunc) gst_event_unref, NULL);