summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThibault Saunier <tsaunier@igalia.com>2021-01-12 15:55:52 -0300
committerThibault Saunier <tsaunier@igalia.com>2021-02-09 18:11:05 -0300
commit6c5daf8c810f177282a7af0e5c9ef00133c31deb (patch)
treec76e5a6683291eed2ffd31aa11363361c4f93f88
parente3a30744e8f684f3aa864512ddd14d68d1f42436 (diff)
command-line-formatter: Add track management to timeline description
Instead of having it all handled by the tool, this way we can set the restriction before clips are added to the timeline, leading to better behavior in term of video images placement in the scene. Without that we would have the clips positioned before setting the restriction caps which leads to weird behavior for the end users. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/merge_requests/227>
-rw-r--r--ges/ges-command-line-formatter.c29
-rw-r--r--ges/ges-structure-parser.c29
-rw-r--r--ges/ges-structured-interface.c63
-rw-r--r--ges/ges-structured-interface.h5
-rw-r--r--ges/parse.l3
-rw-r--r--tools/ges-launcher.c34
6 files changed, 143 insertions, 20 deletions
diff --git a/ges/ges-command-line-formatter.c b/ges/ges-command-line-formatter.c
index d315bb69..b97eab0b 100644
--- a/ges/ges-command-line-formatter.c
+++ b/ges/ges-command-line-formatter.c
@@ -50,6 +50,9 @@ _ges_command_line_formatter_add_test_clip (GESTimeline * timeline,
static gboolean
_ges_command_line_formatter_add_title_clip (GESTimeline * timeline,
GstStructure * structure, GError ** error);
+static gboolean
+_ges_command_line_formatter_add_track (GESTimeline * timeline,
+ GstStructure * structure, GError ** error);
typedef struct
{
@@ -232,6 +235,16 @@ static GESCommandLineOption options[] = {
{NULL, 0, 0, NULL, FALSE},
},
},
+ {"track", 't', (ActionFromStructureFunc) _ges_command_line_formatter_add_track,
+ "<track type>", "Adds a track to the timeline.", NULL,
+ {
+ {
+ "restrictions", "r", 0, NULL,
+ "The restriction caps to set on the track."
+ },
+ {NULL, 0, 0, NULL, FALSE},
+ },
+ },
{
"set-", 0, NULL,
"<property name> <value>", "Set a property on the last added element."
@@ -259,6 +272,7 @@ typedef enum
EFFECT,
TEST_CLIP,
TITLE,
+ TRACK,
SET,
} GESCommandLineOptionType;
@@ -442,6 +456,16 @@ _ges_command_line_formatter_add_title_clip (GESTimeline * timeline,
}
static gboolean
+_ges_command_line_formatter_add_track (GESTimeline * timeline,
+ GstStructure * structure, GError ** error)
+{
+ if (!_cleanup_fields (options[TRACK].properties, structure, error))
+ return FALSE;
+
+ return _ges_add_track_from_struct (timeline, structure, error);
+}
+
+static gboolean
_ges_command_line_formatter_add_effect (GESTimeline * timeline,
GstStructure * structure, GError ** error)
{
@@ -603,11 +627,6 @@ _load (GESFormatter * self, GESTimeline * timeline, const gchar * string,
}
g_object_set (timeline, "auto-transition", TRUE, NULL);
- if (!(ges_timeline_add_track (timeline, GES_TRACK (ges_video_track_new ()))))
- goto fail;
-
- if (!(ges_timeline_add_track (timeline, GES_TRACK (ges_audio_track_new ()))))
- goto fail;
/* Here we've finished initializing our timeline, we're
* ready to start using it... by solely working with the layer !*/
diff --git a/ges/ges-structure-parser.c b/ges/ges-structure-parser.c
index 25831be1..327b2a2c 100644
--- a/ges/ges-structure-parser.c
+++ b/ges/ges-structure-parser.c
@@ -99,25 +99,28 @@ ges_structure_parser_parse_whitespace (GESStructureParser * self)
static void
_finish_structure (GESStructureParser * self)
{
- if (self->current_string) {
- GstStructure *structure =
- gst_structure_new_from_string (self->current_string);
+ GstStructure *structure;
- if (structure == NULL) {
- GST_ERROR ("Could not parse %s", self->current_string);
+ if (!self->current_string)
+ return;
- self->wrong_strings = g_list_append (self->wrong_strings,
- g_strdup (self->current_string));
+ structure = gst_structure_new_from_string (self->current_string);
- return;
- }
+ if (structure == NULL) {
+ GST_ERROR ("Could not parse %s", self->current_string);
- self->structures = g_list_append (self->structures, structure);
- g_free (self->current_string);
- self->current_string = NULL;
+ self->wrong_strings = g_list_append (self->wrong_strings,
+ g_strdup (self->current_string));
+
+ return;
}
+
+ self->structures = g_list_append (self->structures, structure);
+ g_free (self->current_string);
+ self->current_string = NULL;
}
+
void
ges_structure_parser_end_of_file (GESStructureParser * self)
{
@@ -146,6 +149,8 @@ ges_structure_parser_parse_symbol (GESStructureParser * self,
ges_structure_parser_parse_string (self, "transition, type=(string)", TRUE);
else if (!g_ascii_strncasecmp (symbol, "title", 5))
ges_structure_parser_parse_string (self, "title, text=(string)", TRUE);
+ else if (!g_ascii_strncasecmp (symbol, "track", 5))
+ ges_structure_parser_parse_string (self, "track, type=(string)", TRUE);
}
void
diff --git a/ges/ges-structured-interface.c b/ges/ges-structured-interface.c
index b96d1a90..ff44aa71 100644
--- a/ges/ges-structured-interface.c
+++ b/ges/ges-structured-interface.c
@@ -570,6 +570,69 @@ beach:
}
gboolean
+_ges_add_track_from_struct (GESTimeline * timeline,
+ GstStructure * structure, GError ** error)
+{
+ const gchar *ttype;
+ GESTrack *track;
+ GstCaps *caps;
+
+ const gchar *valid_fields[] = { "type", "restrictions", NULL };
+
+ FieldsError fields_error = { valid_fields, NULL };
+
+ if (!_check_fields (structure, fields_error, error))
+ return FALSE;
+
+ ttype = gst_structure_get_string (structure, "type");
+ if (!g_strcmp0 (ttype, "video")) {
+ track = GES_TRACK (ges_video_track_new ());
+ } else if (!g_strcmp0 (ttype, "audio")) {
+ track = GES_TRACK (ges_audio_track_new ());
+ } else {
+ g_set_error (error, GES_ERROR, 0, "Unhandled track type: `%s`", ttype);
+
+ return FALSE;
+ }
+
+ if (gst_structure_has_field (structure, "restrictions")) {
+ GstStructure *restriction_struct;
+ gchar *restriction_str;
+
+ if (gst_structure_get (structure, "restrictions", GST_TYPE_STRUCTURE,
+ &restriction_struct, NULL)) {
+ caps = gst_caps_new_full (restriction_struct, NULL);
+ } else if (gst_structure_get (structure, "restrictions", G_TYPE_STRING,
+ &restriction_str, NULL)) {
+ caps = gst_caps_from_string (restriction_str);
+
+ if (!caps) {
+ g_set_error (error, GES_ERROR, 0, "Invalid restrictions caps: %s",
+ restriction_str);
+
+ g_free (restriction_str);
+ return FALSE;
+ }
+ g_free (restriction_str);
+ } else if (!gst_structure_get (structure, "restrictions", GST_TYPE_CAPS,
+ &caps, NULL)) {
+ gchar *tmp = gst_structure_to_string (structure);
+
+ g_set_error (error, GES_ERROR, 0, "Can't use restrictions caps from %s",
+ tmp);
+
+ g_object_unref (track);
+ return FALSE;
+ }
+
+ ges_track_set_restriction_caps (track, caps);
+ gst_caps_unref (caps);
+ }
+
+ return ges_timeline_add_track (timeline, track);
+}
+
+gboolean
_ges_container_add_child_from_struct (GESTimeline * timeline,
GstStructure * structure, GError ** error)
{
diff --git a/ges/ges-structured-interface.h b/ges/ges-structured-interface.h
index 3a27aabb..13efc167 100644
--- a/ges/ges-structured-interface.h
+++ b/ges/ges-structured-interface.h
@@ -37,6 +37,11 @@ _ges_add_clip_from_struct (GESTimeline * timeline,
GError ** error);
G_GNUC_INTERNAL gboolean
+_ges_add_track_from_struct (GESTimeline * timeline,
+ GstStructure * structure,
+ GError ** error);
+
+G_GNUC_INTERNAL gboolean
_ges_container_add_child_from_struct (GESTimeline * timeline,
GstStructure * structure,
GError ** error);
diff --git a/ges/parse.l b/ges/parse.l
index d4428204..da8743f5 100644
--- a/ges/parse.l
+++ b/ges/parse.l
@@ -16,6 +16,7 @@ TEST_CLIP [ ]+\+test-clip[ ]+
TRANSITION [ ]+\+transition[ ]+
EFFECT [ ]+\+effect[ ]+
TITLE [ ]+\+title[ ]+
+TRACK [ ]+\+track[ ]+
SETTER [ ]+set-[^ ]+[ ]+
@@ -35,7 +36,7 @@ VALUE {STRING}|([abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0
ges_structure_parser_parse_string (yyextra, yytext, FALSE);
}
-{CLIP}|{TRANSITION}|{EFFECT}|{TEST_CLIP}|{TITLE} {
+{TRACK}|{CLIP}|{TRANSITION}|{EFFECT}|{TEST_CLIP}|{TITLE} {
ges_structure_parser_parse_symbol (yyextra, yytext);
}
diff --git a/tools/ges-launcher.c b/tools/ges-launcher.c
index f0a6de22..be33bd0e 100644
--- a/tools/ges-launcher.c
+++ b/tools/ges-launcher.c
@@ -716,6 +716,7 @@ 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;
@@ -723,8 +724,37 @@ _create_timeline (GESLauncher * self, const gchar * serialized_timeline,
if (proj_uri != NULL) {
project = ges_project_new (proj_uri);
} else if (!validate) {
- GST_INFO ("serialized timeline is %s", serialized_timeline);
- project = ges_project_new (serialized_timeline);
+ 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);
} else {
project = ges_project_new (NULL);
}