From 0be8bc9d981ae390992fab4cb1755fd399eb3d17 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 10 Feb 2020 18:05:38 -0300 Subject: [PATCH] ges: Avoid adding unnecessary converters for nested timelines Basically we know that if we are using mixing, compositor will be able to do video conversion and scaling for us, so avoid adding those usless elements. This optimizes a lot caps negotiation for deeply nested timelines. --- ges/ges-audio-source.c | 6 +++++- ges/ges-internal.h | 6 +++--- ges/ges-source.c | 13 +++++------- ges/ges-video-source.c | 40 +++++++++++++++++++++---------------- ges/ges-video-source.h | 1 + ges/ges-video-test-source.c | 10 ++++++++-- ges/ges-video-uri-source.c | 30 +++++++++++++++++++++++++--- 7 files changed, 72 insertions(+), 34 deletions(-) diff --git a/ges/ges-audio-source.c b/ges/ges-audio-source.c index 03ee44c54d..df52cffad0 100644 --- a/ges/ges-audio-source.c +++ b/ges/ges-audio-source.c @@ -125,6 +125,7 @@ ges_audio_source_create_element (GESTrackElement * trksrc) GstElement *volume, *vbin; GstElement *topbin; GstElement *sub_element; + GPtrArray *elements; GESAudioSourceClass *source_class = GES_AUDIO_SOURCE_GET_CLASS (trksrc); const gchar *props[] = { "volume", "mute", NULL }; GESAudioSource *self = GES_AUDIO_SOURCE (trksrc); @@ -139,7 +140,10 @@ ges_audio_source_create_element (GESTrackElement * trksrc) gst_parse_bin_from_description ("audioconvert ! audioresample ! volume name=v ! capsfilter name=audio-track-caps-filter", TRUE, NULL); - topbin = ges_source_create_topbin ("audiosrcbin", sub_element, vbin, NULL); + elements = g_ptr_array_new (); + g_ptr_array_add (elements, vbin); + topbin = ges_source_create_topbin ("audiosrcbin", sub_element, elements); + g_ptr_array_free (elements, TRUE); volume = gst_bin_get_by_name (GST_BIN (vbin), "v"); self->priv->capsfilter = gst_bin_get_by_name (GST_BIN (vbin), "audio-track-caps-filter"); diff --git a/ges/ges-internal.h b/ges/ges-internal.h index a620aa969f..306372debb 100644 --- a/ges/ges-internal.h +++ b/ges/ges-internal.h @@ -403,9 +403,9 @@ G_GNUC_INTERNAL void ges_track_element_copy_bindings (GESTrackElement *element, GESTrackElement *new_element, guint64 position); -G_GNUC_INTERNAL GstElement *ges_source_create_topbin (const gchar * bin_name, GstElement * sub_element, ...); -G_GNUC_INTERNAL void ges_track_set_caps (GESTrack *track, - const GstCaps *caps); +G_GNUC_INTERNAL GstElement* ges_source_create_topbin(const gchar* bin_name, GstElement* sub_element, GPtrArray* elements); +G_GNUC_INTERNAL void ges_track_set_caps(GESTrack* track, + const GstCaps* caps); G_GNUC_INTERNAL GstElement * ges_track_get_composition (GESTrack *track); diff --git a/ges/ges-source.c b/ges/ges-source.c index f960349e45..3c5eee8085 100644 --- a/ges/ges-source.c +++ b/ges/ges-source.c @@ -80,21 +80,21 @@ _ghost_pad_added_cb (GstElement * element, GstPad * srcpad, GstElement * bin) } GstElement * -ges_source_create_topbin (const gchar * bin_name, GstElement * sub_element, ...) +ges_source_create_topbin (const gchar * bin_name, GstElement * sub_element, + GPtrArray * elements) { - va_list argp; - GstElement *element; GstElement *prev = NULL; GstElement *first = NULL; GstElement *bin; GstPad *sub_srcpad; + gint i; - va_start (argp, sub_element); bin = gst_bin_new (bin_name); gst_bin_add (GST_BIN (bin), sub_element); - while ((element = va_arg (argp, GstElement *)) != NULL) { + for (i = 0; i < elements->len; i++) { + element = elements->pdata[i]; gst_bin_add (GST_BIN (bin), element); if (prev) { if (!gst_element_link_pads_full (prev, "src", element, "sink", @@ -102,15 +102,12 @@ ges_source_create_topbin (const gchar * bin_name, GstElement * sub_element, ...) g_error ("Could not link %s and %s", GST_OBJECT_NAME (prev), GST_OBJECT_NAME (element)); } - } prev = element; if (first == NULL) first = element; } - va_end (argp); - sub_srcpad = gst_element_get_static_pad (sub_element, "src"); if (prev != NULL) { diff --git a/ges/ges-video-source.c b/ges/ges-video-source.c index 94f7c6090f..63ae963ef5 100644 --- a/ges/ges-video-source.c +++ b/ges/ges-video-source.c @@ -96,15 +96,15 @@ ges_video_source_create_element (GESTrackElement * trksrc) { GstElement *topbin; GstElement *sub_element; - GstElement *queue = gst_element_factory_make ("queue", NULL); GESVideoSourceClass *source_class = GES_VIDEO_SOURCE_GET_CLASS (trksrc); GESVideoSource *self; - GstElement *positioner, *videoflip, *videoscale, *videorate, *capsfilter, - *videoconvert, *deinterlace; + GstElement *positioner, *videoflip, *capsfilter, *deinterlace; const gchar *positioner_props[] = { "alpha", "posx", "posy", "width", "height", NULL }; const gchar *deinterlace_props[] = { "mode", "fields", "tff", NULL }; const gchar *videoflip_props[] = { "video-direction", NULL }; + gboolean needs_converters = TRUE; + GPtrArray *elements; if (!source_class->create_source) return NULL; @@ -112,26 +112,36 @@ ges_video_source_create_element (GESTrackElement * trksrc) sub_element = source_class->create_source (trksrc); self = (GESVideoSource *) trksrc; + if (source_class->ABI.abi.needs_converters) + needs_converters = source_class->ABI.abi.needs_converters (self); + + elements = g_ptr_array_new (); + g_ptr_array_add (elements, gst_element_factory_make ("queue", NULL)); /* That positioner will add metadata to buffers according to its properties, acting like a proxy for our smart-mixer dynamic pads. */ positioner = gst_element_factory_make ("framepositioner", "frame_tagger"); g_object_set (positioner, "zorder", G_MAXUINT - GES_TIMELINE_ELEMENT_PRIORITY (self), NULL); + g_ptr_array_add (elements, positioner); /* If there's image-orientation tag, make sure the image is correctly oriented * before we scale it. */ videoflip = gst_element_factory_make ("videoflip", "track-element-videoflip"); g_object_set (videoflip, "video-direction", GST_VIDEO_ORIENTATION_AUTO, NULL); + g_ptr_array_add (elements, videoflip); - videoscale = - gst_element_factory_make ("videoscale", "track-element-videoscale"); - videoconvert = - gst_element_factory_make ("videoconvert", "track-element-videoconvert"); - videorate = gst_element_factory_make ("videorate", "track-element-videorate"); - deinterlace = gst_element_factory_make ("deinterlace", "deinterlace"); + if (needs_converters) { + g_ptr_array_add (elements, gst_element_factory_make ("videoscale", + "track-element-videoscale")); + g_ptr_array_add (elements, gst_element_factory_make ("videoconvert", + "track-element-videoconvert")); + } + g_ptr_array_add (elements, gst_element_factory_make ("videorate", + "track-element-videorate")); capsfilter = gst_element_factory_make ("capsfilter", "track-element-capsfilter"); + g_ptr_array_add (elements, capsfilter); ges_frame_positioner_set_source_and_filter (GST_FRAME_POSITIONNER (positioner), trksrc, capsfilter); @@ -141,24 +151,20 @@ ges_video_source_create_element (GESTrackElement * trksrc) ges_track_element_add_children_props (trksrc, videoflip, NULL, NULL, videoflip_props); + deinterlace = gst_element_factory_make ("deinterlace", "deinterlace"); if (deinterlace == NULL) { post_missing_element_message (sub_element, "deinterlace"); GST_ELEMENT_WARNING (sub_element, CORE, MISSING_PLUGIN, ("Missing element '%s' - check your GStreamer installation.", "deinterlace"), ("deinterlacing won't work")); - topbin = - ges_source_create_topbin ("videosrcbin", sub_element, queue, - videoconvert, positioner, videoflip, videoscale, videorate, capsfilter, - NULL); } else { + g_ptr_array_add (elements, deinterlace); ges_track_element_add_children_props (trksrc, deinterlace, NULL, NULL, deinterlace_props); - topbin = - ges_source_create_topbin ("videosrcbin", sub_element, queue, - videoconvert, deinterlace, positioner, videoflip, videoscale, videorate, - capsfilter, NULL); } + topbin = ges_source_create_topbin ("videosrcbin", sub_element, elements); + g_ptr_array_free (elements, TRUE); self->priv->positioner = GST_FRAME_POSITIONNER (positioner); self->priv->positioner->scale_in_compositor = diff --git a/ges/ges-video-source.h b/ges/ges-video-source.h index fd84552542..1554cbd1c1 100644 --- a/ges/ges-video-source.h +++ b/ges/ges-video-source.h @@ -84,6 +84,7 @@ struct _GESVideoSourceClass { gpointer _ges_reserved[GES_PADDING]; struct { gboolean disable_scale_in_compositor; + gboolean (*needs_converters)(GESVideoSource *self); } abi; } ABI; }; diff --git a/ges/ges-video-test-source.c b/ges/ges-video-test-source.c index 22e04d864a..a175dd59d9 100644 --- a/ges/ges-video-test-source.c +++ b/ges/ges-video-test-source.c @@ -64,8 +64,9 @@ ges_video_test_source_create_source (GESTrackElement * self) { GstCaps *caps; gint pattern; - GstElement *testsrc, *capsfilter; + GstElement *testsrc, *capsfilter, *res; const gchar *props[] = { "pattern", NULL }; + GPtrArray *elements; testsrc = gst_element_factory_make ("videotestsrc", NULL); capsfilter = gst_element_factory_make ("capsfilter", NULL); @@ -73,13 +74,18 @@ ges_video_test_source_create_source (GESTrackElement * self) g_object_set (testsrc, "pattern", pattern, NULL); + elements = g_ptr_array_new (); + g_ptr_array_add (elements, capsfilter); caps = gst_caps_new_empty_simple ("video/x-raw"); g_object_set (capsfilter, "caps", caps, NULL); gst_caps_unref (caps); ges_track_element_add_children_props (self, testsrc, NULL, NULL, props); - return ges_source_create_topbin ("videotestsrc", testsrc, capsfilter, NULL); + res = ges_source_create_topbin ("videotestsrc", testsrc, elements); + g_ptr_array_free (elements, TRUE); + + return res; } /** diff --git a/ges/ges-video-uri-source.c b/ges/ges-video-uri-source.c index 1939046b81..468b94b94a 100644 --- a/ges/ges-video-uri-source.c +++ b/ges/ges-video-uri-source.c @@ -91,6 +91,28 @@ ges_video_uri_source_create_source (GESTrackElement * trksrc) return decodebin; } +static gboolean +ges_video_uri_source_needs_converters (GESVideoSource * source) +{ + GESTrack *track = ges_track_element_get_track (GES_TRACK_ELEMENT (source)); + + if (!track || ges_track_get_mixing (track)) { + GESAsset *asset = ges_asset_request (GES_TYPE_URI_CLIP, + GES_VIDEO_URI_SOURCE (source)->uri, NULL); + gboolean is_nested = FALSE; + + g_assert (asset); + + g_object_get (asset, "is-nested-timeline", &is_nested, NULL); + gst_object_unref (asset); + + return !is_nested; + } + + + return FALSE; +} + /* Extractable interface implementation */ static gchar * @@ -100,14 +122,14 @@ ges_extractable_check_id (GType type, const gchar * id, GError ** error) } static void -extractable_set_asset (GESExtractable * self, GESAsset * asset) +extractable_set_asset (GESExtractable * extractable, GESAsset * asset) { /* FIXME That should go into #GESTrackElement, but * some work is needed to make sure it works properly */ - if (ges_track_element_get_track_type (GES_TRACK_ELEMENT (self)) == + if (ges_track_element_get_track_type (GES_TRACK_ELEMENT (extractable)) == GES_TRACK_TYPE_UNKNOWN) { - ges_track_element_set_track_type (GES_TRACK_ELEMENT (self), + ges_track_element_set_track_type (GES_TRACK_ELEMENT (extractable), ges_track_element_asset_get_track_type (GES_TRACK_ELEMENT_ASSET (asset))); } @@ -194,6 +216,8 @@ ges_video_uri_source_class_init (GESVideoUriSourceClass * klass) NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); source_class->create_source = ges_video_uri_source_create_source; + source_class->ABI.abi.needs_converters = + ges_video_uri_source_needs_converters; } static void