transcodebin: Implement support for upstream stream selection

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3128>
This commit is contained in:
Thibault Saunier 2022-10-04 19:19:57 -03:00
parent 31acfcd875
commit bf964f896f
2 changed files with 85 additions and 31 deletions

View file

@ -29,8 +29,6 @@
#include <gst/pbutils/missing-plugins.h> #include <gst/pbutils/missing-plugins.h>
/** /**
* GstTranscodeBin!sink_%u: * GstTranscodeBin!sink_%u:
* *
@ -109,6 +107,7 @@ typedef struct
GstElement *video_filter; GstElement *video_filter;
GPtrArray *transcoding_streams; GPtrArray *transcoding_streams;
gboolean upstream_selected;
} GstTranscodeBin; } GstTranscodeBin;
typedef struct typedef struct
@ -127,6 +126,9 @@ G_DEFINE_TYPE (GstTranscodeBin, gst_transcode_bin, GST_TYPE_BIN);
GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (transcodebin, "transcodebin", GST_RANK_NONE, GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (transcodebin, "transcodebin", GST_RANK_NONE,
GST_TYPE_TRANSCODE_BIN, transcodebin_element_init (plugin)); GST_TYPE_TRANSCODE_BIN, transcodebin_element_init (plugin));
static GstPad *
get_encodebin_pad_from_stream (GstTranscodeBin * self, GstStream * stream);
enum enum
{ {
PROP_0, PROP_0,
@ -316,17 +318,52 @@ done:
return res; return res;
} }
static TranscodingStream *
setup_stream (GstTranscodeBin * self, GstStream * stream)
{
TranscodingStream *res = NULL;
GstPad *encodebin_pad = get_encodebin_pad_from_stream (self, stream);
if (encodebin_pad) {
GST_INFO_OBJECT (self,
"Going to transcode stream %s (encodebin pad: %" GST_PTR_FORMAT ")",
gst_stream_get_stream_id (stream), encodebin_pad);
res = transcoding_stream_new (stream, encodebin_pad);
GST_OBJECT_LOCK (self);
g_ptr_array_add (self->transcoding_streams, res);
GST_OBJECT_UNLOCK (self);
}
return res;
}
static void static void
gst_transcode_bin_link_encodebin_pad (GstTranscodeBin * self, GstPad * pad, gst_transcode_bin_link_encodebin_pad (GstTranscodeBin * self, GstPad * pad,
const gchar * stream_id) GstEvent * sstart)
{ {
GstCaps *caps; GstCaps *caps;
GstPadLinkReturn lret; GstPadLinkReturn lret;
TranscodingStream *stream = find_stream (self, stream_id, NULL); const gchar *stream_id;
TranscodingStream *stream;
gst_event_parse_stream_start (sstart, &stream_id);
stream = find_stream (self, stream_id, NULL);
if (!stream) { if (!stream) {
GST_ERROR_OBJECT (self, "%s -> Got not stream, decodebin3 bug?", stream_id); if (self->upstream_selected) {
return; GstStream *tmpstream;
gst_event_parse_stream (sstart, &tmpstream);
stream = setup_stream (self, tmpstream);
}
if (!stream) {
GST_ERROR_OBJECT (self, "Could not find any stream with ID: %s",
stream_id);
return;
}
} }
caps = gst_pad_query_caps (pad, NULL); caps = gst_pad_query_caps (pad, NULL);
@ -371,15 +408,13 @@ static GstPadProbeReturn
wait_stream_start_probe (GstPad * pad, wait_stream_start_probe (GstPad * pad,
GstPadProbeInfo * info, GstTranscodeBin * self) GstPadProbeInfo * info, GstTranscodeBin * self)
{ {
const gchar *stream_id;
if (GST_EVENT_TYPE (info->data) != GST_EVENT_STREAM_START) if (GST_EVENT_TYPE (info->data) != GST_EVENT_STREAM_START)
return GST_PAD_PROBE_OK; return GST_PAD_PROBE_OK;
gst_event_parse_stream_start (info->data, &stream_id); GST_INFO_OBJECT (self,
GST_INFO_OBJECT (self, "Got pad %" GST_PTR_FORMAT " with stream ID: %s", "Got pad %" GST_PTR_FORMAT " with stream:: %" GST_PTR_FORMAT, pad,
pad, stream_id); info->data);
gst_transcode_bin_link_encodebin_pad (self, pad, stream_id); gst_transcode_bin_link_encodebin_pad (self, pad, info->data);
return GST_PAD_PROBE_REMOVE; return GST_PAD_PROBE_REMOVE;
} }
@ -399,7 +434,7 @@ decodebin_pad_added_cb (GstElement * decodebin, GstPad * pad,
gst_event_parse_stream_start (sstart_event, &stream_id); gst_event_parse_stream_start (sstart_event, &stream_id);
GST_INFO_OBJECT (self, "Got pad %" GST_PTR_FORMAT " with stream ID: %s", GST_INFO_OBJECT (self, "Got pad %" GST_PTR_FORMAT " with stream ID: %s",
pad, stream_id); pad, stream_id);
gst_transcode_bin_link_encodebin_pad (self, pad, stream_id); gst_transcode_bin_link_encodebin_pad (self, pad, sstart_event);
return; return;
} }
@ -549,8 +584,7 @@ caps_is_raw (GstCaps * caps, GstStreamType stype)
} }
static GstPad * static GstPad *
get_encodebin_pad_from_stream (GstTranscodeBin * self, get_encodebin_pad_from_stream (GstTranscodeBin * self, GstStream * stream)
GstEncodingProfile * profile, GstStream * stream)
{ {
GstCaps *caps = gst_stream_get_caps (stream); GstCaps *caps = gst_stream_get_caps (stream);
GstPad *sinkpad = get_encodebin_pad_for_caps (self, caps); GstPad *sinkpad = get_encodebin_pad_for_caps (self, caps);
@ -597,22 +631,9 @@ select_stream_cb (GstElement * decodebin,
for (i = 0; i < gst_stream_collection_get_size (collection); i++) { for (i = 0; i < gst_stream_collection_get_size (collection); i++) {
GstStream *tmpstream = gst_stream_collection_get_stream (collection, i); GstStream *tmpstream = gst_stream_collection_get_stream (collection, i);
GstPad *encodebin_pad =
get_encodebin_pad_from_stream (self, self->profile, tmpstream);
if (encodebin_pad) { if (setup_stream (self, tmpstream) && stream == tmpstream)
if (stream == tmpstream) transcode_stream = TRUE;
transcode_stream = TRUE;
GST_INFO_OBJECT (self,
"Going to transcode stream %s (encodebin pad: %" GST_PTR_FORMAT,
gst_stream_get_stream_id (tmpstream), encodebin_pad);
GST_OBJECT_LOCK (self);
g_ptr_array_add (self->transcoding_streams,
transcoding_stream_new (tmpstream, encodebin_pad));
GST_OBJECT_UNLOCK (self);
}
} }
GST_OBJECT_LOCK (self); GST_OBJECT_LOCK (self);
@ -737,6 +758,38 @@ remove_all_children (GstTranscodeBin * self)
} }
} }
static gboolean
sink_event_function (GstPad * sinkpad, GstTranscodeBin * self, GstEvent * event)
{
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_STREAM_START:
{
GstQuery *q = gst_query_new_selectable ();
/* Query whether upstream can handle stream selection or not */
if (gst_pad_peer_query (sinkpad, q)) {
GST_FIXME_OBJECT (self, "We force `transcodebin` to upstream selection"
" mode if *any* of the inputs is. This means things might break if"
" there's a mix");
gst_query_parse_selectable (q, &self->upstream_selected);
GST_DEBUG_OBJECT (sinkpad, "Upstream is selectable : %d",
self->upstream_selected);
} else {
self->upstream_selected = FALSE;
GST_DEBUG_OBJECT (sinkpad, "Upstream does not handle SELECTABLE query");
}
gst_query_unref (q);
break;
}
default:
break;
}
return gst_pad_event_default (sinkpad, GST_OBJECT (self), event);
}
static GstStateChangeReturn static GstStateChangeReturn
gst_transcode_bin_change_state (GstElement * element, GstStateChange transition) gst_transcode_bin_change_state (GstElement * element, GstStateChange transition)
{ {
@ -851,6 +904,7 @@ gst_transcode_bin_request_pad (GstElement * element, GstPadTemplate * temp,
} }
gpad = gst_ghost_pad_new_from_template (name, decodebin_pad, temp); gpad = gst_ghost_pad_new_from_template (name, decodebin_pad, temp);
gst_pad_set_event_function (gpad, (GstPadEventFunction) sink_event_function);
gst_element_add_pad (element, GST_PAD (gpad)); gst_element_add_pad (element, GST_PAD (gpad));
gst_object_unref (decodebin_pad); gst_object_unref (decodebin_pad);

View file

@ -29,7 +29,7 @@
#include <gst/pbutils/missing-plugins.h> #include <gst/pbutils/missing-plugins.h>
GST_DEBUG_CATEGORY_STATIC (gst_transcodebin_debug); GST_DEBUG_CATEGORY (gst_transcodebin_debug);
#define GST_CAT_DEFAULT gst_transcodebin_debug #define GST_CAT_DEFAULT gst_transcodebin_debug
void void