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"
25 #include "ges-internal.h"
30 #define LAST_CONTAINER_QDATA g_quark_from_string("ges-structured-last-container")
31 #define LAST_CHILD_QDATA g_quark_from_string("ges-structured-last-child")
33 #ifdef G_HAVE_ISO_VARARGS
34 #define REPORT_UNLESS(condition, errpoint, ...) \
37 gchar *tmp = gst_info_strdup_printf(__VA_ARGS__); \
38 *error = g_error_new_literal (GES_ERROR, 0, tmp); \
44 #else /* G_HAVE_GNUC_VARARGS */
45 #ifdef G_HAVE_GNUC_VARARGS
46 #define REPORT_UNLESS(condition, errpoint, args...) \
49 gchar *tmp = gst_info_strdup_printf(##args); \
50 *error = g_error_new_literal (GES_ERROR, 0, tmp); \
56 #endif /* G_HAVE_ISO_VARARGS */
57 #endif /* G_HAVE_GNUC_VARARGS */
59 #define GET_AND_CHECK(name,type,var,label) G_STMT_START {\
60 gboolean found = FALSE; \
62 if (type == GST_TYPE_CLOCK_TIME) {\
63 found = ges_util_structure_get_clocktime (structure,name, (GstClockTime*)var,NULL);\
66 found = gst_structure_get (structure, name, type, var, NULL); \
69 gchar *struct_str = gst_structure_to_string (structure); \
70 *error = g_error_new (GES_ERROR, 0, \
71 "Could not get the mandatory field '%s'" \
72 " of type %s - fields in %s", name, g_type_name (type), struct_str); \
73 g_free (struct_str); \
78 #define TRY_GET_STRING(name,var,def) G_STMT_START {\
79 *var = gst_structure_get_string (structure, name); \
84 #define TRY_GET_TIME(name, var, var_frames, def) G_STMT_START { \
85 if (!ges_util_structure_get_clocktime (structure, name, var, var_frames)) { \
87 *var_frames = GES_FRAME_NUMBER_NONE; \
91 #define TRY_GET(name, type, var, def) G_STMT_START {\
92 g_assert (type != GST_TYPE_CLOCK_TIME); \
93 if (!gst_structure_get (structure, name, type, var, NULL))\
100 GList *invalid_fields;
104 _check_field (GQuark field_id, const GValue * value, FieldsError * fields_error)
107 const gchar *field = g_quark_to_string (field_id);
109 for (i = 0; fields_error->fields[i]; i++) {
110 if (g_strcmp0 (fields_error->fields[i], field) == 0) {
116 fields_error->invalid_fields =
117 g_list_append (fields_error->invalid_fields, (gpointer) field);
123 _check_fields (GstStructure * structure, FieldsError fields_error,
126 gst_structure_foreach (structure,
127 (GstStructureForeachFunc) _check_field, &fields_error);
129 if (fields_error.invalid_fields) {
131 const gchar *struct_name = gst_structure_get_name (structure);
132 GString *msg = g_string_new (NULL);
134 g_string_append_printf (msg, "Unknown propert%s in %s%s:",
135 g_list_length (fields_error.invalid_fields) > 1 ? "ies" : "y",
136 strlen (struct_name) > 1 ? "--" : "-",
137 gst_structure_get_name (structure));
139 for (tmp = fields_error.invalid_fields; tmp; tmp = tmp->next)
140 g_string_append_printf (msg, " %s", (gchar *) tmp->data);
143 *error = g_error_new_literal (GES_ERROR, 0, msg->str);
145 g_string_free (msg, TRUE);
153 static GESTimelineElement *
154 find_element_for_property (GESTimeline * timeline, GstStructure * structure,
155 gchar ** property_name, gboolean require_track_element, GError ** error)
158 const gchar *element_name;
159 GESTimelineElement *element;
161 element_name = gst_structure_get_string (structure, "element-name");
162 if (element_name == NULL) {
163 element = g_object_get_qdata (G_OBJECT (timeline), LAST_CHILD_QDATA);
165 gst_object_ref (element);
167 element = ges_timeline_get_element (timeline, element_name);
170 if (*property_name == NULL) {
171 gchar *tmpstr = *property_name;
172 const gchar *name = gst_structure_get_name (structure);
174 REPORT_UNLESS (g_str_has_prefix (name, "set-"), err,
175 "Could not find any property name in %" GST_PTR_FORMAT, structure);
177 *property_name = g_strdup (&tmpstr[4]);
183 if (!ges_timeline_element_lookup_child (element,
184 *property_name, NULL, NULL)) {
185 gst_clear_object (&element);
190 element = g_object_get_qdata (G_OBJECT (timeline), LAST_CONTAINER_QDATA);
192 gst_object_ref (element);
195 REPORT_UNLESS (GES_IS_TIMELINE_ELEMENT (element), err,
196 "Could not find child %s from %" GST_PTR_FORMAT, element_name, structure);
198 if (!require_track_element || GES_IS_TRACK_ELEMENT (element))
202 REPORT_UNLESS (GES_IS_CONTAINER (element), err,
203 "Could not find child %s from %" GST_PTR_FORMAT, element_name, structure);
205 for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
206 if (ges_timeline_element_lookup_child (tmp->data, *property_name, NULL,
208 gst_object_replace ((GstObject **) & element, tmp->data);
214 REPORT_UNLESS (GES_IS_TRACK_ELEMENT (element), err,
215 "Could not find TrackElement from %" GST_PTR_FORMAT, structure);
220 g_clear_object (&element);
225 _ges_save_timeline_if_needed (GESTimeline * timeline, GstStructure * structure,
229 const gchar *nested_timeline_id =
230 gst_structure_get_string (structure, "project-uri");
232 if (nested_timeline_id) {
233 res = ges_timeline_save_to_uri (timeline, nested_timeline_id, NULL, TRUE,
241 _ges_add_remove_keyframe_from_struct (GESTimeline * timeline,
242 GstStructure * structure, GError ** error)
244 GESTimelineElement *element = NULL;
248 GstClockTime timestamp;
249 GstControlBinding *binding = NULL;
250 GstTimedValueControlSource *source = NULL;
251 gchar *property_name = NULL;
253 gboolean ret = FALSE;
254 gboolean setting_value;
256 const gchar *valid_fields[] =
257 { "element-name", "property-name", "value", "timestamp", "project-uri",
261 FieldsError fields_error = { valid_fields, NULL };
263 if (!_check_fields (structure, fields_error, error))
266 GET_AND_CHECK ("property-name", G_TYPE_STRING, &property_name, done);
267 GET_AND_CHECK ("timestamp", GST_TYPE_CLOCK_TIME, ×tamp, done);
269 GET_AND_CHECK ("property-name", G_TYPE_STRING, &property_name, done);
271 find_element_for_property (timeline, structure, &property_name, TRUE,
275 REPORT_UNLESS (binding =
276 ges_track_element_get_control_binding (GES_TRACK_ELEMENT (element),
278 done, "No control binding found for %" GST_PTR_FORMAT, structure);
280 g_object_get (binding, "control-source", &source, NULL);
281 REPORT_UNLESS (source, done,
282 "No control source found for '%" GST_PTR_FORMAT
283 "' you should first set-control-binding on it", structure);
284 REPORT_UNLESS (GST_IS_TIMED_VALUE_CONTROL_SOURCE (source), done,
285 "You can use add-keyframe"
286 " only on GstTimedValueControlSource not %s",
287 G_OBJECT_TYPE_NAME (source));
289 g_object_get (binding, "absolute", &absolute, NULL);
293 GValue v2 = G_VALUE_INIT;
295 if (!ges_timeline_element_lookup_child (element, property_name, NULL,
298 g_error_new (GES_ERROR, 0, "Could not get property %s for %s",
299 property_name, GES_TIMELINE_ELEMENT_NAME (element));
303 v = gst_structure_get_value (structure, "value");
305 gchar *struct_str = gst_structure_to_string (structure);
307 *error = g_error_new (GES_ERROR, 0,
308 "Could not get the mandatory field 'value'"
309 " of type %s - fields in %s", g_type_name (pspec->value_type),
315 g_value_init (&v2, G_TYPE_DOUBLE);
316 if (!g_value_transform (v, &v2)) {
317 gchar *struct_str = gst_structure_to_string (structure);
319 *error = g_error_new (GES_ERROR, 0,
320 "Could not get the mandatory field 'value'"
321 " of type %s - fields in %s", g_type_name (pspec->value_type),
326 value = g_value_get_double (&v2);
329 GET_AND_CHECK ("value", G_TYPE_DOUBLE, &value, done);
332 !g_strcmp0 (gst_structure_get_name (structure), "add-keyframe");
334 ret = gst_timed_value_control_source_set (source, timestamp, value);
336 ret = gst_timed_value_control_source_unset (source, timestamp);
340 g_error_new (GES_ERROR, 0,
341 "Could not %sset value for timestamp: %" GST_TIME_FORMAT,
342 setting_value ? "" : "un", GST_TIME_ARGS (timestamp));
344 ret = _ges_save_timeline_if_needed (timeline, structure, error);
347 gst_clear_object (&source);
348 gst_clear_object (&element);
349 g_free (property_name);
356 _ges_get_asset_from_timeline (GESTimeline * timeline, GType type,
357 const gchar * id, GError ** error)
360 GESProject *project = ges_timeline_get_project (timeline);
363 asset = ges_project_create_asset_sync (project, id, type, &err);
366 g_propagate_error (error, err);
367 if (!asset || (error && *error)) {
369 if (error && !*error) {
370 *error = g_error_new (GES_ERROR, 0,
371 "There was an error requesting the asset with id %s and type %s (%s)",
372 id, g_type_name (type), "unknown");
376 ("There was an error requesting the asset with id %s and type %s (%s)",
377 id, g_type_name (type), error ? (*error)->message : "unknown");
385 /* Unref after usage */
387 _ges_get_layer_by_priority (GESTimeline * timeline, gint priority)
391 GESLayer *layer = NULL;
393 priority = MAX (priority, 0);
394 layers = ges_timeline_get_layers (timeline);
395 nlayers = (gint) g_list_length (layers);
396 if (priority >= nlayers) {
399 while (i <= priority) {
400 layer = ges_timeline_append_layer (timeline);
405 layer = gst_object_ref (layer);
410 layer = ges_timeline_get_layer (timeline, priority);
413 g_list_free_full (layers, gst_object_unref);
419 ensure_uri (gchar * location)
421 if (gst_uri_is_valid (location))
422 return g_strdup (location);
424 return gst_filename_to_uri (location, NULL);
428 get_flags_from_string (GType type, const gchar * str_flags, guint * flags)
430 GValue value = G_VALUE_INIT;
431 g_value_init (&value, type);
433 if (!gst_value_deserialize (&value, str_flags)) {
434 g_value_unset (&value);
439 *flags = g_value_get_flags (&value);
440 g_value_unset (&value);
446 _ges_add_clip_from_struct (GESTimeline * timeline, GstStructure * structure,
449 GESAsset *asset = NULL;
450 GESLayer *layer = NULL;
455 const gchar *pattern;
456 const gchar *track_types_str;
457 const gchar *nested_timeline_id;
458 gchar *asset_id = NULL;
459 gchar *check_asset_id = NULL;
460 const gchar *type_string;
462 gboolean res = FALSE;
463 GESTrackType track_types = GES_TRACK_TYPE_UNKNOWN;
465 GESFrameNumber start_frame = GES_FRAME_NUMBER_NONE, inpoint_frame =
466 GES_FRAME_NUMBER_NONE, duration_frame = GES_FRAME_NUMBER_NONE;
467 GstClockTime duration = 1 * GST_SECOND, inpoint = 0, start =
470 const gchar *valid_fields[] =
471 { "asset-id", "pattern", "name", "layer-priority", "layer", "type",
472 "start", "inpoint", "duration", "text", "track-types", "project-uri",
476 FieldsError fields_error = { valid_fields, NULL };
478 if (!_check_fields (structure, fields_error, error))
481 GET_AND_CHECK ("asset-id", G_TYPE_STRING, &check_asset_id, beach);
483 TRY_GET_STRING ("pattern", &pattern, NULL);
484 TRY_GET_STRING ("text", &text, NULL);
485 TRY_GET_STRING ("name", &name, NULL);
486 TRY_GET ("layer-priority", G_TYPE_INT, &layer_priority, -1);
487 if (layer_priority == -1)
488 TRY_GET ("layer", G_TYPE_INT, &layer_priority, -1);
489 TRY_GET_STRING ("type", &type_string, "GESUriClip");
490 TRY_GET_TIME ("start", &start, &start_frame, GST_CLOCK_TIME_NONE);
491 TRY_GET_TIME ("inpoint", &inpoint, &inpoint_frame, 0);
492 TRY_GET_TIME ("duration", &duration, &duration_frame, GST_CLOCK_TIME_NONE);
493 TRY_GET_STRING ("track-types", &track_types_str, NULL);
494 TRY_GET_STRING ("project-uri", &nested_timeline_id, NULL);
496 if (track_types_str) {
497 if (!get_flags_from_string (GES_TYPE_TRACK_TYPE, track_types_str,
500 g_error_new (GES_ERROR, 0, "Invalid track types: %s",
506 if (!(type = g_type_from_name (type_string))) {
507 *error = g_error_new (GES_ERROR, 0, "This type doesn't exist : %s",
513 if (type == GES_TYPE_URI_CLIP) {
514 asset_id = ensure_uri (check_asset_id);
516 asset_id = g_strdup (check_asset_id);
519 gst_structure_set (structure, "asset-id", G_TYPE_STRING, asset_id, NULL);
520 asset = _ges_get_asset_from_timeline (timeline, type, asset_id, error);
527 if (layer_priority == -1) {
528 GESContainer *container;
530 container = g_object_get_qdata (G_OBJECT (timeline), LAST_CONTAINER_QDATA);
531 if (!container || !GES_IS_CLIP (container))
532 layer = _ges_get_layer_by_priority (timeline, 0);
534 layer = ges_clip_get_layer (GES_CLIP (container));
537 layer = _ges_get_layer_by_priority (timeline, 0);
539 layer = _ges_get_layer_by_priority (timeline, layer_priority);
544 g_error_new (GES_ERROR, 0, "No layer with priority %d", layer_priority);
548 if (GES_FRAME_NUMBER_IS_VALID (start_frame))
549 start = ges_timeline_get_frame_time (timeline, start_frame);
551 if (GES_FRAME_NUMBER_IS_VALID (inpoint_frame)) {
553 ges_clip_asset_get_frame_time (GES_CLIP_ASSET (asset), inpoint_frame);
554 if (!GST_CLOCK_TIME_IS_VALID (inpoint)) {
556 g_error_new (GES_ERROR, 0, "Could not get inpoint from frame %"
557 G_GINT64_FORMAT, inpoint_frame);
562 if (GES_FRAME_NUMBER_IS_VALID (duration_frame)) {
563 duration = ges_timeline_get_frame_time (timeline, duration_frame);
566 if (GES_IS_URI_CLIP_ASSET (asset) && !GST_CLOCK_TIME_IS_VALID (duration)) {
567 duration = GST_CLOCK_DIFF (inpoint,
568 ges_uri_clip_asset_get_duration (GES_URI_CLIP_ASSET (asset)));
571 clip = ges_layer_add_asset (layer, asset, start, inpoint, duration,
577 if (GES_TIMELINE_ELEMENT_DURATION (clip) == 0) {
578 *error = g_error_new (GES_ERROR, 0,
579 "Clip %s has 0 as duration, please provide a proper duration",
586 if (GES_IS_TEST_CLIP (clip)) {
588 GEnumClass *enum_class =
589 G_ENUM_CLASS (g_type_class_ref (GES_VIDEO_TEST_PATTERN_TYPE));
590 GEnumValue *value = g_enum_get_value_by_nick (enum_class, pattern);
597 ges_test_clip_set_vpattern (GES_TEST_CLIP (clip), value->value);
598 g_type_class_unref (enum_class);
602 if (GES_IS_TITLE_CLIP (clip) && text)
603 ges_timeline_element_set_child_properties (GES_TIMELINE_ELEMENT (clip),
607 && !ges_timeline_element_set_name (GES_TIMELINE_ELEMENT (clip), name)) {
610 g_error_new (GES_ERROR, 0, "couldn't set name %s on clip with id %s",
615 g_error_new (GES_ERROR, 0,
616 "Couldn't add clip with id %s to layer with priority %d", asset_id,
623 g_object_set_qdata (G_OBJECT (timeline), LAST_CONTAINER_QDATA, clip);
624 g_object_set_qdata (G_OBJECT (timeline), LAST_CHILD_QDATA, NULL);
627 res = _ges_save_timeline_if_needed (timeline, structure, error);
630 gst_clear_object (&layer);
631 gst_clear_object (&asset);
633 g_free (check_asset_id);
638 _ges_add_track_from_struct (GESTimeline * timeline,
639 GstStructure * structure, GError ** error)
645 const gchar *valid_fields[] = { "type", "restrictions", NULL };
647 FieldsError fields_error = { valid_fields, NULL };
649 if (!_check_fields (structure, fields_error, error))
652 ttype = gst_structure_get_string (structure, "type");
653 if (!g_strcmp0 (ttype, "video")) {
654 track = GES_TRACK (ges_video_track_new ());
655 } else if (!g_strcmp0 (ttype, "audio")) {
656 track = GES_TRACK (ges_audio_track_new ());
658 g_set_error (error, GES_ERROR, 0, "Unhandled track type: `%s`", ttype);
663 if (gst_structure_has_field (structure, "restrictions")) {
664 GstStructure *restriction_struct;
665 gchar *restriction_str;
667 if (gst_structure_get (structure, "restrictions", GST_TYPE_STRUCTURE,
668 &restriction_struct, NULL)) {
669 caps = gst_caps_new_full (restriction_struct, NULL);
670 } else if (gst_structure_get (structure, "restrictions", G_TYPE_STRING,
671 &restriction_str, NULL)) {
672 caps = gst_caps_from_string (restriction_str);
675 g_set_error (error, GES_ERROR, 0, "Invalid restrictions caps: %s",
678 g_free (restriction_str);
681 g_free (restriction_str);
682 } else if (!gst_structure_get (structure, "restrictions", GST_TYPE_CAPS,
684 gchar *tmp = gst_structure_to_string (structure);
686 g_set_error (error, GES_ERROR, 0, "Can't use restrictions caps from %s",
689 g_object_unref (track);
693 ges_track_set_restriction_caps (track, caps);
694 gst_caps_unref (caps);
697 return ges_timeline_add_track (timeline, track);
701 _ges_container_add_child_from_struct (GESTimeline * timeline,
702 GstStructure * structure, GError ** error)
704 GESAsset *asset = NULL;
705 GESContainer *container;
706 GESTimelineElement *child = NULL;
707 const gchar *container_name, *child_name, *child_type, *id;
710 const gchar *valid_fields[] = { "container-name", "asset-id", "inpoint",
711 "child-type", "child-name", "project-uri", NULL
714 FieldsError fields_error = { valid_fields, NULL };
716 if (!_check_fields (structure, fields_error, error))
719 container_name = gst_structure_get_string (structure, "container-name");
721 if (container_name == NULL) {
722 container = g_object_get_qdata (G_OBJECT (timeline), LAST_CONTAINER_QDATA);
725 GES_CONTAINER (ges_timeline_get_element (timeline, container_name));
728 if (!GES_IS_CONTAINER (container)) {
730 g_error_new (GES_ERROR, 0, "Could not find container: %s (%p)",
731 container_name, container);
737 id = gst_structure_get_string (structure, "asset-id");
738 child_type = gst_structure_get_string (structure, "child-type");
740 if (id && child_type) {
742 _ges_get_asset_from_timeline (timeline, g_type_from_name (child_type),
750 child = GES_TIMELINE_ELEMENT (ges_asset_extract (asset, NULL));
751 if (!GES_IS_TIMELINE_ELEMENT (child)) {
752 *error = g_error_new (GES_ERROR, 0, "Could not extract child element");
758 child_name = gst_structure_get_string (structure, "child-name");
759 if (!child && child_name) {
760 child = ges_timeline_get_element (timeline, child_name);
761 if (!GES_IS_TIMELINE_ELEMENT (child)) {
762 *error = g_error_new (GES_ERROR, 0, "Could not find child element");
770 g_error_new (GES_ERROR, 0, "Wrong parameters, could not get a child");
776 ges_timeline_element_set_name (child, child_name);
778 child_name = GES_TIMELINE_ELEMENT_NAME (child);
780 if (gst_structure_has_field (structure, "inpoint")) {
781 GstClockTime inpoint;
782 GESFrameNumber finpoint;
784 if (!GES_IS_TRACK_ELEMENT (child)) {
785 *error = g_error_new (GES_ERROR, 0, "Child %s is not a trackelement"
786 ", can't set inpoint.", child_name);
788 gst_object_unref (child);
793 if (!ges_util_structure_get_clocktime (structure, "inpoint", &inpoint,
795 *error = g_error_new (GES_ERROR, 0, "Could not use inpoint.");
796 gst_object_unref (child);
801 if (!ges_track_element_set_has_internal_source (GES_TRACK_ELEMENT (child),
804 g_error_new (GES_ERROR, 0,
805 "Could not set inpoint as %s can't have an internal source",
807 gst_object_unref (child);
812 if (GES_FRAME_NUMBER_IS_VALID (finpoint))
813 inpoint = ges_timeline_get_frame_time (timeline, finpoint);
815 ges_timeline_element_set_inpoint (child, inpoint);
819 res = ges_container_add (container, child);
821 g_error_new (GES_ERROR, 0, "Could not add child to container");
823 g_object_set_qdata (G_OBJECT (timeline), LAST_CHILD_QDATA, child);
825 res = _ges_save_timeline_if_needed (timeline, structure, error);
828 gst_clear_object (&asset);
833 _ges_set_child_property_from_struct (GESTimeline * timeline,
834 GstStructure * structure, GError ** error)
837 GValue prop_value = G_VALUE_INIT;
838 gboolean prop_value_set = FALSE;
839 gchar *property_name;
840 GESTimelineElement *element;
844 const gchar *valid_fields[] =
845 { "element-name", "property", "value", "project-uri", NULL };
847 FieldsError fields_error = { valid_fields, NULL };
849 if (!_check_fields (structure, fields_error, error))
852 GET_AND_CHECK ("property", G_TYPE_STRING, &property_name, err);
855 find_element_for_property (timeline, structure, &property_name, FALSE,
859 value = gst_structure_get_value (structure, "value");
861 if (G_VALUE_TYPE (value) == G_TYPE_STRING) {
863 if (ges_timeline_element_lookup_child (element, property_name, NULL,
865 GType p_type = pspec->value_type;
866 g_param_spec_unref (pspec);
867 if (p_type != G_TYPE_STRING) {
868 const gchar *val_string = g_value_get_string (value);
869 g_value_init (&prop_value, p_type);
870 if (!gst_value_deserialize (&prop_value, val_string)) {
871 *error = g_error_new (GES_ERROR, 0, "Could not set the property %s "
872 "because the value %s could not be deserialized to the %s type",
873 property_name, val_string, g_type_name (p_type));
876 prop_value_set = TRUE;
879 /* else, let the setter fail below */
882 if (!prop_value_set) {
883 g_value_init (&prop_value, G_VALUE_TYPE (value));
884 g_value_copy (value, &prop_value);
887 serialized = gst_value_serialize (&prop_value);
888 GST_INFO_OBJECT (element, "Setting property %s to %s\n", property_name,
892 res = ges_timeline_element_set_child_property (element, property_name,
894 g_value_unset (&prop_value);
898 ges_timeline_element_list_children_properties (element, &n_specs);
899 GString *errstr = g_string_new (NULL);
901 g_string_append_printf (errstr,
902 "\n Could not set property `%s` on `%s`, valid properties:\n",
903 property_name, GES_TIMELINE_ELEMENT_NAME (element));
905 for (i = 0; i < n_specs; i++)
906 g_string_append_printf (errstr, " - %s\n", specs[i]->name);
909 *error = g_error_new_literal (GES_ERROR, 0, errstr->str);
910 g_string_free (errstr, TRUE);
914 g_free (property_name);
915 return _ges_save_timeline_if_needed (timeline, structure, error);
918 g_free (property_name);