1 /* GStreamer Editing Services
3 * Copyright (C) <2015> Thibault Saunier <tsaunier@gnome.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
24 #include "ges-structured-interface.h"
29 #define LAST_CONTAINER_QDATA g_quark_from_string("ges-structured-last-container")
30 #define LAST_CHILD_QDATA g_quark_from_string("ges-structured-last-child")
33 _get_clocktime (GstStructure * structure, const gchar * name, gpointer var)
35 gboolean found = FALSE;
36 GstClockTime *val = (GstClockTime *) var;
38 const GValue *gvalue = gst_structure_get_value (structure, name);
41 if (G_VALUE_TYPE (gvalue) == GST_TYPE_CLOCK_TIME) {
42 *val = (GstClockTime) g_value_get_uint64 (gvalue);
44 } else if (G_VALUE_TYPE (gvalue) == G_TYPE_UINT64) {
45 *val = (GstClockTime) g_value_get_uint64 (gvalue);
47 } else if (G_VALUE_TYPE (gvalue) == G_TYPE_UINT) {
48 *val = (GstClockTime) g_value_get_uint (gvalue);
50 } else if (G_VALUE_TYPE (gvalue) == G_TYPE_INT) {
51 *val = (GstClockTime) g_value_get_int (gvalue);
53 } else if (G_VALUE_TYPE (gvalue) == G_TYPE_INT64) {
54 *val = (GstClockTime) g_value_get_int64 (gvalue);
56 } else if (G_VALUE_TYPE (gvalue) == G_TYPE_DOUBLE) {
57 gdouble d = g_value_get_double (gvalue);
61 *val = GST_CLOCK_TIME_NONE;
63 *val = d * GST_SECOND;
64 *val = GST_ROUND_UP_4 (*val);
72 #define GET_AND_CHECK(name,type,var,label) G_STMT_START {\
73 gboolean found = FALSE; \
75 if (type == GST_TYPE_CLOCK_TIME) {\
76 found = _get_clocktime(structure,name,var);\
79 found = gst_structure_get (structure, name, type, var, NULL); \
82 gchar *struct_str = gst_structure_to_string (structure); \
83 *error = g_error_new (GES_ERROR, 0, \
84 "Could not get the mandatory field '%s'" \
85 " fields in %s", name, struct_str); \
86 g_free (struct_str); \
91 #define TRY_GET_STRING(name,var,def) G_STMT_START {\
92 *var = gst_structure_get_string (structure, name); \
97 #define TRY_GET(name,type,var,def) G_STMT_START {\
98 if (type == GST_TYPE_CLOCK_TIME) {\
99 if (!_get_clocktime(structure,name,var))\
101 } else if (!gst_structure_get (structure, name, type, var, NULL)) {\
108 const gchar **fields;
109 GList *invalid_fields;
113 _check_field (GQuark field_id, const GValue * value, FieldsError * fields_error)
116 const gchar *field = g_quark_to_string (field_id);
118 for (i = 0; fields_error->fields[i]; i++) {
119 if (g_strcmp0 (fields_error->fields[i], field) == 0) {
125 fields_error->invalid_fields =
126 g_list_append (fields_error->invalid_fields, (gpointer) field);
132 _check_fields (GstStructure * structure, FieldsError fields_error,
135 gst_structure_foreach (structure,
136 (GstStructureForeachFunc) _check_field, &fields_error);
138 if (fields_error.invalid_fields) {
140 const gchar *struct_name = gst_structure_get_name (structure);
141 GString *msg = g_string_new (NULL);
143 g_string_append_printf (msg, "Unknown propert%s in %s%s:",
144 g_list_length (fields_error.invalid_fields) > 1 ? "ies" : "y",
145 strlen (struct_name) > 1 ? "--" : "-",
146 gst_structure_get_name (structure));
148 for (tmp = fields_error.invalid_fields; tmp; tmp = tmp->next)
149 g_string_append_printf (msg, " %s", (gchar *) tmp->data);
152 *error = g_error_new_literal (GES_ERROR, 0, msg->str);
153 GST_ERROR ("%s", msg->str);
155 g_string_free (msg, TRUE);
165 _ges_add_remove_keyframe_from_struct (GESTimeline * timeline,
166 GstStructure * structure, GError ** error)
168 GESTrackElement *element;
171 GstClockTime timestamp;
172 GstControlBinding *binding = NULL;
173 GstTimedValueControlSource *source = NULL;
174 gchar *element_name = NULL, *property_name = NULL;
176 gboolean ret = FALSE;
178 const gchar *valid_fields[] =
179 { "element-name", "property-name", "value", "timestamp",
183 FieldsError fields_error = { valid_fields, NULL };
185 if (!_check_fields (structure, fields_error, error))
188 GET_AND_CHECK ("element-name", G_TYPE_STRING, &element_name, done);
189 GET_AND_CHECK ("property-name", G_TYPE_STRING, &property_name, done);
190 GET_AND_CHECK ("value", G_TYPE_DOUBLE, &value, done);
191 GET_AND_CHECK ("timestamp", GST_TYPE_CLOCK_TIME, ×tamp, done);
194 GES_TRACK_ELEMENT (ges_timeline_get_element (timeline, element_name));
196 if (!GES_IS_TRACK_ELEMENT (element)) {
198 g_error_new (GES_ERROR, 0, "Could not find TrackElement %s",
204 binding = ges_track_element_get_control_binding (element, property_name);
205 if (binding == NULL) {
206 *error = g_error_new (GES_ERROR, 0, "No control binding found for %s:%s"
207 " you should first set-control-binding on it",
208 element_name, property_name);
213 g_object_get (binding, "control-source", &source, NULL);
215 if (source == NULL) {
216 *error = g_error_new (GES_ERROR, 0, "No control source found for %s:%s"
217 " you should first set-control-binding on it",
218 element_name, property_name);
223 if (!GST_IS_TIMED_VALUE_CONTROL_SOURCE (source)) {
224 *error = g_error_new (GES_ERROR, 0, "You can use add-keyframe"
225 " only on GstTimedValueControlSource not %s",
226 G_OBJECT_TYPE_NAME (source));
231 if (!g_strcmp0 (gst_structure_get_name (structure), "add-keyframe"))
232 ret = gst_timed_value_control_source_set (source, timestamp, value);
234 ret = gst_timed_value_control_source_unset (source, timestamp);
238 g_error_new (GES_ERROR, 0,
239 "Could not unset value for timestamp: %" GST_TIME_FORMAT,
240 GST_TIME_ARGS (timestamp));
246 gst_object_unref (source);
247 g_free (element_name);
248 g_free (property_name);
255 _ges_get_asset_from_timeline (GESTimeline * timeline, GType type,
256 const gchar * id, GError ** error)
259 GESProject *project = ges_timeline_get_project (timeline);
262 asset = ges_project_create_asset_sync (project, id, type, &err);
265 g_propagate_error (error, err);
266 if (!asset || (error && *error)) {
268 if (error && !*error) {
269 *error = g_error_new (GES_ERROR, 0,
270 "There was an error requesting the asset with id %s and type %s (%s)",
271 id, g_type_name (type), "unknown");
275 ("There was an error requesting the asset with id %s and type %s (%s)",
276 id, g_type_name (type), error ? (*error)->message : "unknown");
284 /* Unref after usage */
286 _ges_get_layer_by_priority (GESTimeline * timeline, gint priority)
290 GESLayer *layer = NULL;
292 priority = MAX (priority, 0);
293 layers = ges_timeline_get_layers (timeline);
294 nlayers = (gint) g_list_length (layers);
295 if (priority >= nlayers) {
298 while (i <= priority) {
299 layer = ges_timeline_append_layer (timeline);
304 layer = gst_object_ref (layer);
309 layer = ges_timeline_get_layer (timeline, priority);
312 g_list_free_full (layers, gst_object_unref);
318 ensure_uri (gchar * location)
320 if (gst_uri_is_valid (location))
321 return g_strdup (location);
323 return gst_filename_to_uri (location, NULL);
327 _ges_add_clip_from_struct (GESTimeline * timeline, GstStructure * structure,
336 const gchar *pattern;
337 gchar *asset_id = NULL;
338 gchar *check_asset_id = NULL;
339 const gchar *type_string;
341 gboolean res = FALSE;
343 GstClockTime duration = 1 * GST_SECOND, inpoint = 0, start =
346 const gchar *valid_fields[] =
347 { "asset-id", "pattern", "name", "layer-priority", "layer", "type",
348 "start", "inpoint", "duration", "text", NULL
351 FieldsError fields_error = { valid_fields, NULL };
353 if (!_check_fields (structure, fields_error, error))
356 GET_AND_CHECK ("asset-id", G_TYPE_STRING, &check_asset_id, beach);
358 TRY_GET_STRING ("pattern", &pattern, NULL);
359 TRY_GET_STRING ("text", &text, NULL);
360 TRY_GET_STRING ("name", &name, NULL);
361 TRY_GET ("layer-priority", G_TYPE_INT, &layer_priority, -1);
362 if (layer_priority == -1)
363 TRY_GET ("layer", G_TYPE_INT, &layer_priority, -1);
364 TRY_GET_STRING ("type", &type_string, "GESUriClip");
365 TRY_GET ("start", GST_TYPE_CLOCK_TIME, &start, GST_CLOCK_TIME_NONE);
366 TRY_GET ("inpoint", GST_TYPE_CLOCK_TIME, &inpoint, 0);
367 TRY_GET ("duration", GST_TYPE_CLOCK_TIME, &duration, GST_CLOCK_TIME_NONE);
369 if (!(type = g_type_from_name (type_string))) {
370 *error = g_error_new (GES_ERROR, 0, "This type doesn't exist : %s",
376 if (type == GES_TYPE_URI_CLIP) {
377 asset_id = ensure_uri (check_asset_id);
379 asset_id = g_strdup (check_asset_id);
382 asset = _ges_get_asset_from_timeline (timeline, type, asset_id, error);
389 if (layer_priority == -1) {
390 GESContainer *container;
392 container = g_object_get_qdata (G_OBJECT (timeline), LAST_CONTAINER_QDATA);
393 if (!container || !GES_IS_CLIP (container))
394 layer = _ges_get_layer_by_priority (timeline, 0);
396 layer = ges_clip_get_layer (GES_CLIP (container));
399 layer = _ges_get_layer_by_priority (timeline, 0);
401 layer = _ges_get_layer_by_priority (timeline, layer_priority);
406 g_error_new (GES_ERROR, 0, "No layer with priority %d", layer_priority);
410 if (GES_IS_URI_CLIP_ASSET (asset) && !GST_CLOCK_TIME_IS_VALID (duration)) {
411 duration = GST_CLOCK_DIFF (inpoint,
412 ges_uri_clip_asset_get_duration (GES_URI_CLIP_ASSET (asset)));
415 clip = ges_layer_add_asset (layer, asset, start, inpoint, duration,
416 GES_TRACK_TYPE_UNKNOWN);
421 if (GES_TIMELINE_ELEMENT_DURATION (clip) == 0) {
422 *error = g_error_new (GES_ERROR, 0,
423 "Clip %s has 0 as duration, please provide a proper duration",
430 if (GES_IS_TEST_CLIP (clip)) {
432 GEnumClass *enum_class =
433 G_ENUM_CLASS (g_type_class_ref (GES_VIDEO_TEST_PATTERN_TYPE));
434 GEnumValue *value = g_enum_get_value_by_nick (enum_class, pattern);
441 ges_test_clip_set_vpattern (GES_TEST_CLIP (clip), value->value);
442 g_type_class_unref (enum_class);
446 if (GES_IS_TITLE_CLIP (clip) && text)
447 ges_timeline_element_set_child_properties (GES_TIMELINE_ELEMENT (clip),
451 && !ges_timeline_element_set_name (GES_TIMELINE_ELEMENT (clip), name)) {
454 g_error_new (GES_ERROR, 0, "couldn't set name %s on clip with id %s",
458 *error = g_error_new (GES_ERROR, 0,
459 "Couldn't add clip with id %s to layer with priority %d", asset_id,
464 g_object_set_qdata (G_OBJECT (timeline), LAST_CONTAINER_QDATA, clip);
465 g_object_set_qdata (G_OBJECT (timeline), LAST_CHILD_QDATA, NULL);
468 gst_object_unref (layer);
472 g_free (check_asset_id);
477 _ges_container_add_child_from_struct (GESTimeline * timeline,
478 GstStructure * structure, GError ** error)
481 GESContainer *container;
482 GESTimelineElement *child = NULL;
483 const gchar *container_name, *child_name, *child_type, *id;
486 const gchar *valid_fields[] = { "container-name", "asset-id",
487 "child-type", "child-name", NULL
490 FieldsError fields_error = { valid_fields, NULL };
492 if (!_check_fields (structure, fields_error, error))
495 container_name = gst_structure_get_string (structure, "container-name");
497 if (container_name == NULL) {
498 container = g_object_get_qdata (G_OBJECT (timeline), LAST_CONTAINER_QDATA);
501 GES_CONTAINER (ges_timeline_get_element (timeline, container_name));
504 g_return_val_if_fail (GES_IS_CONTAINER (container), FALSE);
506 id = gst_structure_get_string (structure, "asset-id");
507 child_type = gst_structure_get_string (structure, "child-type");
509 if (id && child_type) {
511 _ges_get_asset_from_timeline (timeline, g_type_from_name (child_type),
519 child = GES_TIMELINE_ELEMENT (ges_asset_extract (asset, NULL));
520 if (!GES_IS_TIMELINE_ELEMENT (child)) {
521 g_error_new (GES_ERROR, 0, "Could not extract child element");
527 child_name = gst_structure_get_string (structure, "child-name");
528 if (!child && child_name) {
529 child = ges_timeline_get_element (timeline, child_name);
530 if (!GES_IS_TIMELINE_ELEMENT (child)) {
531 g_error_new (GES_ERROR, 0, "Could not find child element");
538 g_error_new (GES_ERROR, 0, "Wong parametters, could not get a child");
544 ges_timeline_element_set_name (child, child_name);
546 child_name = GES_TIMELINE_ELEMENT_NAME (child);
548 res = ges_container_add (container, child);
550 g_error_new (GES_ERROR, 0, "Could not add child to container");
552 g_object_set_qdata (G_OBJECT (timeline), LAST_CHILD_QDATA, child);
560 _ges_set_child_property_from_struct (GESTimeline * timeline,
561 GstStructure * structure, GError ** error)
564 GESTimelineElement *element;
565 const gchar *property_name, *element_name;
567 const gchar *valid_fields[] = { "element-name", "property", "value", NULL };
569 FieldsError fields_error = { valid_fields, NULL };
571 if (!_check_fields (structure, fields_error, error))
574 element_name = gst_structure_get_string (structure, "element-name");
575 if (element_name == NULL)
576 element = g_object_get_qdata (G_OBJECT (timeline), LAST_CHILD_QDATA);
578 element = ges_timeline_get_element (timeline, element_name);
580 property_name = gst_structure_get_string (structure, "property");
581 if (property_name == NULL) {
582 const gchar *name = gst_structure_get_name (structure);
584 if (g_str_has_prefix (name, "set-"))
585 property_name = &name[4];
587 gchar *struct_str = gst_structure_to_string (structure);
590 g_error_new (GES_ERROR, 0, "Could not find any property name in %s",
599 if (!ges_track_element_lookup_child (GES_TRACK_ELEMENT (element),
600 property_name, NULL, NULL))
605 element = g_object_get_qdata (G_OBJECT (timeline), LAST_CONTAINER_QDATA);
607 if (element == NULL) {
609 g_error_new (GES_ERROR, 0,
610 "Could not find anywhere to set property: %s", property_name);
616 if (!GES_IS_TIMELINE_ELEMENT (element)) {
618 g_error_new (GES_ERROR, 0, "Could not find child %s", element_name);
623 value = gst_structure_get_value (structure, "value");
625 GST_DEBUG ("%s Setting %s property to %p",
626 element->name, property_name, value);
628 ges_timeline_element_set_child_property (element, property_name,