decodebin3: Refactor/rename slot/output

* Centralize associating an output to a slot in one function, including properly
  resetting those fields
* Rename functions to be more explicit
* Move code to "reset" an output stream into a dedicated function (will be used
later)

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6774>
This commit is contained in:
Edward Hervey 2024-03-22 11:55:40 +01:00 committed by GStreamer Marge Bot
parent 1185a560c2
commit fc96e29606

View File

@ -546,9 +546,9 @@ static void gst_decodebin_input_unblock_streams (DecodebinInput * input,
static gboolean reconfigure_output_stream (DecodebinOutputStream * output, static gboolean reconfigure_output_stream (DecodebinOutputStream * output,
MultiQueueSlot * slot, GstMessage ** msg); MultiQueueSlot * slot, GstMessage ** msg);
static void free_output_stream (GstDecodebin3 * dbin, static void db_output_stream_reset (DecodebinOutputStream * output);
DecodebinOutputStream * output); static void db_output_stream_free (DecodebinOutputStream * output);
static DecodebinOutputStream *create_output_stream (GstDecodebin3 * dbin, static DecodebinOutputStream *db_output_stream_new (GstDecodebin3 * dbin,
GstStreamType type); GstStreamType type);
static GstPadProbeReturn slot_unassign_probe (GstPad * pad, static GstPadProbeReturn slot_unassign_probe (GstPad * pad,
@ -695,11 +695,8 @@ gst_decodebin3_reset (GstDecodebin3 * dbin)
GST_DEBUG_OBJECT (dbin, "Resetting"); GST_DEBUG_OBJECT (dbin, "Resetting");
/* Free output streams */ /* Free output streams */
for (tmp = dbin->output_streams; tmp; tmp = tmp->next) { g_list_free_full (dbin->output_streams,
DecodebinOutputStream *output = (DecodebinOutputStream *) tmp->data; (GDestroyNotify) db_output_stream_free);
free_output_stream (dbin, output);
}
g_list_free (dbin->output_streams);
dbin->output_streams = NULL; dbin->output_streams = NULL;
/* Free multiqueue slots */ /* Free multiqueue slots */
@ -1408,7 +1405,7 @@ remove_slot_from_streaming_thread (GstDecodebin3 * dbin, MultiQueueSlot * slot)
"Multiqueue slot is drained, Remove output stream"); "Multiqueue slot is drained, Remove output stream");
dbin->output_streams = g_list_remove (dbin->output_streams, output); dbin->output_streams = g_list_remove (dbin->output_streams, output);
free_output_stream (dbin, output); db_output_stream_free (output);
} }
GST_DEBUG_OBJECT (slot->src_pad, "No pending pad, Remove multiqueue slot"); GST_DEBUG_OBJECT (slot->src_pad, "No pending pad, Remove multiqueue slot");
@ -2917,11 +2914,73 @@ find_free_compatible_output (GstDecodebin3 * dbin, GstStream * stream)
return NULL; return NULL;
} }
/* Give a certain slot, figure out if it should be linked to an /** mq_slot_set_output:
* output stream * @slot: A #MultiQueueSlot
* CALL WITH SELECTION LOCK TAKEN !*/ * @output: (allow none): A #DecodebinOutputStream
*
* Sets @output as the @slot output. The slot present previously will be
* returned.
*
* If the output previously associated was linked (via a decoder) to the slot,
* they will be unlinked.
*
* Returns: The output previously used on @slot.
*/
static DecodebinOutputStream * static DecodebinOutputStream *
get_output_for_slot (MultiQueueSlot * slot) mq_slot_set_output (MultiQueueSlot * slot, DecodebinOutputStream * output)
{
DecodebinOutputStream *old_output = slot->output;
GST_DEBUG_OBJECT (slot->src_pad, "output: %p", output);
if (old_output == output) {
GST_LOG_OBJECT (slot->src_pad, "Already targetting that output");
return output;
}
if (old_output) {
if (!old_output->slot)
GST_DEBUG_OBJECT (slot->src_pad,
"Old output %p was not associated to any slot", old_output);
else
GST_DEBUG_OBJECT (slot->src_pad,
"Old output %p was associated to %" GST_PTR_FORMAT, old_output,
old_output->slot->src_pad);
/* Check for inconsistencies in assigning */
g_assert (old_output->slot == slot);
GST_DEBUG_OBJECT (slot->src_pad, "Unassigning");
if (old_output->decoder_sink && old_output->decoder)
gst_pad_unlink (slot->src_pad, old_output->decoder_sink);
old_output->linked = FALSE;
old_output->slot = NULL;
}
if (output) {
if (output->slot)
GST_DEBUG_OBJECT (slot->src_pad,
"New output was previously associated to slot %s:%s",
GST_DEBUG_PAD_NAME (output->slot->src_pad));
output->slot = slot;
}
slot->output = output;
return old_output;
}
/** mq_slot_get_or_create_output:
* @slot: A #MultiQueueSlot
*
* Provides the #DecodebinOutputStream the @slot should use. This function will
* figure that out based on the current selection. The slot output will be
* updated accordingly.
*
* Call with SELECTION_LOCK taken
*
* Returns: The #DecodebinOutputStream to use, or #NULL if none can/should be
* used.
*/
static DecodebinOutputStream *
mq_slot_get_or_create_output (MultiQueueSlot * slot)
{ {
GstDecodebin3 *dbin = slot->dbin; GstDecodebin3 *dbin = slot->dbin;
DecodebinOutputStream *output = NULL; DecodebinOutputStream *output = NULL;
@ -2930,8 +2989,11 @@ get_output_for_slot (MultiQueueSlot * slot)
gchar *id_in_list = NULL; gchar *id_in_list = NULL;
/* If we already have a configured output, just use it */ /* If we already have a configured output, just use it */
if (slot->output != NULL) if (slot->output != NULL) {
GST_LOG_OBJECT (slot->src_pad, "Returning current output %s:%s",
GST_DEBUG_PAD_NAME (slot->output->src_pad));
return slot->output; return slot->output;
}
/* /*
* FIXME * FIXME
@ -2950,7 +3012,8 @@ get_output_for_slot (MultiQueueSlot * slot)
stream_id = gst_stream_get_stream_id (slot->active_stream); stream_id = gst_stream_get_stream_id (slot->active_stream);
caps = gst_stream_get_caps (slot->active_stream); caps = gst_stream_get_caps (slot->active_stream);
GST_DEBUG_OBJECT (dbin, "stream %s , %" GST_PTR_FORMAT, stream_id, caps); GST_DEBUG_OBJECT (slot->src_pad, "stream %s , %" GST_PTR_FORMAT, stream_id,
caps);
gst_caps_unref (caps); gst_caps_unref (caps);
/* 0. Emit autoplug-continue signal for pending caps ? */ /* 0. Emit autoplug-continue signal for pending caps ? */
@ -2961,36 +3024,38 @@ get_output_for_slot (MultiQueueSlot * slot)
/* 3. In default mode check if we should expose */ /* 3. In default mode check if we should expose */
id_in_list = (gchar *) stream_in_list (dbin->requested_selection, stream_id); id_in_list = (gchar *) stream_in_list (dbin->requested_selection, stream_id);
if (id_in_list || dbin->upstream_handles_selection) { if (!id_in_list && !dbin->upstream_handles_selection) {
/* Check if we can steal an existing output stream we could re-use. GST_DEBUG_OBJECT (slot->src_pad, "Not selected, not creating any output");
* that is: return NULL;
* * an output stream whose slot->stream is not in requested }
* * and is of the same type as this stream
*/
output = find_free_compatible_output (dbin, slot->active_stream);
if (output) {
/* Move this output from its current slot to this slot */
dbin->to_activate =
g_list_append (dbin->to_activate, (gchar *) stream_id);
dbin->requested_selection =
g_list_remove (dbin->requested_selection, id_in_list);
g_free (id_in_list);
SELECTION_UNLOCK (dbin);
gst_pad_add_probe (output->slot->src_pad, GST_PAD_PROBE_TYPE_IDLE,
(GstPadProbeCallback) slot_unassign_probe, output->slot, NULL);
SELECTION_LOCK (dbin);
return NULL;
}
output = create_output_stream (dbin, slot->type); /* Check if we can steal an existing output stream we could re-use.
output->slot = slot; * that is:
GST_DEBUG ("Linking slot %p to new output %p", slot, output); * * an output stream whose slot->stream is not in requested
slot->output = output; * * and is of the same type as this stream
GST_DEBUG ("Adding '%s' to active_selection", stream_id); */
dbin->active_selection = output = find_free_compatible_output (dbin, slot->active_stream);
g_list_append (dbin->active_selection, (gchar *) g_strdup (stream_id)); if (output) {
} else GST_DEBUG_OBJECT (slot->src_pad, "Reassigning to output %s:%s",
GST_DEBUG ("Not creating any output for slot %p", slot); GST_DEBUG_PAD_NAME (output->src_pad));
/* Move this output from its current slot to this slot */
dbin->to_activate = g_list_append (dbin->to_activate, (gchar *) stream_id);
dbin->requested_selection =
g_list_remove (dbin->requested_selection, id_in_list);
g_free (id_in_list);
SELECTION_UNLOCK (dbin);
gst_pad_add_probe (output->slot->src_pad, GST_PAD_PROBE_TYPE_IDLE,
(GstPadProbeCallback) mq_slot_unassign_probe, output->slot, NULL);
SELECTION_LOCK (dbin);
return NULL;
}
output = db_output_stream_new (dbin, slot->type);
mq_slot_set_output (slot, output);
GST_DEBUG ("Adding '%s' to active_selection", stream_id);
dbin->active_selection =
g_list_append (dbin->active_selection, (gchar *) g_strdup (stream_id));
return output; return output;
} }
@ -3222,17 +3287,18 @@ multiqueue_src_probe (GstPad * pad, GstPadProbeInfo * info,
slot->active_stream = stream; slot->active_stream = stream;
if (stream_type_changed) { if (stream_type_changed) {
DecodebinOutputStream *previous_output;
/* The stream type has changed, we get rid of the current output. A /* 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 * new one (targetting the new stream type) will be created once the
* caps are received. */ * caps are received. */
GST_DEBUG_OBJECT (pad, previous_output = mq_slot_set_output (slot, NULL);
"Stream type change, discarding current output stream"); if (previous_output) {
if (slot->output) { GST_DEBUG_OBJECT (pad,
DecodebinOutputStream *output = slot->output; "Stream type change, discarding current output stream");
SELECTION_LOCK (dbin); SELECTION_LOCK (dbin);
dbin->output_streams = dbin->output_streams =
g_list_remove (dbin->output_streams, output); g_list_remove (dbin->output_streams, previous_output);
free_output_stream (dbin, output); db_output_stream_free (previous_output);
SELECTION_UNLOCK (dbin); SELECTION_UNLOCK (dbin);
} }
} }
@ -3884,15 +3950,9 @@ reassign_slot (GstDecodebin3 * dbin, MultiQueueSlot * slot)
} }
/* Unlink slot from output */ /* Unlink slot from output */
/* FIXME : Handle flushing ? */ GST_DEBUG_OBJECT (slot->src_pad, "Unlinking from previous output");
/* FIXME : Handle outputs without decoders */ mq_slot_set_output (slot, NULL);
GST_DEBUG_OBJECT (slot->src_pad, "Unlinking from decoder %p",
output->decoder_sink);
if (output->decoder_sink)
gst_pad_unlink (slot->src_pad, output->decoder_sink);
output->linked = FALSE;
slot->output = NULL;
output->slot = NULL;
/* Remove sid from active selection */ /* Remove sid from active selection */
GST_DEBUG ("Removing '%s' from active_selection", sid); GST_DEBUG ("Removing '%s' from active_selection", sid);
for (tmp = dbin->active_selection; tmp; tmp = tmp->next) for (tmp = dbin->active_selection; tmp; tmp = tmp->next)
@ -3923,8 +3983,7 @@ reassign_slot (GstDecodebin3 * dbin, MultiQueueSlot * slot)
if (target_slot) { if (target_slot) {
GST_DEBUG_OBJECT (slot->src_pad, "Assigning output to slot %p '%s'", GST_DEBUG_OBJECT (slot->src_pad, "Assigning output to slot %p '%s'",
target_slot, tsid); target_slot, tsid);
target_slot->output = output; mq_slot_set_output (target_slot, output);
output->slot = target_slot;
GST_DEBUG ("Adding '%s' to active_selection", tsid); GST_DEBUG ("Adding '%s' to active_selection", tsid);
dbin->active_selection = dbin->active_selection =
g_list_append (dbin->active_selection, (gchar *) g_strdup (tsid)); g_list_append (dbin->active_selection, (gchar *) g_strdup (tsid));
@ -3939,7 +3998,7 @@ reassign_slot (GstDecodebin3 * dbin, MultiQueueSlot * slot)
GstMessage *msg; GstMessage *msg;
dbin->output_streams = g_list_remove (dbin->output_streams, output); dbin->output_streams = g_list_remove (dbin->output_streams, output);
free_output_stream (dbin, output); db_output_stream_free (output);
msg = is_selection_done (slot->dbin); msg = is_selection_done (slot->dbin);
SELECTION_UNLOCK (dbin); SELECTION_UNLOCK (dbin);
@ -4282,11 +4341,17 @@ free_multiqueue_slot (GstDecodebin3 * dbin, MultiQueueSlot * slot)
g_free (slot); g_free (slot);
} }
/* Create a DecodebinOutputStream for a given type /** db_output_stream_new:
* Note: It will be empty initially, it needs to be configured * @dbin: A #GstDecodebin3
* afterwards */ * @type: The #GstStreamType
*
* Creates a #DecodebinOutputStream for the given type and adds it to the list
* of available outputs.
*
* Returns: a #DecodebinOutputStream for the given @type.
*/
static DecodebinOutputStream * static DecodebinOutputStream *
create_output_stream (GstDecodebin3 * dbin, GstStreamType type) db_output_stream_new (GstDecodebin3 * dbin, GstStreamType type)
{ {
DecodebinOutputStream *res = g_new0 (DecodebinOutputStream, 1); DecodebinOutputStream *res = g_new0 (DecodebinOutputStream, 1);
gchar *pad_name; gchar *pad_name;
@ -4338,29 +4403,74 @@ create_output_stream (GstDecodebin3 * dbin, GstStreamType type)
dbin->output_streams = g_list_append (dbin->output_streams, res); dbin->output_streams = g_list_append (dbin->output_streams, res);
GST_DEBUG_OBJECT (dbin, "Created output stream %p (%s:%s)", res,
GST_DEBUG_PAD_NAME (res->src_pad));
return res; return res;
} }
/** db_output_stream_reset:
* @output: A #DecodebinOutputStream
*
* Resets the @output to be able to be re-used by another slot/format. If a
* decoder is present it will be disabled and removed
*/
static void static void
free_output_stream (GstDecodebin3 * dbin, DecodebinOutputStream * output) db_output_stream_reset (DecodebinOutputStream * output)
{ {
if (output->slot) { MultiQueueSlot *slot = output->slot;
if (output->decoder_sink && output->decoder)
gst_pad_unlink (output->slot->src_pad, output->decoder_sink);
output->slot->output = NULL; GST_DEBUG_OBJECT (output->dbin, "Resetting %s:%s",
output->slot = NULL; GST_DEBUG_PAD_NAME (output->src_pad));
/* Unlink decoder if needed */
if (output->linked && slot && output->decoder_sink) {
gst_pad_unlink (slot->src_pad, output->decoder_sink);
} }
output->linked = FALSE;
if (slot && output->drop_probe_id) {
gst_pad_remove_probe (slot->src_pad, output->drop_probe_id);
output->drop_probe_id = 0;
}
/* Remove/Reset pads */
gst_object_replace ((GstObject **) & output->decoder_sink, NULL); gst_object_replace ((GstObject **) & output->decoder_sink, NULL);
decode_pad_set_target ((GstGhostPad *) output->src_pad, NULL); decode_pad_set_target ((GstGhostPad *) output->src_pad, NULL);
gst_object_replace ((GstObject **) & output->decoder_src, NULL); gst_object_replace ((GstObject **) & output->decoder_src, NULL);
if (output->src_exposed) {
gst_element_remove_pad ((GstElement *) dbin, output->src_pad); /* Remove decoder */
}
if (output->decoder) { if (output->decoder) {
gst_element_set_locked_state (output->decoder, TRUE); gst_element_set_locked_state (output->decoder, TRUE);
gst_element_set_state (output->decoder, GST_STATE_NULL); gst_element_set_state (output->decoder, GST_STATE_NULL);
gst_bin_remove ((GstBin *) dbin, output->decoder); gst_bin_remove ((GstBin *) output->dbin, output->decoder);
output->decoder = NULL;
output->decoder_latency = GST_CLOCK_TIME_NONE;
}
}
/** db_output_stream_free:
* @output: A #DecodebinOutputstream
*
* Releases the @output from the associated slot, removes the associated source
* ghost pad and frees any decoder
*/
static void
db_output_stream_free (DecodebinOutputStream * output)
{
GstDecodebin3 *dbin = output->dbin;
GST_DEBUG_OBJECT (output->src_pad, "Freeing");
db_output_stream_reset (output);
if (output->slot)
mq_slot_set_output (output->slot, NULL);
if (output->src_exposed) {
gst_element_remove_pad ((GstElement *) dbin, output->src_pad);
} }
g_free (output); g_free (output);
} }