decodebin3: try candidate decoders to select the first one that works

Send sticky events to the new created decoder after it switches
to PAUSED state. It it fails, just skip this decoder and try the
next one until finding one that works. Otherwise remove this
failing stream after trying all decoders and no one can work.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4677>
This commit is contained in:
Hou Qi 2023-05-29 13:24:40 +08:00 committed by GStreamer Marge Bot
parent 6fc6e934aa
commit 887ae4d9e0

View file

@ -2938,35 +2938,29 @@ reconfigure_output_stream (DecodebinOutputStream * output,
GList *factories, *next_factory; GList *factories, *next_factory;
factories = next_factory = create_decoder_factory_list (dbin, new_caps); factories = next_factory = create_decoder_factory_list (dbin, new_caps);
while (!output->decoder) { if (!next_factory) {
gboolean decoder_failed = FALSE;
/* If we don't have a decoder yet, instantiate one */
if (next_factory) {
output->decoder = gst_element_factory_create ((GstElementFactory *)
next_factory->data, NULL);
GST_DEBUG ("Created decoder %" GST_PTR_FORMAT, output->decoder);
} else {
GST_DEBUG ("Could not find an element for caps %" GST_PTR_FORMAT, GST_DEBUG ("Could not find an element for caps %" GST_PTR_FORMAT,
new_caps); new_caps);
g_assert (output->decoder == NULL); g_assert (output->decoder == NULL);
}
if (output->decoder == NULL) {
GstCaps *caps;
/* FIXME : Should we be smarter if there's a missing decoder ?
* Should we deactivate that stream ? */
caps = gst_stream_get_caps (slot->active_stream);
*msg = gst_missing_decoder_message_new (GST_ELEMENT_CAST (dbin), caps);
gst_caps_unref (caps);
ret = FALSE; ret = FALSE;
goto cleanup; goto missing_decoder;
} }
while (next_factory) {
gboolean decoder_failed = FALSE;
/* If we don't have a decoder yet, instantiate one */
output->decoder = gst_element_factory_create ((GstElementFactory *)
next_factory->data, NULL);
GST_DEBUG ("Trying decoder %" GST_PTR_FORMAT, output->decoder);
if (output->decoder == NULL)
goto try_next;
if (!gst_bin_add ((GstBin *) dbin, output->decoder)) { if (!gst_bin_add ((GstBin *) dbin, output->decoder)) {
GST_ERROR_OBJECT (dbin, "could not add decoder to pipeline"); GST_WARNING_OBJECT (dbin, "could not add decoder '%s' to pipeline",
ret = FALSE; GST_ELEMENT_NAME (output->decoder));
goto cleanup; goto try_next;
} }
output->decoder_sink = output->decoder_sink =
gst_element_get_static_pad (output->decoder, "sink"); gst_element_get_static_pad (output->decoder, "sink");
@ -2977,27 +2971,29 @@ reconfigure_output_stream (DecodebinOutputStream * output,
gst_pad_add_probe (slot->src_pad, GST_PAD_PROBE_TYPE_BUFFER, gst_pad_add_probe (slot->src_pad, GST_PAD_PROBE_TYPE_BUFFER,
(GstPadProbeCallback) keyframe_waiter_probe, output, NULL); (GstPadProbeCallback) keyframe_waiter_probe, output, NULL);
} }
if (gst_pad_link_full (slot->src_pad, output->decoder_sink, if (gst_pad_link_full (slot->src_pad, output->decoder_sink,
GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK) { GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK) {
GST_ERROR_OBJECT (dbin, "could not link to %s:%s", GST_WARNING_OBJECT (dbin, "could not link to %s:%s",
GST_DEBUG_PAD_NAME (output->decoder_sink)); GST_DEBUG_PAD_NAME (output->decoder_sink));
ret = FALSE; goto try_next;
goto cleanup;
} }
if (gst_element_set_state (output->decoder, if (gst_element_set_state (output->decoder,
GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) { GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
GST_DEBUG_OBJECT (dbin, GST_WARNING_OBJECT (dbin,
"Decoder '%s' failed to reach READY state, trying the next type", "Decoder '%s' failed to reach READY state",
GST_ELEMENT_NAME (output->decoder)); GST_ELEMENT_NAME (output->decoder));
decoder_failed = TRUE; decoder_failed = TRUE;
remove_decoder_link (output, slot); goto try_next;
} }
if (!gst_pad_query_accept_caps (output->decoder_sink, new_caps)) { if (!gst_pad_query_accept_caps (output->decoder_sink, new_caps)) {
GST_DEBUG_OBJECT (dbin, GST_DEBUG_OBJECT (dbin,
"Decoder '%s' did not accept the caps, trying the next type", "Decoder '%s' did not accept the caps, trying the next type",
GST_ELEMENT_NAME (output->decoder)); GST_ELEMENT_NAME (output->decoder));
decoder_failed = TRUE; decoder_failed = TRUE;
remove_decoder_link (output, slot); goto try_next;
} }
/* First lock element's sinkpad stream lock so no data reaches /* First lock element's sinkpad stream lock so no data reaches
@ -3013,14 +3009,33 @@ reconfigure_output_stream (DecodebinOutputStream * output,
GST_WARNING_OBJECT (dbin, GST_WARNING_OBJECT (dbin,
"Decoder '%s' failed to reach PAUSED state", "Decoder '%s' failed to reach PAUSED state",
GST_ELEMENT_NAME (output->decoder)); GST_ELEMENT_NAME (output->decoder));
remove_decoder_link (output, slot); decoder_failed = TRUE;
goto try_next;
} else { } else {
/* Everything went well */ /* Everything went well */
GST_PAD_STREAM_UNLOCK (output->decoder_sink); GST_PAD_STREAM_UNLOCK (output->decoder_sink);
output->linked = TRUE;
GST_DEBUG ("created decoder %" GST_PTR_FORMAT, output->decoder);
} }
break;
try_next:
{
if (decoder_failed)
remove_decoder_link (output, slot);
if (!next_factory->next) {
ret = FALSE;
if (!decoder_failed)
goto cleanup;
if (output->decoder == NULL)
goto missing_decoder;
} else {
next_factory = next_factory->next; next_factory = next_factory->next;
} }
}
}
gst_plugin_feature_list_free (factories); gst_plugin_feature_list_free (factories);
} else { } else {
output->decoder_src = gst_object_ref (slot->src_pad); output->decoder_src = gst_object_ref (slot->src_pad);
@ -3028,7 +3043,6 @@ reconfigure_output_stream (DecodebinOutputStream * output,
} }
gst_caps_unref (new_caps); gst_caps_unref (new_caps);
output->linked = TRUE;
if (!decode_pad_set_target ((GstGhostPad *) output->src_pad, if (!decode_pad_set_target ((GstGhostPad *) output->src_pad,
output->decoder_src)) { output->decoder_src)) {
GST_ERROR_OBJECT (dbin, "Could not expose decoder pad"); GST_ERROR_OBJECT (dbin, "Could not expose decoder pad");
@ -3060,6 +3074,14 @@ reconfigure_output_stream (DecodebinOutputStream * output,
output->slot = slot; output->slot = slot;
return ret; return ret;
missing_decoder:
{
GstCaps *caps;
caps = gst_stream_get_caps (slot->active_stream);
*msg = gst_missing_decoder_message_new (GST_ELEMENT_CAST (dbin), caps);
gst_caps_unref (caps);
}
cleanup: cleanup:
{ {
GST_DEBUG_OBJECT (dbin, "Cleanup"); GST_DEBUG_OBJECT (dbin, "Cleanup");