ges-launcher: allow using a clip to determine the rendering format

This includes both topology and profile

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/merge_requests/265>
This commit is contained in:
Mathieu Duponchelle 2021-08-10 23:25:06 +02:00
parent ee35cba6e8
commit 148c751bc0
2 changed files with 136 additions and 12 deletions

View file

@ -388,25 +388,93 @@ sort_encoding_profiles (gconstpointer a, gconstpointer b)
return 1; return 1;
} }
static GstEncodingProfile * static GList *
get_smart_profile (GESLauncher * self) _timeline_assets (GESLauncher * self)
{ {
gint n_audio, n_video; GList *tmp, *assets = NULL;
GList *tmp, *assets = NULL, *possible_profiles = NULL;
GstEncodingProfile *res = NULL;
_check_has_audio_video (self, &n_audio, &n_video);
for (tmp = self->priv->timeline->layers; tmp; tmp = tmp->next) { for (tmp = self->priv->timeline->layers; tmp; tmp = tmp->next) {
GList *tclip, *clips = ges_layer_get_clips (tmp->data); GList *tclip, *clips = ges_layer_get_clips (tmp->data);
for (tclip = clips; tclip; tclip = tclip->next) { for (tclip = clips; tclip; tclip = tclip->next) {
if (GES_IS_URI_CLIP (tclip->data)) if (GES_IS_URI_CLIP (tclip->data)) {
assets = assets =
g_list_append (assets, ges_extractable_get_asset (tclip->data)); g_list_append (assets, ges_extractable_get_asset (tclip->data));
} }
}
g_list_free_full (clips, gst_object_unref); g_list_free_full (clips, gst_object_unref);
} }
return assets;
}
static GESAsset *
_asset_for_named_clip (GESLauncher * self, const gchar * name)
{
GList *tmp;
GESAsset *ret = NULL;
for (tmp = self->priv->timeline->layers; tmp; tmp = tmp->next) {
GList *tclip, *clips = ges_layer_get_clips (tmp->data);
for (tclip = clips; tclip; tclip = tclip->next) {
if (GES_IS_URI_CLIP (tclip->data) &&
!g_strcmp0 (name, ges_timeline_element_get_name (tclip->data))) {
ret = ges_extractable_get_asset (tclip->data);
break;
}
}
g_list_free_full (clips, gst_object_unref);
if (ret)
break;
}
return ret;
}
static GstEncodingProfile *
_get_profile_from (GESLauncher * self)
{
GESAsset *asset =
_asset_for_named_clip (self, self->priv->parsed_options.profile_from);
GstDiscovererInfo *info;
GstEncodingProfile *prof;
g_assert (asset);
info = ges_uri_clip_asset_get_info (GES_URI_CLIP_ASSET (asset));
prof = gst_encoding_profile_from_discoverer (info);
return prof;
}
static GstEncodingProfile *
get_smart_profile (GESLauncher * self)
{
gint n_audio, n_video;
GList *tmp, *assets, *possible_profiles = NULL;
GstEncodingProfile *res = NULL;
if (self->priv->parsed_options.profile_from) {
GESAsset *asset =
_asset_for_named_clip (self, self->priv->parsed_options.profile_from);
GstDiscovererInfo *info;
GstEncodingProfile *prof;
g_assert (asset);
info = ges_uri_clip_asset_get_info (GES_URI_CLIP_ASSET (asset));
prof = gst_encoding_profile_from_discoverer (info);
return prof;
}
_check_has_audio_video (self, &n_audio, &n_video);
assets = _timeline_assets (self);
for (tmp = assets; tmp; tmp = tmp->next) { for (tmp = assets; tmp; tmp = tmp->next) {
GESAsset *asset = tmp->data; GESAsset *asset = tmp->data;
GList *audio_streams, *video_streams; GList *audio_streams, *video_streams;
@ -503,7 +571,9 @@ _set_rendering_details (GESLauncher * self)
if (!prof) { if (!prof) {
if (opts->format == NULL) { if (opts->format == NULL) {
if (opts->smartrender) if (opts->profile_from)
prof = _get_profile_from (self);
else if (opts->smartrender)
prof = get_smart_profile (self); prof = get_smart_profile (self);
if (prof) if (prof)
smart_profile = TRUE; smart_profile = TRUE;
@ -591,6 +661,46 @@ _timeline_set_user_options (GESLauncher * self, GESTimeline * timeline,
gboolean has_audio = FALSE, has_video = FALSE; gboolean has_audio = FALSE, has_video = FALSE;
GESLauncherParsedOptions *opts = &self->priv->parsed_options; GESLauncherParsedOptions *opts = &self->priv->parsed_options;
if (self->priv->parsed_options.profile_from) {
GList *tmp, *tracks;
GList *audio_streams, *video_streams;
GESAsset *asset =
_asset_for_named_clip (self, self->priv->parsed_options.profile_from);
GstDiscovererInfo *info;
guint i;
if (!asset) {
ges_printerr
("\nERROR: can't create profile from named clip, no such clip %s\n\n",
self->priv->parsed_options.profile_from);
return FALSE;
}
tracks = ges_timeline_get_tracks (self->priv->timeline);
for (tmp = tracks; tmp; tmp = tmp->next) {
ges_timeline_remove_track (timeline, tmp->data);
}
g_list_free_full (tracks, gst_object_unref);
info = ges_uri_clip_asset_get_info (GES_URI_CLIP_ASSET (asset));
audio_streams = gst_discoverer_info_get_audio_streams (info);
video_streams = gst_discoverer_info_get_video_streams (info);
for (i = 0; i < g_list_length (audio_streams); i++) {
ges_timeline_add_track (timeline, GES_TRACK (ges_audio_track_new ()));
}
for (i = 0; i < g_list_length (video_streams); i++) {
ges_timeline_add_track (timeline, GES_TRACK (ges_video_track_new ()));
}
gst_discoverer_stream_info_list_free (audio_streams);
gst_discoverer_stream_info_list_free (video_streams);
}
retry: retry:
for (tmp = timeline->tracks; tmp; tmp = tmp->next) { for (tmp = timeline->tracks; tmp; tmp = tmp->next) {
@ -600,13 +710,17 @@ retry:
has_audio = TRUE; has_audio = TRUE;
_track_set_mixing (tmp->data, opts); _track_set_mixing (tmp->data, opts);
if (!self->priv->parsed_options.profile_from) {
if (!(GES_TRACK (tmp->data)->type & opts->track_types)) { if (!(GES_TRACK (tmp->data)->type & opts->track_types)) {
ges_timeline_remove_track (timeline, tmp->data); ges_timeline_remove_track (timeline, tmp->data);
goto retry; goto retry;
} }
} }
}
if ((opts->scenario || opts->testfile) && !load_path) { if ((opts->scenario || opts->testfile) && !load_path
&& !self->priv->parsed_options.profile_from) {
if (!has_video && opts->track_types & GES_TRACK_TYPE_VIDEO) { if (!has_video && opts->track_types & GES_TRACK_TYPE_VIDEO) {
trackv = GES_TRACK (ges_video_track_new ()); trackv = GES_TRACK (ges_video_track_new ());
@ -981,6 +1095,9 @@ _create_pipeline (GESLauncher * self, const gchar * serialized_timeline)
self->priv->pipeline = ges_pipeline_new (); self->priv->pipeline = ges_pipeline_new ();
if (opts->outputuri)
ges_pipeline_set_mode (self->priv->pipeline, 0);
if (!_create_timeline (self, serialized_timeline, uri, opts->scenario if (!_create_timeline (self, serialized_timeline, uri, opts->scenario
|| opts->testfile)) { || opts->testfile)) {
GST_ERROR ("Could not create the timeline"); GST_ERROR ("Could not create the timeline");
@ -1117,6 +1234,11 @@ ges_launcher_get_rendering_option_group (GESLauncherParsedOptions * opts)
"See ges-launch-1.0 help profile for more information. " "See ges-launch-1.0 help profile for more information. "
"This will have no effect if no outputuri has been specified.", "This will have no effect if no outputuri has been specified.",
"<profile-name>"}, "<profile-name>"},
{"profile-from", 0, 0, G_OPTION_ARG_STRING, &opts->profile_from,
"Use clip with name <clip-name> to determine the topology and profile "
"of the rendered output. This will have no effect if no outputuri "
"has been specified.",
"<clip-name>"},
{"smart-rendering", 0, 0, G_OPTION_ARG_NONE, &opts->smartrender, {"smart-rendering", 0, 0, G_OPTION_ARG_NONE, &opts->smartrender,
"Avoid reencoding when rendering. This option implies --disable-mixing.", "Avoid reencoding when rendering. This option implies --disable-mixing.",
NULL}, NULL},
@ -1505,6 +1627,7 @@ _finalize (GObject * object)
g_free (opts->outputuri); g_free (opts->outputuri);
g_free (opts->format); g_free (opts->format);
g_free (opts->encoding_profile); g_free (opts->encoding_profile);
g_free (opts->profile_from);
g_free (opts->videosink); g_free (opts->videosink);
g_free (opts->audiosink); g_free (opts->audiosink);
g_free (opts->video_track_caps); g_free (opts->video_track_caps);

View file

@ -38,6 +38,7 @@ typedef struct
gchar *format; gchar *format;
gchar *outputuri; gchar *outputuri;
gchar *encoding_profile; gchar *encoding_profile;
gchar *profile_from;
gchar *videosink; gchar *videosink;
gchar *audiosink; gchar *audiosink;
gboolean list_transitions; gboolean list_transitions;