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
This commit is contained in:
parent
01c7fb11ba
commit
c24a1254c9
@ -1029,6 +1029,13 @@ gst_audio_base_sink_wait_event (GstBaseSink * bsink, GstEvent * event)
|
||||
GstMapInfo minfo;
|
||||
|
||||
spec = &sink->ringbuffer->spec;
|
||||
if (G_UNLIKELY (spec->info.rate == 0)) {
|
||||
GST_ELEMENT_ERROR (sink, STREAM, FORMAT, (NULL),
|
||||
("Sink not negotiated before GAP event."));
|
||||
ret = GST_FLOW_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
gst_event_parse_gap (event, ×tamp, &duration);
|
||||
|
||||
/* If the GAP event has a duration, handle it like a
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user