uri-source: Respect stream-id even on streams muxed in raw
authorThibault Saunier <tsaunier@igalia.com>
Mon, 14 Dec 2020 01:54:37 +0000 (22:54 -0300)
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Sat, 23 Jan 2021 04:27:07 +0000 (04:27 +0000)
The issue is that we rely on `decodebin::autoplug-select` to `SKIP`
unwanted pads, that signal was first provided to select factories during
autoplugin, not totally thought to avoid exposing pads. For streams
muxed directly in raw, decodebin has nothing to plug after the demuxer
and the pad is exposed right away, meaning that we do not have any
chance to avoid that pad to be exposed. This patch takes that limitation
into account and checks the stream ID of the pads exposed by decodebin
before exposing them itself, so we end up using the right pad even if
more are uselessly exposed by decodebin.

Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/126

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/merge_requests/222>

ges/ges-audio-uri-source.c
ges/ges-source.c
ges/ges-source.h
ges/ges-uri-source.c
ges/ges-uri-source.h
ges/ges-video-uri-source.c

index bc96a3b..ce3af09 100644 (file)
@@ -136,7 +136,8 @@ ges_audio_uri_source_class_init (GESAudioUriSourceClass * klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GESTimelineElementClass *element_class = GES_TIMELINE_ELEMENT_CLASS (klass);
-  GESAudioSourceClass *source_class = GES_AUDIO_SOURCE_CLASS (klass);
+  GESSourceClass *src_class = GES_SOURCE_CLASS (klass);
+  GESAudioSourceClass *audio_src_class = GES_AUDIO_SOURCE_CLASS (klass);
 
   object_class->get_property = ges_audio_uri_source_get_property;
   object_class->set_property = ges_audio_uri_source_set_property;
@@ -153,7 +154,8 @@ ges_audio_uri_source_class_init (GESAudioUriSourceClass * klass)
 
   element_class->get_natural_framerate = _get_natural_framerate;
 
-  source_class->create_source = ges_audio_uri_source_create_source;
+  src_class->select_pad = ges_uri_source_select_pad;
+  audio_src_class->create_source = ges_audio_uri_source_create_source;
 }
 
 static void
index 5a3b85f..7386860 100644 (file)
@@ -82,8 +82,15 @@ _set_ghost_pad_target (GESSource * self, GstPad * srcpad, GstElement * element)
 {
   GstPadLinkReturn link_return;
   GESSourcePrivate *priv = self->priv;
+  GESSourceClass *source_klass = GES_SOURCE_GET_CLASS (self);
   gboolean use_converter = ! !priv->first_converter;
 
+  if (source_klass->select_pad && !source_klass->select_pad (self, srcpad)) {
+    GST_INFO_OBJECT (self, "Ignoring pad %" GST_PTR_FORMAT, srcpad);
+    return;
+  }
+
+
   if (use_converter && priv->is_rendering_smartly) {
     GstPad *pad = gst_element_get_static_pad (priv->first_converter, "sink");
     use_converter = gst_pad_can_link (srcpad, pad);
index a243d99..022297e 100644 (file)
@@ -55,9 +55,21 @@ struct _GESSourceClass {
   /*< private >*/
   GESTrackElementClass parent_class;
 
-  /*< private >*/
+  /**
+   * GESSourceClass::select_pad:
+   * @source: The @source for which to check if @pad should be used or not
+   * @pad: The pad to check
+   *
+   * Check whether @pad should be exposed/used.
+   *
+   * Returns: %TRUE if @pad should be used %FALSE otherwise.
+   *
+   * Since: 1.20
+   */
+  gboolean (*select_pad)(GESSource *source, GstPad *pad);
+
   /* Padding for API extension */
-  gpointer _ges_reserved[GES_PADDING];
+  gpointer _ges_reserved[GES_PADDING - 1];
 };
 
 G_END_DECLS
index d828eb7..1775db4 100644 (file)
@@ -71,13 +71,17 @@ autoplug_select_cb (GstElement * bin, GstPad * pad, GstCaps * caps,
           (ges_extractable_get_asset (GES_EXTRACTABLE (self->element)))));
   gboolean wanted = !g_strcmp0 (stream_id, wanted_id);
 
-
   if (!ges_source_get_rendering_smartly (GES_SOURCE (self->element))) {
-    if (!wanted && are_raw_caps (caps)) {
-      GST_DEBUG_OBJECT (self->element, "Totally skipping %s", stream_id);
+    if (!are_raw_caps (caps))
+      goto done;
+
+    if (!wanted) {
+      GST_INFO_OBJECT (self->element, "Not matching stream id: %s -> SKIPPING",
+          stream_id);
       res = GST_AUTOPLUG_SELECT_SKIP;
+    } else {
+      GST_INFO_OBJECT (self->element, "Using stream %s", stream_id);
     }
-    GST_LOG_OBJECT (self->element, "Not being smart here");
     goto done;
   }
 
@@ -183,3 +187,37 @@ ges_uri_source_init (GESTrackElement * element, GESUriSource * self)
   g_signal_connect (element, "notify::track",
       G_CALLBACK (ges_uri_source_track_set_cb), self);
 }
+
+gboolean
+ges_uri_source_select_pad (GESSource * self, GstPad * pad)
+{
+  gboolean res = TRUE;
+  gboolean is_nested_timeline;
+  GESUriSourceAsset *asset =
+      GES_URI_SOURCE_ASSET (ges_extractable_get_asset (GES_EXTRACTABLE (self)));
+  const GESUriClipAsset *clip_asset =
+      ges_uri_source_asset_get_filesource_asset (asset);
+  const gchar *wanted_stream_id = ges_asset_get_id (GES_ASSET (asset));
+  gchar *stream_id;
+
+  if (clip_asset) {
+    g_object_get (G_OBJECT (clip_asset), "is-nested-timeline",
+        &is_nested_timeline, NULL);
+
+    if (is_nested_timeline) {
+      GST_DEBUG_OBJECT (self, "Nested timeline track selection is handled"
+          " by the timeline SELECT_STREAM events handling.");
+
+      return TRUE;
+    }
+  }
+
+  stream_id = gst_pad_get_stream_id (pad);
+  res = !g_strcmp0 (stream_id, wanted_stream_id);
+
+  GST_INFO_OBJECT (self, "%s pad with stream id: %s as %s wanted",
+      res ? "Using" : "Ignoring", stream_id, wanted_stream_id);
+  g_free (stream_id);
+
+  return res;
+}
index 7a8fba2..86b35ad 100644 (file)
@@ -35,7 +35,8 @@ struct _GESUriSource
   GESTrackElement *element;
 };
 
-G_GNUC_INTERNAL GstElement * ges_uri_source_create_source (GESUriSource *self);
+G_GNUC_INTERNAL gboolean      ges_uri_source_select_pad   (GESSource *self, GstPad *pad);
+G_GNUC_INTERNAL GstElement *ges_uri_source_create_source  (GESUriSource *self);
 G_GNUC_INTERNAL void         ges_uri_source_init          (GESTrackElement *element, GESUriSource *self);
 
 G_END_DECLS
index f7426b1..4e8de05 100644 (file)
@@ -297,7 +297,8 @@ static void
 ges_video_uri_source_class_init (GESVideoUriSourceClass * klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
-  GESVideoSourceClass *source_class = GES_VIDEO_SOURCE_CLASS (klass);
+  GESSourceClass *src_class = GES_SOURCE_CLASS (klass);
+  GESVideoSourceClass *video_src_class = GES_VIDEO_SOURCE_CLASS (klass);
 
   object_class->get_property = ges_video_uri_source_get_property;
   object_class->set_property = ges_video_uri_source_set_property;
@@ -312,12 +313,14 @@ ges_video_uri_source_class_init (GESVideoUriSourceClass * klass)
       g_param_spec_string ("uri", "URI", "uri of the resource",
           NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
-  source_class->create_source = ges_video_uri_source_create_source;
-  source_class->ABI.abi.needs_converters =
+  src_class->select_pad = ges_uri_source_select_pad;
+
+  video_src_class->create_source = ges_video_uri_source_create_source;
+  video_src_class->ABI.abi.needs_converters =
       ges_video_uri_source_needs_converters;
-  source_class->ABI.abi.get_natural_size =
+  video_src_class->ABI.abi.get_natural_size =
       ges_video_uri_source_get_natural_size;
-  source_class->ABI.abi.create_filters = ges_video_uri_source_create_filters;
+  video_src_class->ABI.abi.create_filters = ges_video_uri_source_create_filters;
 }
 
 static void