mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-29 21:21:12 +00:00
ges: Factor out a GESCommandLineFormatter class
This formatter will allow any user to deserialize a timeline using the new ges-launch command line interface
This commit is contained in:
parent
ed0839dd82
commit
28a1e97aa2
16 changed files with 537 additions and 301 deletions
|
@ -6,7 +6,7 @@ lib_LTLIBRARIES = libges-@GST_API_VERSION@.la
|
||||||
|
|
||||||
EXTRA_libges_@GST_API_VERSION@_la_SOURCES = gesmarshal.list
|
EXTRA_libges_@GST_API_VERSION@_la_SOURCES = gesmarshal.list
|
||||||
|
|
||||||
CLEANFILES = $(BUILT_SOURCES) $(built_header_make) $(built_source_make) *.gcno *.gcda *.gcov *.gcov.out
|
CLEANFILES = $(BUILT_SOURCES) $(built_header_make) $(built_source_make) *.gcno *.gcda *.gcov *.gcov.out lex.priv_ges_parse_yy.c
|
||||||
|
|
||||||
libges_@GST_API_VERSION@_la_SOURCES = \
|
libges_@GST_API_VERSION@_la_SOURCES = \
|
||||||
$(built_source_make) \
|
$(built_source_make) \
|
||||||
|
@ -66,6 +66,7 @@ libges_@GST_API_VERSION@_la_SOURCES = \
|
||||||
ges-project.c \
|
ges-project.c \
|
||||||
ges-base-xml-formatter.c \
|
ges-base-xml-formatter.c \
|
||||||
ges-xml-formatter.c \
|
ges-xml-formatter.c \
|
||||||
|
ges-command-line-formatter.c \
|
||||||
ges-auto-transition.c \
|
ges-auto-transition.c \
|
||||||
ges-timeline-element.c \
|
ges-timeline-element.c \
|
||||||
ges-container.c \
|
ges-container.c \
|
||||||
|
@ -76,6 +77,7 @@ libges_@GST_API_VERSION@_la_SOURCES = \
|
||||||
ges-group.c \
|
ges-group.c \
|
||||||
ges-validate.c \
|
ges-validate.c \
|
||||||
ges-structured-interface.c \
|
ges-structured-interface.c \
|
||||||
|
ges-structure-parser.c \
|
||||||
gstframepositionner.c
|
gstframepositionner.c
|
||||||
|
|
||||||
libges_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/ges/
|
libges_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/ges/
|
||||||
|
@ -133,6 +135,7 @@ libges_@GST_API_VERSION@include_HEADERS = \
|
||||||
ges-project.h \
|
ges-project.h \
|
||||||
ges-base-xml-formatter.h \
|
ges-base-xml-formatter.h \
|
||||||
ges-xml-formatter.h \
|
ges-xml-formatter.h \
|
||||||
|
ges-command-line-formatter.h \
|
||||||
ges-timeline-element.h \
|
ges-timeline-element.h \
|
||||||
ges-container.h \
|
ges-container.h \
|
||||||
ges-effect-asset.h \
|
ges-effect-asset.h \
|
||||||
|
@ -155,6 +158,7 @@ noinst_HEADERS = \
|
||||||
ges-internal.h \
|
ges-internal.h \
|
||||||
ges-auto-transition.h \
|
ges-auto-transition.h \
|
||||||
ges-structured-interface.h \
|
ges-structured-interface.h \
|
||||||
|
ges-structure-parser.h \
|
||||||
gstframepositionner.h
|
gstframepositionner.h
|
||||||
|
|
||||||
libges_@GST_API_VERSION@_la_CFLAGS = -I$(top_srcdir) $(GST_PBUTILS_CFLAGS) \
|
libges_@GST_API_VERSION@_la_CFLAGS = -I$(top_srcdir) $(GST_PBUTILS_CFLAGS) \
|
||||||
|
@ -166,6 +170,8 @@ libges_@GST_API_VERSION@_la_LIBADD = $(GST_PBUTILS_LIBS) \
|
||||||
libges_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \
|
libges_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \
|
||||||
$(GST_LT_LDFLAGS) $(GIO_CFLAGS) $(GST_VALIDATE_CFLAGS)
|
$(GST_LT_LDFLAGS) $(GIO_CFLAGS) $(GST_VALIDATE_CFLAGS)
|
||||||
|
|
||||||
|
nodist_libges_@GST_API_VERSION@_la_SOURCES = lex.priv_ges_parse_yy.c parse_lex.h
|
||||||
|
|
||||||
DISTCLEANFILE = $(CLEANFILES)
|
DISTCLEANFILE = $(CLEANFILES)
|
||||||
|
|
||||||
#files built on make all/check/instal
|
#files built on make all/check/instal
|
||||||
|
@ -267,3 +273,6 @@ Android.mk: Makefile.am $(BUILT_SOURCES)
|
||||||
$(nodist_libges_@GST_API_VERSION@include_HEADERS) \
|
$(nodist_libges_@GST_API_VERSION@include_HEADERS) \
|
||||||
-:PASSTHROUGH LOCAL_ARM_MODE:=arm \
|
-:PASSTHROUGH LOCAL_ARM_MODE:=arm \
|
||||||
> $@
|
> $@
|
||||||
|
|
||||||
|
lex.priv_ges_parse_yy.c parse_lex.h: parse.l
|
||||||
|
$(AM_V_GEN)$(FLEX_PATH) --header-file=parse_lex.h -Ppriv_ges_parse_yy $^
|
||||||
|
|
346
ges/ges-command-line-formatter.c
Normal file
346
ges/ges-command-line-formatter.c
Normal file
|
@ -0,0 +1,346 @@
|
||||||
|
/* GStreamer Editing Services
|
||||||
|
*
|
||||||
|
* Copyright (C) <2015> Thibault Saunier <tsaunier@gnome.org>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ges-command-line-formatter.h"
|
||||||
|
|
||||||
|
#include "ges/ges-structured-interface.h"
|
||||||
|
#include "ges-structure-parser.h"
|
||||||
|
#include "ges-internal.h"
|
||||||
|
#include "parse_lex.h"
|
||||||
|
|
||||||
|
struct _GESCommandLineFormatterPrivate
|
||||||
|
{
|
||||||
|
gpointer dummy;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (GESCommandLineFormatter, ges_command_line_formatter,
|
||||||
|
GES_TYPE_FORMATTER);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const gchar *long_name;
|
||||||
|
const gchar *short_name;
|
||||||
|
GType type;
|
||||||
|
const gchar *new_name;
|
||||||
|
} Properties;
|
||||||
|
|
||||||
|
static gint /* -1: not present, 0: failure, 1: OK */
|
||||||
|
_convert_to_clocktime (GstStructure * structure, const gchar * name,
|
||||||
|
GstClockTime default_value)
|
||||||
|
{
|
||||||
|
gint res = 1;
|
||||||
|
gdouble val;
|
||||||
|
GValue d_val = { 0 };
|
||||||
|
GstClockTime timestamp;
|
||||||
|
const GValue *gvalue = gst_structure_get_value (structure, name);
|
||||||
|
|
||||||
|
if (gvalue == NULL) {
|
||||||
|
timestamp = default_value;
|
||||||
|
|
||||||
|
res = -1;
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (G_VALUE_TYPE (gvalue) == GST_TYPE_CLOCK_TIME)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
g_value_init (&d_val, G_TYPE_DOUBLE);
|
||||||
|
if (!g_value_transform (gvalue, &d_val)) {
|
||||||
|
GST_ERROR ("Could not get timestamp for %s", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
val = g_value_get_double ((const GValue *) &d_val);
|
||||||
|
|
||||||
|
if (val == -1.0)
|
||||||
|
timestamp = GST_CLOCK_TIME_NONE;
|
||||||
|
else
|
||||||
|
timestamp = val * GST_SECOND;
|
||||||
|
|
||||||
|
done:
|
||||||
|
gst_structure_set (structure, name, G_TYPE_UINT64, timestamp, NULL);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_cleanup_fields (const Properties * field_names, GstStructure * structure,
|
||||||
|
GError ** error)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0; field_names[i].long_name; i++) {
|
||||||
|
gboolean exists = FALSE;
|
||||||
|
|
||||||
|
/* Move shortly named fields to longname variante */
|
||||||
|
if (gst_structure_has_field (structure, field_names[i].short_name)) {
|
||||||
|
exists = TRUE;
|
||||||
|
|
||||||
|
if (gst_structure_has_field (structure, field_names[i].long_name)) {
|
||||||
|
*error = g_error_new (GES_ERROR, 0, "Using short and long name"
|
||||||
|
" at the same time for property: %s, which one should I use?!",
|
||||||
|
field_names[i].long_name);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
} else {
|
||||||
|
const GValue *val =
|
||||||
|
gst_structure_get_value (structure, field_names[i].short_name);
|
||||||
|
|
||||||
|
gst_structure_set_value (structure, field_names[i].long_name, val);
|
||||||
|
gst_structure_remove_field (structure, field_names[i].short_name);
|
||||||
|
}
|
||||||
|
} else if (gst_structure_has_field (structure, field_names[i].long_name)) {
|
||||||
|
exists = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
|
if (field_names[i].type == GST_TYPE_CLOCK_TIME) {
|
||||||
|
if (_convert_to_clocktime (structure, field_names[i].long_name, 0) == 0) {
|
||||||
|
*error = g_error_new (GES_ERROR, 0, "Could not convert"
|
||||||
|
" %s to GstClockTime", field_names[i].long_name);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field_names[i].new_name
|
||||||
|
&& gst_structure_has_field (structure, field_names[i].long_name)) {
|
||||||
|
const GValue *val =
|
||||||
|
gst_structure_get_value (structure, field_names[i].long_name);
|
||||||
|
|
||||||
|
gst_structure_set_value (structure, field_names[i].new_name, val);
|
||||||
|
gst_structure_remove_field (structure, field_names[i].long_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_ges_command_line_formatter_add_clip (GESTimeline * timeline,
|
||||||
|
GstStructure * structure, GError ** error)
|
||||||
|
{
|
||||||
|
const Properties field_names[] = {
|
||||||
|
{"uri", "n", 0, "asset-id"},
|
||||||
|
{"name", "n", 0, NULL},
|
||||||
|
{"start", "s", GST_TYPE_CLOCK_TIME, NULL},
|
||||||
|
{"duration", "d", GST_TYPE_CLOCK_TIME, NULL},
|
||||||
|
{"inpoint", "i", GST_TYPE_CLOCK_TIME, NULL},
|
||||||
|
{"track-types", "tt", 0, NULL},
|
||||||
|
{"layer", "l", 0, NULL},
|
||||||
|
{NULL, 0, 0, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!_cleanup_fields (field_names, structure, error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
gst_structure_set (structure, "type", G_TYPE_STRING, "GESUriClip", NULL);
|
||||||
|
|
||||||
|
return _ges_add_clip_from_struct (timeline, structure, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_ges_command_line_formatter_add_effect (GESTimeline * timeline,
|
||||||
|
GstStructure * structure, GError ** error)
|
||||||
|
{
|
||||||
|
const Properties field_names[] = {
|
||||||
|
{"element-name", "e", 0, NULL},
|
||||||
|
{"bin-description", "d", 0, "asset-id"},
|
||||||
|
{"name", "n", 0, "child-name"},
|
||||||
|
{NULL, NULL, 0, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!_cleanup_fields (field_names, structure, error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
gst_structure_set (structure, "child-type", G_TYPE_STRING, "GESEffect", NULL);
|
||||||
|
|
||||||
|
return _ges_container_add_child_from_struct (timeline, structure, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GOptionEntry timeline_parsing_options[] = {
|
||||||
|
{"clip", 'c', 0.0, G_OPTION_ARG_CALLBACK,
|
||||||
|
&_ges_command_line_formatter_add_clip,
|
||||||
|
"",
|
||||||
|
"Adds a clip in the timeline\n"
|
||||||
|
" * start - s : The start position of the element inside the layer.\n"
|
||||||
|
" * duration - d: The duration of the clip.\n"
|
||||||
|
" * inpoint - i : The inpoint of the clip.\n"
|
||||||
|
" * track-types - tt: The type of the tracks where the clip should be used:\n"
|
||||||
|
" Examples:\n"
|
||||||
|
" * audio / a\n"
|
||||||
|
" * video / v\n"
|
||||||
|
" * audio+video / a+v\n"
|
||||||
|
" Will default to all the media types in the clip that match the global track-types\n"},
|
||||||
|
{"effect", 'e', 0.0, G_OPTION_ARG_CALLBACK,
|
||||||
|
&_ges_command_line_formatter_add_effect, "",
|
||||||
|
"Adds an effect as specified by 'bin-description'\n"
|
||||||
|
" * bin-description - d: The description of the effect bin with a gst-launch-style pipeline description.\n"
|
||||||
|
" * element-name - e : The name of the element to apply the effect on.\n"},
|
||||||
|
};
|
||||||
|
|
||||||
|
GOptionGroup *
|
||||||
|
_ges_command_line_formatter_get_option_group (void)
|
||||||
|
{
|
||||||
|
GOptionGroup *group;
|
||||||
|
|
||||||
|
group = g_option_group_new ("GESCommandLineFormatter",
|
||||||
|
"GStreamer Editing Services command line options to describe a timeline",
|
||||||
|
"Show GStreamer Options", NULL, NULL);
|
||||||
|
g_option_group_add_entries (group, timeline_parsing_options);
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_set_child_property (GESTimeline * timeline, GstStructure * structure,
|
||||||
|
GError ** error)
|
||||||
|
{
|
||||||
|
return _ges_set_child_property_from_struct (timeline, structure, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EXEC(func,structure,error) G_STMT_START { \
|
||||||
|
gboolean res = ((ActionFromStructureFunc)func)(timeline, structure, error); \
|
||||||
|
if (!res) {\
|
||||||
|
GST_ERROR ("Could not execute: %" GST_PTR_FORMAT ", error: %s", structure, (*error)->message); \
|
||||||
|
goto fail; \
|
||||||
|
} \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
|
||||||
|
static GESStructureParser *
|
||||||
|
_parse_structures (const gchar * string)
|
||||||
|
{
|
||||||
|
yyscan_t scanner;
|
||||||
|
GESStructureParser *parser = ges_structure_parser_new ();
|
||||||
|
|
||||||
|
priv_ges_parse_yylex_init_extra (parser, &scanner);
|
||||||
|
priv_ges_parse_yy_scan_string (string, scanner);
|
||||||
|
priv_ges_parse_yylex (scanner);
|
||||||
|
priv_ges_parse_yylex_destroy (scanner);
|
||||||
|
|
||||||
|
ges_structure_parser_end_of_file (parser);
|
||||||
|
return parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_can_load (GESFormatter * dummy_formatter, const gchar * string,
|
||||||
|
GError ** error)
|
||||||
|
{
|
||||||
|
gboolean res = FALSE;
|
||||||
|
GESStructureParser *parser;
|
||||||
|
|
||||||
|
if (string == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
parser = _parse_structures (string);
|
||||||
|
|
||||||
|
if (parser->structures)
|
||||||
|
res = TRUE;
|
||||||
|
|
||||||
|
gst_object_unref (parser);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_load (GESFormatter * self, GESTimeline * timeline, const gchar * string,
|
||||||
|
GError ** error)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
GList *tmp;
|
||||||
|
GESStructureParser *parser = _parse_structures (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 !*/
|
||||||
|
for (tmp = parser->structures; tmp; tmp = tmp->next) {
|
||||||
|
const gchar *name = gst_structure_get_name (tmp->data);
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (g_str_has_prefix (name, "set-")) {
|
||||||
|
EXEC (_set_child_property, tmp->data, &error);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (timeline_parsing_options); i++) {
|
||||||
|
if (gst_structure_has_name (tmp->data,
|
||||||
|
timeline_parsing_options[i].long_name)
|
||||||
|
|| (strlen (name) == 1 &&
|
||||||
|
*name == timeline_parsing_options[i].short_name)) {
|
||||||
|
EXEC (((ActionFromStructureFunc) timeline_parsing_options[i].arg_data),
|
||||||
|
tmp->data, &error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_object_unref (parser);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
gst_object_unref (parser);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ges_command_line_formatter_init (GESCommandLineFormatter *
|
||||||
|
ges_command_line_formatter)
|
||||||
|
{
|
||||||
|
ges_command_line_formatter->priv =
|
||||||
|
G_TYPE_INSTANCE_GET_PRIVATE (ges_command_line_formatter,
|
||||||
|
GES_TYPE_COMMAND_LINE_FORMATTER, GESCommandLineFormatterPrivate);
|
||||||
|
|
||||||
|
/* TODO: Add initialization code here */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ges_command_line_formatter_finalize (GObject * object)
|
||||||
|
{
|
||||||
|
/* TODO: Add deinitalization code here */
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (ges_command_line_formatter_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ges_command_line_formatter_class_init (GESCommandLineFormatterClass * klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
GESFormatterClass *formatter_klass = GES_FORMATTER_CLASS (klass);
|
||||||
|
|
||||||
|
g_type_class_add_private (klass, sizeof (GESCommandLineFormatterPrivate));
|
||||||
|
|
||||||
|
object_class->finalize = ges_command_line_formatter_finalize;
|
||||||
|
|
||||||
|
formatter_klass->can_load_uri = _can_load;
|
||||||
|
formatter_klass->load_from_uri = _load;
|
||||||
|
formatter_klass->rank = GST_RANK_MARGINAL;
|
||||||
|
}
|
58
ges/ges-command-line-formatter.h
Normal file
58
ges/ges-command-line-formatter.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/* GStreamer Editing Services
|
||||||
|
*
|
||||||
|
* Copyright (C) <2015> Thibault Saunier <tsaunier@gnome.org>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GES_COMMAND_LINE_FORMATTER_H_
|
||||||
|
#define _GES_COMMAND_LINE_FORMATTER_H_
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include "ges-formatter.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define GES_TYPE_COMMAND_LINE_FORMATTER (ges_command_line_formatter_get_type ())
|
||||||
|
#define GES_COMMAND_LINE_FORMATTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GES_TYPE_COMMAND_LINE_FORMATTER, GESCommandLineFormatter))
|
||||||
|
#define GES_COMMAND_LINE_FORMATTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GES_TYPE_COMMAND_LINE_FORMATTER, GESCommandLineFormatterClass))
|
||||||
|
#define GES_IS_COMMAND_LINE_FORMATTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GES_TYPE_COMMAND_LINE_FORMATTER))
|
||||||
|
#define GES_IS_COMMAND_LINE_FORMATTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GES_TYPE_COMMAND_LINE_FORMATTER))
|
||||||
|
#define GES_COMMAND_LINE_FORMATTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GES_TYPE_COMMAND_LINE_FORMATTER, GESCommandLineFormatterClass))
|
||||||
|
|
||||||
|
typedef struct _GESCommandLineFormatterClass GESCommandLineFormatterClass;
|
||||||
|
typedef struct _GESCommandLineFormatter GESCommandLineFormatter;
|
||||||
|
typedef struct _GESCommandLineFormatterPrivate GESCommandLineFormatterPrivate;
|
||||||
|
|
||||||
|
|
||||||
|
struct _GESCommandLineFormatterClass
|
||||||
|
{
|
||||||
|
GESFormatterClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GESCommandLineFormatter
|
||||||
|
{
|
||||||
|
GESFormatter parent_instance;
|
||||||
|
|
||||||
|
GESCommandLineFormatterPrivate *priv;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType ges_command_line_formatter_get_type (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* _GES_COMMAND_LINE_FORMATTER_H_ */
|
||||||
|
|
|
@ -513,7 +513,7 @@ _sort_formatters (GESAsset * asset, GESAsset * asset1)
|
||||||
}
|
}
|
||||||
|
|
||||||
GESAsset *
|
GESAsset *
|
||||||
_find_formatter_asset_for_uri (const gchar * uri)
|
_find_formatter_asset_for_id (const gchar * id)
|
||||||
{
|
{
|
||||||
GESFormatterClass *class = NULL;
|
GESFormatterClass *class = NULL;
|
||||||
GList *formatter_assets, *tmp;
|
GList *formatter_assets, *tmp;
|
||||||
|
@ -528,7 +528,7 @@ _find_formatter_asset_for_uri (const gchar * uri)
|
||||||
class = g_type_class_ref (ges_asset_get_extractable_type (asset));
|
class = g_type_class_ref (ges_asset_get_extractable_type (asset));
|
||||||
dummy_instance =
|
dummy_instance =
|
||||||
g_object_new (ges_asset_get_extractable_type (asset), NULL);
|
g_object_new (ges_asset_get_extractable_type (asset), NULL);
|
||||||
if (class->can_load_uri (dummy_instance, uri, NULL)) {
|
if (class->can_load_uri (dummy_instance, id, NULL)) {
|
||||||
g_type_class_unref (class);
|
g_type_class_unref (class);
|
||||||
asset = gst_object_ref (asset);
|
asset = gst_object_ref (asset);
|
||||||
gst_object_unref (dummy_instance);
|
gst_object_unref (dummy_instance);
|
||||||
|
|
|
@ -116,6 +116,9 @@ typedef gboolean (*GESFormatterSaveToURIMethod) (GESFormatter *formatter,
|
||||||
struct _GESFormatterClass {
|
struct _GESFormatterClass {
|
||||||
GInitiallyUnownedClass parent_class;
|
GInitiallyUnownedClass parent_class;
|
||||||
|
|
||||||
|
/* TODO 2.0: Rename the loading method to can_load and load.
|
||||||
|
* Technically we just pass data to load, it should not necessarily
|
||||||
|
* be a URI */
|
||||||
GESFormatterCanLoadURIMethod can_load_uri;
|
GESFormatterCanLoadURIMethod can_load_uri;
|
||||||
GESFormatterLoadFromURIMethod load_from_uri;
|
GESFormatterLoadFromURIMethod load_from_uri;
|
||||||
GESFormatterSaveToURIMethod save_to_uri;
|
GESFormatterSaveToURIMethod save_to_uri;
|
||||||
|
|
|
@ -163,7 +163,7 @@ ges_formatter_set_project (GESFormatter *formatter,
|
||||||
G_GNUC_INTERNAL GESProject *
|
G_GNUC_INTERNAL GESProject *
|
||||||
ges_formatter_get_project (GESFormatter *formatter);
|
ges_formatter_get_project (GESFormatter *formatter);
|
||||||
G_GNUC_INTERNAL GESAsset *
|
G_GNUC_INTERNAL GESAsset *
|
||||||
_find_formatter_asset_for_uri (const gchar *uri);
|
_find_formatter_asset_for_id (const gchar *id);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -289,6 +289,13 @@ ges_base_xml_formatter_set_timeline_properties(GESBaseXmlFormatter * self,
|
||||||
const gchar *properties,
|
const gchar *properties,
|
||||||
const gchar *metadatas);
|
const gchar *metadatas);
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************
|
||||||
|
* GESCommandLineFormatter *
|
||||||
|
****************************************************/
|
||||||
|
GOptionGroup *
|
||||||
|
_ges_command_line_formatter_get_option_group (void);
|
||||||
|
|
||||||
/****************************************************
|
/****************************************************
|
||||||
* GESContainer *
|
* GESContainer *
|
||||||
****************************************************/
|
****************************************************/
|
||||||
|
|
|
@ -151,8 +151,8 @@ ges_project_set_uri (GESProject * project, const gchar * uri)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uri == NULL || !gst_uri_is_valid (uri)) {
|
if (uri == NULL) {
|
||||||
GST_LOG_OBJECT (project, "Invalid URI: %s", uri);
|
GST_LOG_OBJECT (project, "Uri should not be NULL");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ _load_project (GESProject * project, GESTimeline * timeline, GError ** error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->formatter_asset == NULL)
|
if (priv->formatter_asset == NULL)
|
||||||
priv->formatter_asset = _find_formatter_asset_for_uri (priv->uri);
|
priv->formatter_asset = _find_formatter_asset_for_id (priv->uri);
|
||||||
|
|
||||||
if (priv->formatter_asset == NULL)
|
if (priv->formatter_asset == NULL)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
|
@ -87,7 +87,7 @@ gboolean ges_project_save (GESProject * project,
|
||||||
gboolean ges_project_load (GESProject * project,
|
gboolean ges_project_load (GESProject * project,
|
||||||
GESTimeline * timeline,
|
GESTimeline * timeline,
|
||||||
GError **error);
|
GError **error);
|
||||||
GESProject * ges_project_new (const gchar *uri);
|
GESProject * ges_project_new (const gchar *id);
|
||||||
gchar * ges_project_get_uri (GESProject *project);
|
gchar * ges_project_get_uri (GESProject *project);
|
||||||
GESAsset * ges_project_get_asset (GESProject * project,
|
GESAsset * ges_project_get_asset (GESProject * project,
|
||||||
const gchar *id,
|
const gchar *id,
|
||||||
|
|
|
@ -27,7 +27,8 @@ typedef gboolean (*ActionFromStructureFunc) (GESTimeline * timeline,
|
||||||
GstStructure * structure,
|
GstStructure * structure,
|
||||||
GError ** error);
|
GError ** error);
|
||||||
|
|
||||||
gboolean _ges_add_remove_keyframe_from_struct (GESTimeline * timeline,
|
G_GNUC_INTERNAL gboolean
|
||||||
|
_ges_add_remove_keyframe_from_struct (GESTimeline * timeline,
|
||||||
GstStructure * structure,
|
GstStructure * structure,
|
||||||
GError ** error);
|
GError ** error);
|
||||||
G_GNUC_INTERNAL gboolean
|
G_GNUC_INTERNAL gboolean
|
||||||
|
@ -35,20 +36,22 @@ _ges_add_clip_from_struct (GESTimeline * timeline,
|
||||||
GstStructure * structure,
|
GstStructure * structure,
|
||||||
GError ** error);
|
GError ** error);
|
||||||
|
|
||||||
gboolean
|
G_GNUC_INTERNAL gboolean
|
||||||
_ges_container_add_child_from_struct (GESTimeline * timeline,
|
_ges_container_add_child_from_struct (GESTimeline * timeline,
|
||||||
GstStructure * structure,
|
GstStructure * structure,
|
||||||
GError ** error);
|
GError ** error);
|
||||||
|
|
||||||
gboolean
|
G_GNUC_INTERNAL gboolean
|
||||||
_ges_set_child_property_from_struct (GESTimeline * timeline,
|
_ges_set_child_property_from_struct (GESTimeline * timeline,
|
||||||
GstStructure * structure,
|
GstStructure * structure,
|
||||||
GError ** error);
|
GError ** error);
|
||||||
|
|
||||||
GESAsset * _ges_get_asset_from_timeline (GESTimeline * timeline,
|
G_GNUC_INTERNAL GESAsset *
|
||||||
|
_ges_get_asset_from_timeline (GESTimeline * timeline,
|
||||||
GType type,
|
GType type,
|
||||||
const gchar * id);
|
const gchar * id);
|
||||||
GESLayer * _ges_get_layer_by_priority (GESTimeline * timeline,
|
G_GNUC_INTERNAL GESLayer *
|
||||||
|
_ges_get_layer_by_priority (GESTimeline * timeline,
|
||||||
gint priority);
|
gint priority);
|
||||||
|
|
||||||
#endif /* __GES_STRUCTURED_INTERFACE__*/
|
#endif /* __GES_STRUCTURED_INTERFACE__*/
|
||||||
|
|
|
@ -93,6 +93,7 @@ ges_init (void)
|
||||||
|
|
||||||
/* register formatter types with the system */
|
/* register formatter types with the system */
|
||||||
GES_TYPE_PITIVI_FORMATTER;
|
GES_TYPE_PITIVI_FORMATTER;
|
||||||
|
GES_TYPE_COMMAND_LINE_FORMATTER;
|
||||||
GES_TYPE_XML_FORMATTER;
|
GES_TYPE_XML_FORMATTER;
|
||||||
|
|
||||||
/* Register track elements */
|
/* Register track elements */
|
||||||
|
|
|
@ -74,6 +74,7 @@
|
||||||
#include <ges/ges-effect.h>
|
#include <ges/ges-effect.h>
|
||||||
#include <ges/ges-formatter.h>
|
#include <ges/ges-formatter.h>
|
||||||
#include <ges/ges-pitivi-formatter.h>
|
#include <ges/ges-pitivi-formatter.h>
|
||||||
|
#include <ges/ges-command-line-formatter.h>
|
||||||
#include <ges/ges-utils.h>
|
#include <ges/ges-utils.h>
|
||||||
#include <ges/ges-meta-container.h>
|
#include <ges/ges-meta-container.h>
|
||||||
#include <ges/ges-gerror.h>
|
#include <ges/ges-gerror.h>
|
||||||
|
|
|
@ -3,13 +3,10 @@ bin_PROGRAMS = ges-launch-@GST_API_VERSION@
|
||||||
AM_CFLAGS = -I$(top_srcdir) $(GST_PBUTILS_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS) $(GST_VALIDATE_CFLAGS)
|
AM_CFLAGS = -I$(top_srcdir) $(GST_PBUTILS_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS) $(GST_VALIDATE_CFLAGS)
|
||||||
LDADD = $(top_builddir)/ges/libges-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) $(GIO_LIBS) $(GST_VALIDATE_LIBS)
|
LDADD = $(top_builddir)/ges/libges-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) $(GIO_LIBS) $(GST_VALIDATE_LIBS)
|
||||||
|
|
||||||
noinst_HEADERS = ges-validate.h ges-structure-parser.h
|
noinst_HEADERS = ges-validate.h
|
||||||
|
|
||||||
ges_launch_@GST_API_VERSION@_SOURCES = ges-validate.c ges-launch.c ges-structure-parser.c
|
ges_launch_@GST_API_VERSION@_SOURCES = ges-validate.c ges-launch.c
|
||||||
|
|
||||||
nodist_ges_launch_@GST_API_VERSION@_SOURCES = lex.priv_ges_parse_yy.c parse_lex.h
|
|
||||||
|
|
||||||
CLEANFILES = lex.priv_ges_parse_yy.c
|
|
||||||
|
|
||||||
Android.mk: Makefile.am $(BUILT_SOURCES)
|
Android.mk: Makefile.am $(BUILT_SOURCES)
|
||||||
androgenizer \
|
androgenizer \
|
||||||
|
@ -21,6 +18,3 @@ Android.mk: Makefile.am $(BUILT_SOURCES)
|
||||||
-:LDFLAGS -lges-@GST_API_VERSION@ $(GST_PBUTILS_LIBS) $(GST_LIBS) \
|
-:LDFLAGS -lges-@GST_API_VERSION@ $(GST_PBUTILS_LIBS) $(GST_LIBS) \
|
||||||
-:PASSTHROUGH LOCAL_ARM_MODE:=arm \
|
-:PASSTHROUGH LOCAL_ARM_MODE:=arm \
|
||||||
> $@
|
> $@
|
||||||
|
|
||||||
lex.priv_ges_parse_yy.c parse_lex.h: parse.l
|
|
||||||
$(AM_V_GEN)$(FLEX_PATH) --header-file=parse_lex.h -Ppriv_ges_parse_yy $^
|
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <glib/gprintf.h>
|
#include <glib/gprintf.h>
|
||||||
#include <ges/ges.h>
|
#include <ges/ges.h>
|
||||||
#include "../ges/ges-structured-interface.h"
|
|
||||||
#include <gst/pbutils/encoding-profile.h>
|
#include <gst/pbutils/encoding-profile.h>
|
||||||
|
|
||||||
#include <locale.h> /* for LC_ALL */
|
#include <locale.h> /* for LC_ALL */
|
||||||
|
@ -36,9 +35,6 @@
|
||||||
#include <glib-unix.h>
|
#include <glib-unix.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ges-structure-parser.h"
|
|
||||||
#include "parse_lex.h"
|
|
||||||
|
|
||||||
/* GLOBAL VARIABLE */
|
/* GLOBAL VARIABLE */
|
||||||
static guint repeat = 0;
|
static guint repeat = 0;
|
||||||
static gboolean mute = FALSE;
|
static gboolean mute = FALSE;
|
||||||
|
@ -136,6 +132,56 @@ error_loading_asset_cb (GESProject * project, GError * error,
|
||||||
g_main_loop_quit (mainloop);
|
g_main_loop_quit (mainloop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_timeline_set_user_options (GESTimeline * timeline, const gchar * load_path)
|
||||||
|
{
|
||||||
|
GList *tmp;
|
||||||
|
GESTrack *tracka, *trackv;
|
||||||
|
gboolean has_audio = FALSE, has_video = FALSE;
|
||||||
|
|
||||||
|
retry:
|
||||||
|
for (tmp = timeline->tracks; tmp; tmp = tmp->next) {
|
||||||
|
|
||||||
|
if (GES_TRACK (tmp->data)->type == GES_TRACK_TYPE_VIDEO)
|
||||||
|
has_video = TRUE;
|
||||||
|
else if (GES_TRACK (tmp->data)->type == GES_TRACK_TYPE_AUDIO)
|
||||||
|
has_audio = TRUE;
|
||||||
|
|
||||||
|
if (disable_mixing) {
|
||||||
|
GST_ERROR_OBJECT (tmp->data, "DISABLE MIXING");
|
||||||
|
ges_track_set_mixing (tmp->data, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(GES_TRACK (tmp->data)->type & track_types)) {
|
||||||
|
ges_timeline_remove_track (timeline, tmp->data);
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scenario && !load_path) {
|
||||||
|
if (!has_video && track_types & GES_TRACK_TYPE_VIDEO) {
|
||||||
|
trackv = GES_TRACK (ges_video_track_new ());
|
||||||
|
|
||||||
|
if (disable_mixing)
|
||||||
|
ges_track_set_mixing (trackv, FALSE);
|
||||||
|
|
||||||
|
if (!(ges_timeline_add_track (timeline, trackv)))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!has_audio && track_types & GES_TRACK_TYPE_AUDIO) {
|
||||||
|
tracka = GES_TRACK (ges_audio_track_new ());
|
||||||
|
if (disable_mixing)
|
||||||
|
ges_track_set_mixing (tracka, FALSE);
|
||||||
|
|
||||||
|
if (!(ges_timeline_add_track (timeline, tracka)))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
project_loaded_cb (GESProject * project, GESTimeline * timeline)
|
project_loaded_cb (GESProject * project, GESTimeline * timeline)
|
||||||
{
|
{
|
||||||
|
@ -165,7 +211,10 @@ project_loaded_cb (GESProject * project, GESTimeline * timeline)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ges_validate_activate (GST_PIPELINE (pipeline), scenario,
|
_timeline_set_user_options (timeline, ges_project_get_uri (project));
|
||||||
|
|
||||||
|
if (ges_project_get_uri (project)
|
||||||
|
&& ges_validate_activate (GST_PIPELINE (pipeline), scenario,
|
||||||
&needs_set_state) == FALSE) {
|
&needs_set_state) == FALSE) {
|
||||||
g_error ("Could not activate scenario %s", scenario);
|
g_error ("Could not activate scenario %s", scenario);
|
||||||
seenerrors = TRUE;
|
seenerrors = TRUE;
|
||||||
|
@ -178,264 +227,6 @@ project_loaded_cb (GESProject * project, GESTimeline * timeline)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint /* -1: not present, 0: failure, 1: OK */
|
|
||||||
_convert_to_clocktime (GstStructure * structure, const gchar * name,
|
|
||||||
GstClockTime default_value)
|
|
||||||
{
|
|
||||||
gint res = 1;
|
|
||||||
gdouble val;
|
|
||||||
GValue d_val = { 0 };
|
|
||||||
GstClockTime timestamp;
|
|
||||||
const GValue *gvalue = gst_structure_get_value (structure, name);
|
|
||||||
|
|
||||||
if (gvalue == NULL) {
|
|
||||||
timestamp = default_value;
|
|
||||||
|
|
||||||
res = -1;
|
|
||||||
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (G_VALUE_TYPE (gvalue) == GST_TYPE_CLOCK_TIME)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
g_value_init (&d_val, G_TYPE_DOUBLE);
|
|
||||||
if (!g_value_transform (gvalue, &d_val)) {
|
|
||||||
GST_ERROR ("Could not get timestamp for %s", name);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
val = g_value_get_double ((const GValue *) &d_val);
|
|
||||||
|
|
||||||
if (val == -1.0)
|
|
||||||
timestamp = GST_CLOCK_TIME_NONE;
|
|
||||||
else
|
|
||||||
timestamp = val * GST_SECOND;
|
|
||||||
|
|
||||||
done:
|
|
||||||
gst_structure_set (structure, name, G_TYPE_UINT64, timestamp, NULL);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
const gchar *long_name;
|
|
||||||
const gchar *short_name;
|
|
||||||
GType type;
|
|
||||||
const gchar *new_name;
|
|
||||||
} Properties;
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
_cleanup_fields (const Properties * filed_names, GstStructure * structure,
|
|
||||||
GError ** error)
|
|
||||||
{
|
|
||||||
guint i;
|
|
||||||
|
|
||||||
for (i = 0; filed_names[i].long_name; i++) {
|
|
||||||
gboolean exists = FALSE;
|
|
||||||
|
|
||||||
/* Move shortly named fields to longname variante */
|
|
||||||
if (gst_structure_has_field (structure, filed_names[i].short_name)) {
|
|
||||||
exists = TRUE;
|
|
||||||
|
|
||||||
if (gst_structure_has_field (structure, filed_names[i].long_name)) {
|
|
||||||
*error = g_error_new (GES_ERROR, 0, "Using short and long name"
|
|
||||||
" at the same time for property: %s, which one should I use?!",
|
|
||||||
filed_names[i].long_name);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
} else {
|
|
||||||
const GValue *val =
|
|
||||||
gst_structure_get_value (structure, filed_names[i].short_name);
|
|
||||||
|
|
||||||
gst_structure_set_value (structure, filed_names[i].long_name, val);
|
|
||||||
gst_structure_remove_field (structure, filed_names[i].short_name);
|
|
||||||
}
|
|
||||||
} else if (gst_structure_has_field (structure, filed_names[i].long_name)) {
|
|
||||||
exists = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exists) {
|
|
||||||
if (filed_names[i].type == GST_TYPE_CLOCK_TIME) {
|
|
||||||
if (_convert_to_clocktime (structure, filed_names[i].long_name, 0) == 0) {
|
|
||||||
*error = g_error_new (GES_ERROR, 0, "Could not convert"
|
|
||||||
" %s to GstClockTime", filed_names[i].long_name);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filed_names[i].new_name
|
|
||||||
&& gst_structure_has_field (structure, filed_names[i].long_name)) {
|
|
||||||
const GValue *val =
|
|
||||||
gst_structure_get_value (structure, filed_names[i].long_name);
|
|
||||||
|
|
||||||
gst_structure_set_value (structure, filed_names[i].new_name, val);
|
|
||||||
gst_structure_remove_field (structure, filed_names[i].long_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
_add_clip (GESTimeline * timeline, GstStructure * structure, GError ** error)
|
|
||||||
{
|
|
||||||
const Properties filed_names[] = {
|
|
||||||
{"uri", "n", 0, "asset-id"},
|
|
||||||
{"name", "n", 0, NULL},
|
|
||||||
{"start", "s", GST_TYPE_CLOCK_TIME, NULL},
|
|
||||||
{"duration", "d", GST_TYPE_CLOCK_TIME, NULL},
|
|
||||||
{"inpoint", "i", GST_TYPE_CLOCK_TIME, NULL},
|
|
||||||
{"track-types", "tt", 0, NULL},
|
|
||||||
{"layer", "l", 0, NULL},
|
|
||||||
{NULL},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!_cleanup_fields (filed_names, structure, error))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
gst_structure_set (structure, "type", G_TYPE_STRING, "GESUriClip", NULL);
|
|
||||||
|
|
||||||
GST_ERROR ("Adding a clip %" GST_PTR_FORMAT, structure);
|
|
||||||
|
|
||||||
return _ges_add_add_clip_from_struct (timeline, structure, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
_add_effect (GESTimeline * timeline, GstStructure * structure, GError ** error)
|
|
||||||
{
|
|
||||||
const Properties filed_names[] = {
|
|
||||||
{"element-name", "e", 0, NULL},
|
|
||||||
{"bin-description", "d", 0, "asset-id"},
|
|
||||||
{"name", "n", 0, "child-name"},
|
|
||||||
{NULL, NULL, 0, NULL},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!_cleanup_fields (filed_names, structure, error))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
gst_structure_set (structure, "child-type", G_TYPE_STRING, "GESEffect", NULL);
|
|
||||||
|
|
||||||
GST_ERROR ("Adding a clip %" GST_PTR_FORMAT, structure);
|
|
||||||
|
|
||||||
return _ges_container_add_child_from_struct (timeline, structure, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
_set_child_property (GESTimeline * timeline, GstStructure * structure,
|
|
||||||
GError ** error)
|
|
||||||
{
|
|
||||||
return _ges_set_child_property_from_struct (timeline, structure, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GOptionEntry timeline_parsing_options[] = {
|
|
||||||
{"clip", 'c', 0.0, G_OPTION_ARG_CALLBACK, &_add_clip,
|
|
||||||
"Adds a clip in the timeline",
|
|
||||||
" start - s: The start position of the element inside the layer.\n"
|
|
||||||
" duration - d: The duration of the clip.\n"
|
|
||||||
" inpoint - i: The inpoint of the clip\n."
|
|
||||||
" track-types - tt: The type of the tracks where the clip should be used:\n"
|
|
||||||
" Examples:\n"
|
|
||||||
" * audio / a\n"
|
|
||||||
" * video / v\n"
|
|
||||||
" * audio+video / a+v\n"
|
|
||||||
" Will default to all the media types in the clip that match the global track-types"},
|
|
||||||
{"effect", 'e', 0.0, G_OPTION_ARG_CALLBACK, &_add_effect,
|
|
||||||
"Adds an effect as decribed by 'bin-description'",
|
|
||||||
" bin-description - d: The description of the effect bin with a gst-launch-style pipeline description."
|
|
||||||
" element-name - d: The name of the element to apply the effect on."
|
|
||||||
/* TODO: Implement that:
|
|
||||||
* " start - s: The start position of the element inside the layer -- implies creation of effect *Clip*.\n"
|
|
||||||
* " duration - d: The duration of the clip -- implies creation of effect *Clip*.\n"
|
|
||||||
* " inpoint - i: The inpoint of the clip-- implies creation of effect *Clip*.\n" */
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define EXEC(func,structure,error) G_STMT_START { \
|
|
||||||
gboolean res = ((ActionFromStructureFunc)func)(timeline, structure, error); \
|
|
||||||
if (!res) {\
|
|
||||||
GST_ERROR ("Could not execute: %" GST_PTR_FORMAT ", error: %s", structure, (*error)->message); \
|
|
||||||
goto build_failure; \
|
|
||||||
} \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
static GESTimeline *
|
|
||||||
create_timeline (GList * structures, const gchar * proj_uri,
|
|
||||||
const gchar * scenario)
|
|
||||||
{
|
|
||||||
guint i;
|
|
||||||
GList *tmp;
|
|
||||||
GESTimeline *timeline;
|
|
||||||
GESTrack *tracka = NULL, *trackv = NULL;
|
|
||||||
GESProject *project = ges_project_new (proj_uri);
|
|
||||||
|
|
||||||
g_signal_connect (project, "error-loading-asset",
|
|
||||||
G_CALLBACK (error_loading_asset_cb), NULL);
|
|
||||||
|
|
||||||
if (proj_uri != NULL) {
|
|
||||||
g_signal_connect (project, "loaded", G_CALLBACK (project_loaded_cb), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
timeline = GES_TIMELINE (ges_asset_extract (GES_ASSET (project), NULL));
|
|
||||||
|
|
||||||
if (proj_uri) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_object_set (timeline, "auto-transition", TRUE, NULL);
|
|
||||||
if (track_types & GES_TRACK_TYPE_VIDEO) {
|
|
||||||
trackv = GES_TRACK (ges_video_track_new ());
|
|
||||||
|
|
||||||
if (disable_mixing)
|
|
||||||
ges_track_set_mixing (trackv, FALSE);
|
|
||||||
|
|
||||||
if (!(ges_timeline_add_track (timeline, trackv)))
|
|
||||||
goto build_failure;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (track_types & GES_TRACK_TYPE_AUDIO) {
|
|
||||||
tracka = GES_TRACK (ges_audio_track_new ());
|
|
||||||
if (disable_mixing)
|
|
||||||
ges_track_set_mixing (tracka, FALSE);
|
|
||||||
|
|
||||||
if (!(ges_timeline_add_track (timeline, tracka)))
|
|
||||||
goto build_failure;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Here we've finished initializing our timeline, we're
|
|
||||||
* ready to start using it... by solely working with the layer !*/
|
|
||||||
for (tmp = structures; tmp; tmp = tmp->next) {
|
|
||||||
const gchar *name = gst_structure_get_name (tmp->data);
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
if (g_str_has_prefix (name, "set-")) {
|
|
||||||
EXEC (_set_child_property, tmp->data, &error);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS (timeline_parsing_options); i++) {
|
|
||||||
if (gst_structure_has_name (tmp->data,
|
|
||||||
timeline_parsing_options[i].long_name)
|
|
||||||
|| (strlen (name) == 1 &&
|
|
||||||
*name == timeline_parsing_options[i].short_name)) {
|
|
||||||
EXEC (((ActionFromStructureFunc) timeline_parsing_options[i].arg_data),
|
|
||||||
tmp->data, &error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
return timeline;
|
|
||||||
|
|
||||||
build_failure:
|
|
||||||
{
|
|
||||||
gst_object_unref (timeline);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_save_timeline (GESTimeline * timeline, const gchar * load_path)
|
_save_timeline (GESTimeline * timeline, const gchar * load_path)
|
||||||
|
@ -453,9 +244,33 @@ _save_timeline (GESTimeline * timeline, const gchar * load_path)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GESTimeline *
|
||||||
|
create_timeline (const gchar * serialized_timeline, const gchar * proj_uri,
|
||||||
|
const gchar * scenario)
|
||||||
|
{
|
||||||
|
GESTimeline *timeline;
|
||||||
|
GESProject *project;
|
||||||
|
|
||||||
|
if (proj_uri != NULL) {
|
||||||
|
project = ges_project_new (proj_uri);
|
||||||
|
} else if (scenario == NULL) {
|
||||||
|
project = ges_project_new (serialized_timeline);
|
||||||
|
} else {
|
||||||
|
project = ges_project_new (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_signal_connect (project, "error-loading-asset",
|
||||||
|
G_CALLBACK (error_loading_asset_cb), NULL);
|
||||||
|
g_signal_connect (project, "loaded", G_CALLBACK (project_loaded_cb), NULL);
|
||||||
|
|
||||||
|
timeline = GES_TIMELINE (ges_asset_extract (GES_ASSET (project), NULL));
|
||||||
|
|
||||||
|
return timeline;
|
||||||
|
}
|
||||||
|
|
||||||
static GESPipeline *
|
static GESPipeline *
|
||||||
create_pipeline (GESTimeline ** ret_timeline, gchar * load_path,
|
create_pipeline (GESTimeline ** ret_timeline, gchar * load_path,
|
||||||
GList * structures, const gchar * scenario)
|
const gchar * serialized_timeline, const gchar * scenario)
|
||||||
{
|
{
|
||||||
gchar *uri = NULL;
|
gchar *uri = NULL;
|
||||||
GESTimeline *timeline = NULL;
|
GESTimeline *timeline = NULL;
|
||||||
|
@ -472,8 +287,10 @@ create_pipeline (GESTimeline ** ret_timeline, gchar * load_path,
|
||||||
|
|
||||||
pipeline = ges_pipeline_new ();
|
pipeline = ges_pipeline_new ();
|
||||||
|
|
||||||
if (!(timeline = create_timeline (structures, uri, scenario)))
|
if (!(timeline = create_timeline (serialized_timeline, uri, scenario))) {
|
||||||
|
GST_ERROR ("Could not create the timeline");
|
||||||
goto failure;
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
if (!load_path)
|
if (!load_path)
|
||||||
ges_timeline_commit (timeline);
|
ges_timeline_commit (timeline);
|
||||||
|
@ -790,15 +607,13 @@ sanitize_argument (gchar * arg)
|
||||||
return new_string;
|
return new_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GESStructureParser *
|
static gchar *
|
||||||
_parse_timeline (int argc, char **argv)
|
_parse_timeline (int argc, char **argv)
|
||||||
{
|
{
|
||||||
gint i;
|
gint i;
|
||||||
yyscan_t scanner;
|
|
||||||
gchar *string = g_strdup (" ");
|
|
||||||
GESStructureParser *parser = ges_structure_parser_new ();
|
|
||||||
|
|
||||||
priv_ges_parse_yylex_init_extra (parser, &scanner);
|
gchar *string = g_strdup (" ");
|
||||||
|
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
gchar *new_string;
|
gchar *new_string;
|
||||||
gchar *sanitized = sanitize_argument (argv[i]);
|
gchar *sanitized = sanitize_argument (argv[i]);
|
||||||
|
@ -810,13 +625,8 @@ _parse_timeline (int argc, char **argv)
|
||||||
string = new_string;
|
string = new_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv_ges_parse_yy_scan_string (string, scanner);
|
|
||||||
priv_ges_parse_yylex (scanner);
|
|
||||||
g_free (string);
|
|
||||||
priv_ges_parse_yylex_destroy (scanner);
|
|
||||||
|
|
||||||
ges_structure_parser_end_of_file (parser);
|
return string;
|
||||||
return parser;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -824,7 +634,7 @@ main (int argc, gchar ** argv)
|
||||||
{
|
{
|
||||||
gint validate_res;
|
gint validate_res;
|
||||||
GError *err = NULL;
|
GError *err = NULL;
|
||||||
gchar *outputuri = NULL;
|
gchar *outputuri = NULL, *serialized_timeline = NULL;
|
||||||
const gchar *format = NULL;
|
const gchar *format = NULL;
|
||||||
gchar *exclude_args = NULL;
|
gchar *exclude_args = NULL;
|
||||||
static gboolean smartrender = FALSE;
|
static gboolean smartrender = FALSE;
|
||||||
|
@ -836,7 +646,6 @@ main (int argc, gchar ** argv)
|
||||||
gchar *videosink = NULL, *audiosink = NULL;
|
gchar *videosink = NULL, *audiosink = NULL;
|
||||||
gboolean inspect_action_type = FALSE;
|
gboolean inspect_action_type = FALSE;
|
||||||
gchar *encoding_profile = NULL;
|
gchar *encoding_profile = NULL;
|
||||||
GESStructureParser *parser;
|
|
||||||
|
|
||||||
GOptionEntry options[] = {
|
GOptionEntry options[] = {
|
||||||
{"thumbnail", 'm', 0.0, G_OPTION_ARG_DOUBLE, &thumbinterval,
|
{"thumbnail", 'm', 0.0, G_OPTION_ARG_DOUBLE, &thumbinterval,
|
||||||
|
@ -979,8 +788,8 @@ main (int argc, gchar ** argv)
|
||||||
g_option_context_free (ctx);
|
g_option_context_free (ctx);
|
||||||
|
|
||||||
/* Create the pipeline */
|
/* Create the pipeline */
|
||||||
parser = _parse_timeline (argc, argv);
|
serialized_timeline = _parse_timeline (argc, argv);
|
||||||
create_pipeline (&timeline, load_path, parser->structures, scenario);
|
create_pipeline (&timeline, load_path, serialized_timeline, scenario);
|
||||||
if (!pipeline)
|
if (!pipeline)
|
||||||
exit (1);
|
exit (1);
|
||||||
|
|
||||||
|
@ -1070,6 +879,11 @@ main (int argc, gchar ** argv)
|
||||||
g_error ("Could not activate scenario %s", scenario);
|
g_error ("Could not activate scenario %s", scenario);
|
||||||
return 29;
|
return 29;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_timeline_set_user_options (timeline, NULL)) {
|
||||||
|
g_error ("Could not properly set tracks");
|
||||||
|
return 29;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
|
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
|
||||||
|
|
Loading…
Reference in a new issue