ges: Use a `ges:` uri to define timeline from description
authorThibault Saunier <tsaunier@igalia.com>
Fri, 15 Jan 2021 18:03:20 +0000 (15:03 -0300)
committerThibault Saunier <tsaunier@igalia.com>
Wed, 10 Feb 2021 19:14:47 +0000 (16:14 -0300)
This way the command line formatter actually uses an URI and not
an ugly hack where were passing a random string instead of an URI.
This also allows the `gessrc` element to handle timelines described
in its URI meaning that you can now use, for example:

   gst-play-1.0 "ges:+test-clip blue d=4.0

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

ges/ges-command-line-formatter.c
plugins/ges/gessrc.c
tools/ges-launcher.c
tools/ges-launcher.h
tools/utils.c
tools/utils.h

index 475cf5f..777ec9e 100644 (file)
@@ -660,34 +660,86 @@ _parse_structures (const gchar * string)
   return parser;
 }
 
+/* @uri: (transfer full): */
+static gchar *
+get_timeline_desc_from_uri (GstUri * uri)
+{
+  gchar *res, *path;
+
+  if (!uri)
+    return NULL;
+
+  /* Working around parser requiring a space to begin with */
+  path = gst_uri_get_path (uri);
+  res = g_strconcat (" ", path, NULL);
+  g_free (path);
+
+  gst_uri_unref (uri);
+
+  return res;
+}
+
 static gboolean
 _can_load (GESFormatter * dummy_formatter, const gchar * string,
     GError ** error)
 {
   gboolean res = FALSE;
+  GstUri *uri;
+  const gchar *scheme;
+  gchar *timeline_desc = NULL;
   GESStructureParser *parser;
 
-  if (string == NULL)
+  if (string == NULL) {
+    GST_ERROR ("No URI!");
+    return FALSE;
+  }
+
+  uri = gst_uri_from_string (string);
+  if (!uri) {
+    GST_INFO_OBJECT (dummy_formatter, "Wrong uri: %s", string);
     return FALSE;
+  }
 
-  parser = _parse_structures (string);
+  scheme = gst_uri_get_scheme (uri);
+  if (!g_strcmp0 (scheme, "ges:")) {
+    GST_INFO_OBJECT (dummy_formatter, "Wrong scheme: %s", string);
+    gst_uri_unref (uri);
 
+    return FALSE;
+  }
+
+  timeline_desc = get_timeline_desc_from_uri (uri);
+  parser = _parse_structures (timeline_desc);
   if (parser->structures)
     res = TRUE;
 
   gst_object_unref (parser);
+  g_free (timeline_desc);
 
   return res;
 }
 
 static gboolean
+_set_project_loaded (GESFormatter * self)
+{
+  ges_project_set_loaded (self->project, self, NULL);
+  gst_object_unref (self);
+
+  return FALSE;
+}
+
+static gboolean
 _load (GESFormatter * self, GESTimeline * timeline, const gchar * string,
     GError ** error)
 {
   guint i;
   GList *tmp;
   GError *err;
-  GESStructureParser *parser = _parse_structures (string);
+  gchar *timeline_desc =
+      get_timeline_desc_from_uri (gst_uri_from_string (string));
+  GESStructureParser *parser = _parse_structures (timeline_desc);
+
+  g_free (timeline_desc);
 
   err = ges_structure_parser_get_error (parser);
 
@@ -719,6 +771,8 @@ _load (GESFormatter * self, GESTimeline * timeline, const gchar * string,
 
   gst_object_unref (parser);
 
+  ges_idle_add ((GSourceFunc) _set_project_loaded, g_object_ref (self), NULL);
+
   return TRUE;
 
 fail:
index e726c38..103efe9 100644 (file)
@@ -87,10 +87,31 @@ ges_src_uri_get_uri (GstURIHandler * handler)
 }
 
 static gboolean
-ges_src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+ges_src_uri_set_uri (GstURIHandler * handler, const gchar * uristr,
     GError ** error)
 {
-  return TRUE;
+  gboolean res = FALSE;
+  GstUri *uri = gst_uri_from_string (uristr);
+  GESProject *project = NULL;
+  GESTimeline *timeline = NULL;
+
+  if (!gst_uri_get_path (uri)) {
+    GST_INFO_OBJECT (handler, "User need to specify the timeline");
+    res = TRUE;
+    goto done;
+  }
+
+  project = ges_project_new (uristr);
+  timeline = (GESTimeline *) ges_asset_extract (GES_ASSET (project), NULL);
+
+  if (timeline)
+    res = ges_base_bin_set_timeline (GES_BASE_BIN (handler), timeline);
+
+done:
+  gst_uri_unref (uri);
+  gst_clear_object (&project);
+
+  return res;
 }
 
 static void
index be33bd0..72dda86 100644 (file)
@@ -716,7 +716,6 @@ static gboolean
 _create_timeline (GESLauncher * self, const gchar * serialized_timeline,
     const gchar * proj_uri, gboolean validate)
 {
-  GESLauncherParsedOptions *opts = &self->priv->parsed_options;
   GESProject *project;
 
   GError *error = NULL;
@@ -724,37 +723,7 @@ _create_timeline (GESLauncher * self, const gchar * serialized_timeline,
   if (proj_uri != NULL) {
     project = ges_project_new (proj_uri);
   } else if (!validate) {
-    GString *timeline_str = g_string_new (serialized_timeline);
-
-    if (!strstr (serialized_timeline, "+track")) {
-      GString *track_def;
-
-      if (opts->track_types & GES_TRACK_TYPE_VIDEO) {
-        track_def = g_string_new (" +track video ");
-
-        if (opts->video_track_caps)
-          g_string_append_printf (track_def, " restrictions=[%s] ",
-              opts->video_track_caps);
-
-        g_string_prepend (timeline_str, track_def->str);
-        g_string_free (track_def, TRUE);
-      }
-
-      if (opts->track_types & GES_TRACK_TYPE_AUDIO) {
-        track_def = g_string_new (" +track audio ");
-
-        if (opts->audio_track_caps)
-          g_string_append_printf (track_def, " restrictions=[%s] ",
-              opts->audio_track_caps);
-
-        g_string_prepend (timeline_str, track_def->str);
-        g_string_free (track_def, TRUE);
-      }
-    }
-
-    GST_INFO ("Launching timeline: `%s`", timeline_str->str);
-    project = ges_project_new (timeline_str->str);
-    g_string_free (timeline_str, TRUE);
+    project = ges_project_new (serialized_timeline);
   } else {
     project = ges_project_new (NULL);
   }
@@ -1366,7 +1335,7 @@ _local_command_line (GApplication * application, gchar ** arguments[],
 
   g_option_context_free (ctx);
 
-  opts->sanitized_timeline = sanitize_timeline_description (*arguments);
+  opts->sanitized_timeline = sanitize_timeline_description (*arguments, opts);
 
   if (!g_application_register (application, NULL, &error)) {
     *exit_status = 1;
index 4021b14..108ca84 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <ges/ges.h>
 
+#include "utils.h"
+
 G_BEGIN_DECLS
 
 #define GES_TYPE_LAUNCHER ges_launcher_get_type()
@@ -28,35 +30,6 @@ G_BEGIN_DECLS
 typedef struct _GESLauncherPrivate GESLauncherPrivate;
 G_DECLARE_FINAL_TYPE(GESLauncher, ges_launcher, GES, LAUNCHER, GApplication);
 
-typedef struct
-{
-  gboolean mute;
-  gboolean disable_mixing;
-  gchar *save_path;
-  gchar *save_only_path;
-  gchar *load_path;
-  GESTrackType track_types;
-  gboolean needs_set_state;
-  gboolean smartrender;
-  gchar *scenario;
-  gchar *testfile;
-  gchar *format;
-  gchar *outputuri;
-  gchar *encoding_profile;
-  gchar *videosink;
-  gchar *audiosink;
-  gboolean list_transitions;
-  gboolean inspect_action_type;
-  gchar *sanitized_timeline;
-  gchar *video_track_caps;
-  gchar *audio_track_caps;
-  gboolean embed_nesteds;
-  gboolean disable_validate;
-
-  gboolean ignore_eos;
-  gboolean interactive;
-} GESLauncherParsedOptions;
-
 struct _GESLauncher {
   GApplication parent;
 
index 78015cd..2815ad2 100644 (file)
@@ -89,10 +89,12 @@ _sanitize_argument (gchar * arg, const gchar * prev_arg)
 }
 
 gchar *
-sanitize_timeline_description (gchar ** args)
+sanitize_timeline_description (gchar ** args, GESLauncherParsedOptions * opts)
 {
   gint i;
   gchar *prev_arg = NULL;
+  GString *track_def;
+  GString *timeline_str;
 
   gchar *string = g_strdup (" ");
 
@@ -108,7 +110,41 @@ sanitize_timeline_description (gchar ** args)
     prev_arg = args[i];
   }
 
-  return string;
+  if (strstr (string, "+track")) {
+    gchar *res = g_strconcat ("ges:", string, NULL);
+    g_free (string);
+
+    return res;
+  }
+
+  timeline_str = g_string_new (string);
+  g_free (string);
+
+  if (opts->track_types & GES_TRACK_TYPE_VIDEO) {
+    track_def = g_string_new (" +track video ");
+
+    if (opts->video_track_caps)
+      g_string_append_printf (track_def, " restrictions=[%s] ",
+          opts->video_track_caps);
+
+    g_string_prepend (timeline_str, track_def->str);
+    g_string_free (track_def, TRUE);
+  }
+
+  if (opts->track_types & GES_TRACK_TYPE_AUDIO) {
+    track_def = g_string_new (" +track audio ");
+
+    if (opts->audio_track_caps)
+      g_string_append_printf (track_def, " restrictions=[%s] ",
+          opts->audio_track_caps);
+
+    g_string_prepend (timeline_str, track_def->str);
+    g_string_free (track_def, TRUE);
+  }
+
+  g_string_prepend (timeline_str, "ges:");
+
+  return g_string_free (timeline_str, FALSE);
 }
 
 gboolean
index 63e2101..afd5ab2 100644 (file)
 #include <gst/pbutils/pbutils.h>
 #include <gst/pbutils/encoding-profile.h>
 
-gchar * sanitize_timeline_description (gchar **args);
+#pragma once
+
+typedef struct
+{
+  gboolean mute;
+  gboolean disable_mixing;
+  gchar *save_path;
+  gchar *save_only_path;
+  gchar *load_path;
+  GESTrackType track_types;
+  gboolean needs_set_state;
+  gboolean smartrender;
+  gchar *scenario;
+  gchar *testfile;
+  gchar *format;
+  gchar *outputuri;
+  gchar *encoding_profile;
+  gchar *videosink;
+  gchar *audiosink;
+  gboolean list_transitions;
+  gboolean inspect_action_type;
+  gchar *sanitized_timeline;
+  gchar *video_track_caps;
+  gchar *audio_track_caps;
+  gboolean embed_nesteds;
+  gboolean disable_validate;
+
+  gboolean ignore_eos;
+  gboolean interactive;
+} GESLauncherParsedOptions;
+
+gchar * sanitize_timeline_description (gchar **args, GESLauncherParsedOptions *opts);
 gboolean get_flags_from_string (GType type, const gchar * str_flags, guint *val);
 gchar * ensure_uri (const gchar * location);
 GstEncodingProfile * parse_encoding_profile (const gchar * format);