From d6f1c517f3e93836a2dfd6dbc85f067224924584 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 24 May 2023 16:39:54 +0200 Subject: [PATCH] decodebin3: Handle changes in stream type While decodebin3 could handle changes in inputs (ex: changing codecs), there was still one limitation which was when changing between sources which had non-intersecting stream types (ex: switching from a video-only source to a audio-only source). While the decoder *could* change to the proper codec ... it would carry on using a `DecodebinOutputStream` associated to that stream type (and therefore with pads with the wrong name). In order to handle this: * We notify the `MultiQueueSlot` of the change in `GstStreamType` if it already had an associated inputstream (ex: the one associated with the static sink pad) * We detect such changes on the output of multiqueue as soon as possible (i.e. when we get the GST_EVENT_STREAM_START for the new stream type) by discarding the associated output. Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1669 Part-of: --- .../gst/playback/gstdecodebin3.c | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/subprojects/gst-plugins-base/gst/playback/gstdecodebin3.c b/subprojects/gst-plugins-base/gst/playback/gstdecodebin3.c index 95efdbf924..721290ff41 100644 --- a/subprojects/gst-plugins-base/gst/playback/gstdecodebin3.c +++ b/subprojects/gst-plugins-base/gst/playback/gstdecodebin3.c @@ -2376,11 +2376,31 @@ multiqueue_src_probe (GstPad * pad, GstPadProbeInfo * info, if (slot->active_stream == NULL) { slot->active_stream = stream; } else if (slot->active_stream != stream) { - GST_FIXME_OBJECT (pad, "Handle stream changes (%s => %s) !", + gboolean stream_type_changed = + gst_stream_get_stream_type (stream) != + gst_stream_get_stream_type (slot->active_stream); + + GST_DEBUG_OBJECT (pad, "Stream change (%s => %s) !", gst_stream_get_stream_id (slot->active_stream), gst_stream_get_stream_id (stream)); gst_object_unref (slot->active_stream); slot->active_stream = stream; + + if (stream_type_changed) { + /* The stream type has changed, we get rid of the current output. A + * new one (targetting the new stream type) will be created once the + * caps are received. */ + GST_DEBUG_OBJECT (pad, + "Stream type change, discarding current output stream"); + if (slot->output) { + DecodebinOutputStream *output = slot->output; + SELECTION_LOCK (dbin); + dbin->output_streams = + g_list_remove (dbin->output_streams, output); + free_output_stream (dbin, output); + SELECTION_UNLOCK (dbin); + } + } } else gst_object_unref (stream); #if 0 /* Disabled because stream-start is pushed for every buffer on every unlinked pad */ @@ -2615,6 +2635,20 @@ get_slot_for_input (GstDecodebin3 * dbin, DecodebinInputStream * input) /* Already used input, return that one */ if (slot->input == input) { GST_DEBUG_OBJECT (dbin, "Returning already specified slot %d", slot->id); + if (input_type && slot->type != input_type) { + /* The input stream type has changed. It is the responsibility of the + * user of decodebin3 to ensure that the inputs are coherent. + * + * The only case where the stream type will change is when switching + * between sources which have non-intersecting stream types (ex: + * switching from audio-only file to video-only file) + * + * NOTE : We need to change the slot type here, since it is notified as + * soon as the *input* of the slot changes. + */ + GST_DEBUG_OBJECT (dbin, "Changing multiqueue slot stream type"); + slot->type = input_type; + } return slot; } }