h264decoder: Enable low-latency bumping in case of pic_order_cnt_type 2
[platform/upstream/gstreamer.git] / subprojects / gst-editing-services / ges / ges-structured-interface.c
1 /* GStreamer Editing Services
2  *
3  * Copyright (C) <2015> Thibault Saunier <tsaunier@gnome.org>
4  *
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.
9  *
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.
14  *
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.
19  */
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "ges-structured-interface.h"
25 #include "ges-internal.h"
26
27 #include <string.h>
28
29
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")
32
33 #ifdef G_HAVE_ISO_VARARGS
34 #define REPORT_UNLESS(condition, errpoint, ...)                                \
35   G_STMT_START {                                                               \
36     if (!(condition)) {                                                        \
37       gchar *tmp = gst_info_strdup_printf(__VA_ARGS__);                            \
38       *error = g_error_new_literal (GES_ERROR, 0, tmp);                        \
39       g_free (tmp);                                                            \
40       goto errpoint;                                                           \
41     }                                                                          \
42   }                                                                            \
43   G_STMT_END
44 #else /* G_HAVE_GNUC_VARARGS */
45 #ifdef G_HAVE_GNUC_VARARGS
46 #define REPORT_UNLESS(condition, errpoint, args...)                            \
47   G_STMT_START {                                                               \
48     if (!(condition)) {                                                        \
49       gchar *tmp = gst_info_strdup_printf(##args);                            \
50       *error = g_error_new_literal (GES_ERROR, 0, tmp);                        \
51       g_free (tmp);                                                            \
52       goto errpoint;                                                           \
53     }                                                                          \
54   }                                                                            \
55   G_STMT_END
56 #endif /* G_HAVE_ISO_VARARGS */
57 #endif /* G_HAVE_GNUC_VARARGS */
58
59 #define GET_AND_CHECK(name,type,var,label) G_STMT_START {\
60   gboolean found = FALSE; \
61 \
62   if (type == GST_TYPE_CLOCK_TIME) {\
63     found = ges_util_structure_get_clocktime (structure,name, (GstClockTime*)var,NULL);\
64   }\
65   else { \
66     found = gst_structure_get (structure, name, type, var, NULL); \
67   }\
68   if (!found) {\
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); \
74     goto label;\
75   } \
76 } G_STMT_END
77
78 #define TRY_GET_STRING(name,var,def) G_STMT_START {\
79   *var = gst_structure_get_string (structure, name); \
80   if (*var == NULL) \
81     *var = def; \
82 } G_STMT_END
83
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)) { \
86       *var = def;                                          \
87       *var_frames = GES_FRAME_NUMBER_NONE;                            \
88   }                                                        \
89 } G_STMT_END
90
91 static gboolean
92 _get_structure_value (GstStructure * structure, const gchar * field, GType type,
93     gpointer v)
94 {
95   gboolean res = TRUE;
96   const gchar *value_str;
97   const GValue *value;
98   GValue nvalue = G_VALUE_INIT;
99
100   if (gst_structure_get (structure, field, type, v, NULL))
101     return res;
102
103   g_value_init (&nvalue, type);
104   value = gst_structure_get_value (structure, field);
105   if (!value)
106     goto fail;
107
108   if (g_value_transform (value, &nvalue))
109     goto set_and_get_value;
110
111   if (!G_VALUE_HOLDS_STRING (value))
112     goto fail;
113
114   value_str = g_value_get_string (value);
115   if (!gst_value_deserialize (&nvalue, value_str))
116     goto done;
117
118 set_and_get_value:
119   gst_structure_set_value (structure, field, &nvalue);
120   gst_structure_get (structure, field, type, v, NULL);
121
122 done:
123   g_value_reset (&nvalue);
124   return res;
125
126 fail:
127   res = FALSE;
128   goto done;
129 }
130
131 #define TRY_GET(name, type, var, def) G_STMT_START {\
132   g_assert (type != GST_TYPE_CLOCK_TIME);                      \
133   if (!_get_structure_value (structure, name, type, var))\
134     *var = def;                                             \
135 } G_STMT_END
136
137 typedef struct
138 {
139   const gchar **fields;
140   GList *invalid_fields;
141 } FieldsError;
142
143 static gboolean
144 enum_from_str (GType type, const gchar * str_enum, guint * enum_value)
145 {
146   GValue value = G_VALUE_INIT;
147   g_value_init (&value, type);
148
149   if (!gst_value_deserialize (&value, str_enum))
150     return FALSE;
151
152   *enum_value = g_value_get_enum (&value);
153   g_value_unset (&value);
154
155   return TRUE;
156 }
157
158 static gboolean
159 _check_field (GQuark field_id, const GValue * value, FieldsError * fields_error)
160 {
161   guint i;
162   const gchar *field = g_quark_to_string (field_id);
163
164   for (i = 0; fields_error->fields[i]; i++) {
165     if (g_strcmp0 (fields_error->fields[i], field) == 0) {
166
167       return TRUE;
168     }
169   }
170
171   fields_error->invalid_fields =
172       g_list_append (fields_error->invalid_fields, (gpointer) field);
173
174   return TRUE;
175 }
176
177 static gboolean
178 _check_fields (GstStructure * structure, FieldsError fields_error,
179     GError ** error)
180 {
181   gst_structure_foreach (structure,
182       (GstStructureForeachFunc) _check_field, &fields_error);
183
184   if (fields_error.invalid_fields) {
185     GList *tmp;
186     const gchar *struct_name = gst_structure_get_name (structure);
187     GString *msg = g_string_new (NULL);
188
189     g_string_append_printf (msg, "Unknown propert%s in %s%s:",
190         g_list_length (fields_error.invalid_fields) > 1 ? "ies" : "y",
191         strlen (struct_name) > 1 ? "--" : "-",
192         gst_structure_get_name (structure));
193
194     for (tmp = fields_error.invalid_fields; tmp; tmp = tmp->next)
195       g_string_append_printf (msg, " %s", (gchar *) tmp->data);
196
197     if (error)
198       *error = g_error_new_literal (GES_ERROR, 0, msg->str);
199
200     g_string_free (msg, TRUE);
201
202     return FALSE;
203   }
204
205   return TRUE;
206 }
207
208 static GESTimelineElement *
209 find_element_for_property (GESTimeline * timeline, GstStructure * structure,
210     gchar ** property_name, gboolean require_track_element, GError ** error)
211 {
212   GList *tmp;
213   const gchar *element_name;
214   GESTimelineElement *element;
215
216   element_name = gst_structure_get_string (structure, "element-name");
217   if (element_name == NULL) {
218     element = g_object_get_qdata (G_OBJECT (timeline), LAST_CHILD_QDATA);
219     if (element)
220       gst_object_ref (element);
221   } else {
222     element = ges_timeline_get_element (timeline, element_name);
223   }
224
225   if (*property_name == NULL) {
226     gchar *tmpstr = *property_name;
227     const gchar *name = gst_structure_get_name (structure);
228
229     REPORT_UNLESS (g_str_has_prefix (name, "set-"), err,
230         "Could not find any property name in %" GST_PTR_FORMAT, structure);
231
232     *property_name = g_strdup (&tmpstr[4]);
233
234     g_free (tmpstr);
235   }
236
237   if (element) {
238     if (!ges_timeline_element_lookup_child (element,
239             *property_name, NULL, NULL)) {
240       gst_clear_object (&element);
241     }
242   }
243
244   if (!element) {
245     element = g_object_get_qdata (G_OBJECT (timeline), LAST_CONTAINER_QDATA);
246     if (element)
247       gst_object_ref (element);
248   }
249
250   REPORT_UNLESS (GES_IS_TIMELINE_ELEMENT (element), err,
251       "Could not find child %s from %" GST_PTR_FORMAT, element_name, structure);
252
253   if (!require_track_element || GES_IS_TRACK_ELEMENT (element))
254     return element;
255
256
257   REPORT_UNLESS (GES_IS_CONTAINER (element), err,
258       "Could not find child %s from %" GST_PTR_FORMAT, element_name, structure);
259
260   for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
261     if (ges_timeline_element_lookup_child (tmp->data, *property_name, NULL,
262             NULL)) {
263       gst_object_replace ((GstObject **) & element, tmp->data);
264
265       break;
266     }
267   }
268
269   REPORT_UNLESS (GES_IS_TRACK_ELEMENT (element), err,
270       "Could not find TrackElement from %" GST_PTR_FORMAT, structure);
271
272   return element;
273
274 err:
275   g_clear_object (&element);
276   return element;
277 }
278
279 gboolean
280 _ges_save_timeline_if_needed (GESTimeline * timeline, GstStructure * structure,
281     GError ** error)
282 {
283   gboolean res = TRUE;
284   const gchar *nested_timeline_id =
285       gst_structure_get_string (structure, "project-uri");
286
287   if (nested_timeline_id) {
288     res = ges_timeline_save_to_uri (timeline, nested_timeline_id, NULL, TRUE,
289         error);
290   }
291
292   return res;
293 }
294
295 typedef struct
296 {
297   GstTimedValueControlSource *source;
298   GstStructure *structure;
299   GError *error;
300   const gchar *property_name;
301   gboolean res;
302 } SetKeyframesData;
303
304 static gboolean
305 un_set_keyframes_foreach (GQuark field_id, const GValue * value,
306     SetKeyframesData * d)
307 {
308   GValue v = G_VALUE_INIT;
309   GError **error = &d->error;
310   gchar *tmp;
311   gint i;
312   const gchar *valid_fields[] = {
313     "element-name", "property-name", "value", "timestamp", "project-uri",
314     "binding-type", "source-type", "interpolation-mode", "interpolation-mode",
315     NULL
316   };
317   const gchar *field = g_quark_to_string (field_id);
318   gdouble ts;
319
320   for (i = 0; valid_fields[i]; i++) {
321     if (g_quark_from_string (valid_fields[i]) == field_id)
322       return TRUE;
323   }
324
325   errno = 0;
326   ts = g_strtod (field, &tmp);
327
328   REPORT_UNLESS (errno == 0 && field != tmp, err,
329       "Could not convert `%s` to GstClockTime (%s)", field, g_strerror (errno));
330
331   if (gst_structure_has_name (d->structure, "remove-keyframe")) {
332     REPORT_UNLESS (gst_timed_value_control_source_unset (d->source,
333             ts * GST_SECOND), err, "Could not unset keyframe at %f", ts);
334
335     return TRUE;
336   }
337
338   g_value_init (&v, G_TYPE_DOUBLE);
339   REPORT_UNLESS (g_value_transform (value, &v), err,
340       "Could not convert keyframe %f value %s to double", ts,
341       gst_value_serialize (value));
342
343   REPORT_UNLESS (gst_timed_value_control_source_set (d->source, ts * GST_SECOND,
344           g_value_get_double (&v)), err, "Could not set keyframe %f=%f", ts,
345       g_value_get_double (&v));
346
347   g_value_reset (&v);
348   return TRUE;
349
350 err:
351   if (v.g_type)
352     g_value_reset (&v);
353   d->res = FALSE;
354   return FALSE;
355 }
356
357
358 gboolean
359 _ges_add_remove_keyframe_from_struct (GESTimeline * timeline,
360     GstStructure * structure, GError ** error)
361 {
362   GESTimelineElement *element = NULL;
363
364   gboolean absolute;
365   gdouble value;
366   GstClockTime timestamp;
367   GstControlBinding *binding = NULL;
368   GstTimedValueControlSource *source = NULL;
369   gchar *property_name = NULL;
370
371   gboolean ret = FALSE;
372   gboolean setting_value;
373
374   const gchar *valid_fields[] =
375       { "element-name", "property-name", "value", "timestamp", "project-uri",
376     NULL
377   };
378
379   FieldsError fields_error = { valid_fields, NULL };
380
381   if (gst_structure_has_field (structure, "value")) {
382     if (!_check_fields (structure, fields_error, error))
383       return FALSE;
384     GET_AND_CHECK ("timestamp", GST_TYPE_CLOCK_TIME, &timestamp, done);
385   } else {
386     REPORT_UNLESS (!gst_structure_has_field (structure, "timestamp"), done,
387         "Doesn't have a `value` field in %" GST_PTR_FORMAT
388         " but has a `timestamp`" " that can't work!", structure);
389   }
390
391   GET_AND_CHECK ("property-name", G_TYPE_STRING, &property_name, done);
392   if (!(element =
393           find_element_for_property (timeline, structure, &property_name, TRUE,
394               error)))
395     goto done;
396
397   REPORT_UNLESS (binding =
398       ges_track_element_get_control_binding (GES_TRACK_ELEMENT (element),
399           property_name),
400       done, "No control binding found for %" GST_PTR_FORMAT, structure);
401
402   g_object_get (binding, "control-source", &source, NULL);
403   REPORT_UNLESS (source, done,
404       "No control source found for '%" GST_PTR_FORMAT
405       "' you should first set-control-binding on it", structure);
406   REPORT_UNLESS (GST_IS_TIMED_VALUE_CONTROL_SOURCE (source), done,
407       "You can use add-keyframe"
408       " only on GstTimedValueControlSource not %s",
409       G_OBJECT_TYPE_NAME (source));
410
411   if (!gst_structure_has_field (structure, "value")) {
412     SetKeyframesData d = {
413       source, structure, NULL, property_name, TRUE,
414     };
415     gst_structure_foreach (structure,
416         (GstStructureForeachFunc) un_set_keyframes_foreach, &d);
417     if (!d.res)
418       g_propagate_error (error, d.error);
419
420     return d.res;
421   }
422
423   g_object_get (binding, "absolute", &absolute, NULL);
424   if (absolute) {
425     GParamSpec *pspec;
426     const GValue *v;
427     GValue v2 = G_VALUE_INIT;
428
429     if (!ges_timeline_element_lookup_child (element, property_name, NULL,
430             &pspec)) {
431       *error =
432           g_error_new (GES_ERROR, 0, "Could not get property %s for %s",
433           property_name, GES_TIMELINE_ELEMENT_NAME (element));
434       goto done;
435     }
436
437     v = gst_structure_get_value (structure, "value");
438     if (!v) {
439       gchar *struct_str = gst_structure_to_string (structure);
440
441       *error = g_error_new (GES_ERROR, 0,
442           "Could not get the mandatory field 'value'"
443           " of type %s - fields in %s", g_type_name (pspec->value_type),
444           struct_str);
445       g_free (struct_str);
446       goto done;
447     }
448
449     g_value_init (&v2, G_TYPE_DOUBLE);
450     if (!g_value_transform (v, &v2)) {
451       gchar *struct_str = gst_structure_to_string (structure);
452
453       *error = g_error_new (GES_ERROR, 0,
454           "Could not get the mandatory field 'value'"
455           " of type %s - fields in %s", g_type_name (pspec->value_type),
456           struct_str);
457       g_free (struct_str);
458       goto done;
459     }
460     value = g_value_get_double (&v2);
461     g_value_reset (&v2);
462   } else
463     GET_AND_CHECK ("value", G_TYPE_DOUBLE, &value, done);
464
465   setting_value =
466       !g_strcmp0 (gst_structure_get_name (structure), "add-keyframe");
467   if (setting_value)
468     ret = gst_timed_value_control_source_set (source, timestamp, value);
469   else
470     ret = gst_timed_value_control_source_unset (source, timestamp);
471
472   if (!ret) {
473     *error =
474         g_error_new (GES_ERROR, 0,
475         "Could not %sset value for timestamp: %" GST_TIME_FORMAT,
476         setting_value ? "" : "un", GST_TIME_ARGS (timestamp));
477   }
478   ret = _ges_save_timeline_if_needed (timeline, structure, error);
479
480 done:
481   gst_clear_object (&source);
482   gst_clear_object (&element);
483   g_free (property_name);
484
485   return ret;
486
487 }
488
489 GESAsset *
490 _ges_get_asset_from_timeline (GESTimeline * timeline, GType type,
491     const gchar * id, GError ** error)
492 {
493   GESAsset *asset;
494   GESProject *project = ges_timeline_get_project (timeline);
495   GError *err = NULL;
496
497   asset = ges_project_create_asset_sync (project, id, type, &err);
498
499   if (err)
500     g_propagate_error (error, err);
501   if (!asset || (error && *error)) {
502
503     if (error && !*error) {
504       *error = g_error_new (GES_ERROR, 0,
505           "There was an error requesting the asset with id %s and type %s (%s)",
506           id, g_type_name (type), "unknown");
507     }
508
509     GST_ERROR
510         ("There was an error requesting the asset with id %s and type %s (%s)",
511         id, g_type_name (type), error ? (*error)->message : "unknown");
512
513     return NULL;
514   }
515
516   return asset;
517 }
518
519 /* Unref after usage */
520 GESLayer *
521 _ges_get_layer_by_priority (GESTimeline * timeline, gint priority)
522 {
523   GList *layers;
524   gint nlayers;
525   GESLayer *layer = NULL;
526
527   priority = MAX (priority, 0);
528   layers = ges_timeline_get_layers (timeline);
529   nlayers = (gint) g_list_length (layers);
530   if (priority >= nlayers) {
531     gint i = nlayers;
532
533     while (i <= priority) {
534       layer = ges_timeline_append_layer (timeline);
535
536       i++;
537     }
538
539     layer = gst_object_ref (layer);
540
541     goto done;
542   }
543
544   layer = ges_timeline_get_layer (timeline, priority);
545
546 done:
547   g_list_free_full (layers, gst_object_unref);
548
549   return layer;
550 }
551
552 static gchar *
553 ensure_uri (gchar * location)
554 {
555   if (gst_uri_is_valid (location))
556     return g_strdup (location);
557   else
558     return gst_filename_to_uri (location, NULL);
559 }
560
561 static gboolean
562 get_flags_from_string (GType type, const gchar * str_flags, guint * flags)
563 {
564   GValue value = G_VALUE_INIT;
565   g_value_init (&value, type);
566
567   if (!gst_value_deserialize (&value, str_flags)) {
568     g_value_unset (&value);
569
570     return FALSE;
571   }
572
573   *flags = g_value_get_flags (&value);
574   g_value_unset (&value);
575
576   return TRUE;
577 }
578
579 gboolean
580 _ges_add_clip_from_struct (GESTimeline * timeline, GstStructure * structure,
581     GError ** error)
582 {
583   GESAsset *asset = NULL;
584   GESLayer *layer = NULL;
585   GESClip *clip;
586   gint layer_priority;
587   const gchar *name;
588   const gchar *text;
589   const gchar *pattern;
590   const gchar *track_types_str;
591   const gchar *nested_timeline_id;
592   gchar *asset_id = NULL;
593   gchar *check_asset_id = NULL;
594   const gchar *type_string;
595   GType type;
596   gboolean res = FALSE;
597   GESTrackType track_types = GES_TRACK_TYPE_UNKNOWN;
598
599   GESFrameNumber start_frame = GES_FRAME_NUMBER_NONE, inpoint_frame =
600       GES_FRAME_NUMBER_NONE, duration_frame = GES_FRAME_NUMBER_NONE;
601   GstClockTime duration = 1 * GST_SECOND, inpoint = 0, start =
602       GST_CLOCK_TIME_NONE;
603
604   const gchar *valid_fields[] =
605       { "asset-id", "pattern", "name", "layer-priority", "layer", "type",
606     "start", "inpoint", "duration", "text", "track-types", "project-uri",
607     NULL
608   };
609
610   FieldsError fields_error = { valid_fields, NULL };
611
612   if (!_check_fields (structure, fields_error, error))
613     return FALSE;
614
615   GET_AND_CHECK ("asset-id", G_TYPE_STRING, &check_asset_id, beach);
616
617   TRY_GET_STRING ("pattern", &pattern, NULL);
618   TRY_GET_STRING ("text", &text, NULL);
619   TRY_GET_STRING ("name", &name, NULL);
620   TRY_GET ("layer-priority", G_TYPE_INT, &layer_priority, -1);
621   if (layer_priority == -1)
622     TRY_GET ("layer", G_TYPE_INT, &layer_priority, -1);
623   TRY_GET_STRING ("type", &type_string, "GESUriClip");
624   TRY_GET_TIME ("start", &start, &start_frame, GST_CLOCK_TIME_NONE);
625   TRY_GET_TIME ("inpoint", &inpoint, &inpoint_frame, 0);
626   TRY_GET_TIME ("duration", &duration, &duration_frame, GST_CLOCK_TIME_NONE);
627   TRY_GET_STRING ("track-types", &track_types_str, NULL);
628   TRY_GET_STRING ("project-uri", &nested_timeline_id, NULL);
629
630   if (track_types_str) {
631     if (!get_flags_from_string (GES_TYPE_TRACK_TYPE, track_types_str,
632             &track_types)) {
633       *error =
634           g_error_new (GES_ERROR, 0, "Invalid track types: %s",
635           track_types_str);
636     }
637
638   }
639
640   if (!(type = g_type_from_name (type_string))) {
641     *error = g_error_new (GES_ERROR, 0, "This type doesn't exist : %s",
642         type_string);
643
644     goto beach;
645   }
646
647   if (type == GES_TYPE_URI_CLIP) {
648     asset_id = ensure_uri (check_asset_id);
649   } else {
650     asset_id = g_strdup (check_asset_id);
651   }
652
653   gst_structure_set (structure, "asset-id", G_TYPE_STRING, asset_id, NULL);
654   asset = _ges_get_asset_from_timeline (timeline, type, asset_id, error);
655   if (!asset) {
656     res = FALSE;
657
658     goto beach;
659   }
660
661   if (layer_priority == -1) {
662     GESContainer *container;
663
664     container = g_object_get_qdata (G_OBJECT (timeline), LAST_CONTAINER_QDATA);
665     if (!container || !GES_IS_CLIP (container))
666       layer = _ges_get_layer_by_priority (timeline, 0);
667     else
668       layer = ges_clip_get_layer (GES_CLIP (container));
669
670     if (!layer)
671       layer = _ges_get_layer_by_priority (timeline, 0);
672   } else {
673     layer = _ges_get_layer_by_priority (timeline, layer_priority);
674   }
675
676   if (!layer) {
677     *error =
678         g_error_new (GES_ERROR, 0, "No layer with priority %d", layer_priority);
679     goto beach;
680   }
681
682   if (GES_FRAME_NUMBER_IS_VALID (start_frame))
683     start = ges_timeline_get_frame_time (timeline, start_frame);
684
685   if (GES_FRAME_NUMBER_IS_VALID (inpoint_frame)) {
686     inpoint =
687         ges_clip_asset_get_frame_time (GES_CLIP_ASSET (asset), inpoint_frame);
688     if (!GST_CLOCK_TIME_IS_VALID (inpoint)) {
689       *error =
690           g_error_new (GES_ERROR, 0, "Could not get inpoint from frame %"
691           G_GINT64_FORMAT, inpoint_frame);
692       goto beach;
693     }
694   }
695
696   if (GES_FRAME_NUMBER_IS_VALID (duration_frame)) {
697     duration = ges_timeline_get_frame_time (timeline, duration_frame);
698   }
699
700   if (GES_IS_URI_CLIP_ASSET (asset) && !GST_CLOCK_TIME_IS_VALID (duration)) {
701     duration = GST_CLOCK_DIFF (inpoint,
702         ges_uri_clip_asset_get_duration (GES_URI_CLIP_ASSET (asset)));
703   }
704
705   clip = ges_layer_add_asset (layer, asset, start, inpoint, duration,
706       track_types);
707
708   if (clip) {
709     res = TRUE;
710
711     if (GES_TIMELINE_ELEMENT_DURATION (clip) == 0) {
712       *error = g_error_new (GES_ERROR, 0,
713           "Clip %s has 0 as duration, please provide a proper duration",
714           asset_id);
715       res = FALSE;
716       goto beach;
717     }
718
719
720     if (GES_IS_TEST_CLIP (clip)) {
721       if (pattern) {
722         guint v;
723
724         REPORT_UNLESS (enum_from_str (GES_VIDEO_TEST_PATTERN_TYPE, pattern, &v),
725             beach, "Invalid pattern: %s", pattern);
726         ges_test_clip_set_vpattern (GES_TEST_CLIP (clip), v);
727       }
728     }
729
730     if (GES_IS_TITLE_CLIP (clip) && text)
731       ges_timeline_element_set_child_properties (GES_TIMELINE_ELEMENT (clip),
732           "text", text, NULL);
733
734     if (name
735         && !ges_timeline_element_set_name (GES_TIMELINE_ELEMENT (clip), name)) {
736       res = FALSE;
737       *error =
738           g_error_new (GES_ERROR, 0, "couldn't set name %s on clip with id %s",
739           name, asset_id);
740     }
741   } else {
742     *error =
743         g_error_new (GES_ERROR, 0,
744         "Couldn't add clip with id %s to layer with priority %d", asset_id,
745         layer_priority);
746     res = FALSE;
747     goto beach;
748   }
749
750   if (res) {
751     g_object_set_qdata (G_OBJECT (timeline), LAST_CONTAINER_QDATA, clip);
752     g_object_set_qdata (G_OBJECT (timeline), LAST_CHILD_QDATA, NULL);
753   }
754
755   res = _ges_save_timeline_if_needed (timeline, structure, error);
756
757 beach:
758   gst_clear_object (&layer);
759   gst_clear_object (&asset);
760   g_free (asset_id);
761   g_free (check_asset_id);
762   return res;
763 }
764
765 gboolean
766 _ges_add_track_from_struct (GESTimeline * timeline,
767     GstStructure * structure, GError ** error)
768 {
769   const gchar *ttype;
770   GESTrack *track;
771   GstCaps *caps;
772
773   const gchar *valid_fields[] = { "type", "restrictions", NULL };
774
775   FieldsError fields_error = { valid_fields, NULL };
776
777   if (!_check_fields (structure, fields_error, error))
778     return FALSE;
779
780   ttype = gst_structure_get_string (structure, "type");
781   if (!g_strcmp0 (ttype, "video")) {
782     track = GES_TRACK (ges_video_track_new ());
783   } else if (!g_strcmp0 (ttype, "audio")) {
784     track = GES_TRACK (ges_audio_track_new ());
785   } else {
786     g_set_error (error, GES_ERROR, 0, "Unhandled track type: `%s`", ttype);
787
788     return FALSE;
789   }
790
791   if (gst_structure_has_field (structure, "restrictions")) {
792     GstStructure *restriction_struct;
793     gchar *restriction_str;
794
795     if (gst_structure_get (structure, "restrictions", GST_TYPE_STRUCTURE,
796             &restriction_struct, NULL)) {
797       caps = gst_caps_new_full (restriction_struct, NULL);
798     } else if (gst_structure_get (structure, "restrictions", G_TYPE_STRING,
799             &restriction_str, NULL)) {
800       caps = gst_caps_from_string (restriction_str);
801
802       if (!caps) {
803         g_set_error (error, GES_ERROR, 0, "Invalid restrictions caps: %s",
804             restriction_str);
805
806         g_free (restriction_str);
807         return FALSE;
808       }
809       g_free (restriction_str);
810     } else if (!gst_structure_get (structure, "restrictions", GST_TYPE_CAPS,
811             &caps, NULL)) {
812       gchar *tmp = gst_structure_to_string (structure);
813
814       g_set_error (error, GES_ERROR, 0, "Can't use restrictions caps from %s",
815           tmp);
816
817       g_object_unref (track);
818       return FALSE;
819     }
820
821     ges_track_set_restriction_caps (track, caps);
822     gst_caps_unref (caps);
823   }
824
825   return ges_timeline_add_track (timeline, track);
826 }
827
828 gboolean
829 _ges_container_add_child_from_struct (GESTimeline * timeline,
830     GstStructure * structure, GError ** error)
831 {
832   GESAsset *asset = NULL;
833   GESContainer *container;
834   GESTimelineElement *child = NULL;
835   const gchar *container_name, *child_name, *child_type, *id;
836
837   gboolean res = TRUE;
838   const gchar *valid_fields[] = { "container-name", "asset-id", "inpoint",
839     "child-type", "child-name", "project-uri", NULL
840   };
841
842   FieldsError fields_error = { valid_fields, NULL };
843
844   if (!_check_fields (structure, fields_error, error))
845     return FALSE;
846
847   container_name = gst_structure_get_string (structure, "container-name");
848
849   if (container_name == NULL) {
850     container = g_object_get_qdata (G_OBJECT (timeline), LAST_CONTAINER_QDATA);
851   } else {
852     container =
853         GES_CONTAINER (ges_timeline_get_element (timeline, container_name));
854   }
855
856   if (!GES_IS_CONTAINER (container)) {
857     *error =
858         g_error_new (GES_ERROR, 0, "Could not find container: %s (%p)",
859         container_name, container);
860
861     res = FALSE;
862     goto beach;
863   }
864
865   id = gst_structure_get_string (structure, "asset-id");
866   child_type = gst_structure_get_string (structure, "child-type");
867
868   if (id && child_type) {
869     asset =
870         _ges_get_asset_from_timeline (timeline, g_type_from_name (child_type),
871         id, error);
872
873     if (asset == NULL) {
874       res = FALSE;
875       goto beach;
876     }
877
878     child = GES_TIMELINE_ELEMENT (ges_asset_extract (asset, NULL));
879     if (!GES_IS_TIMELINE_ELEMENT (child)) {
880       *error = g_error_new (GES_ERROR, 0, "Could not extract child element");
881
882       goto beach;
883     }
884   }
885
886   child_name = gst_structure_get_string (structure, "child-name");
887   if (!child && child_name) {
888     child = ges_timeline_get_element (timeline, child_name);
889     if (!GES_IS_TIMELINE_ELEMENT (child)) {
890       *error = g_error_new (GES_ERROR, 0, "Could not find child element");
891
892       goto beach;
893     }
894   }
895
896   if (!child) {
897     *error =
898         g_error_new (GES_ERROR, 0, "Wrong parameters, could not get a child");
899
900     return FALSE;
901   }
902
903   if (child_name)
904     ges_timeline_element_set_name (child, child_name);
905   else
906     child_name = GES_TIMELINE_ELEMENT_NAME (child);
907
908   if (gst_structure_has_field (structure, "inpoint")) {
909     GstClockTime inpoint;
910     GESFrameNumber finpoint;
911
912     if (!GES_IS_TRACK_ELEMENT (child)) {
913       *error = g_error_new (GES_ERROR, 0, "Child %s is not a trackelement"
914           ", can't set inpoint.", child_name);
915
916       gst_object_unref (child);
917
918       goto beach;
919     }
920
921     if (!ges_util_structure_get_clocktime (structure, "inpoint", &inpoint,
922             &finpoint)) {
923       *error = g_error_new (GES_ERROR, 0, "Could not use inpoint.");
924       gst_object_unref (child);
925
926       goto beach;
927     }
928
929     if (!ges_track_element_set_has_internal_source (GES_TRACK_ELEMENT (child),
930             TRUE)) {
931       *error =
932           g_error_new (GES_ERROR, 0,
933           "Could not set inpoint as %s can't have an internal source",
934           child_name);
935       gst_object_unref (child);
936
937       goto beach;
938     }
939
940     if (GES_FRAME_NUMBER_IS_VALID (finpoint))
941       inpoint = ges_timeline_get_frame_time (timeline, finpoint);
942
943     ges_timeline_element_set_inpoint (child, inpoint);
944
945   }
946
947   res = ges_container_add (container, child);
948   if (res == FALSE) {
949     g_error_new (GES_ERROR, 0, "Could not add child to container");
950   } else {
951     g_object_set_qdata (G_OBJECT (timeline), LAST_CHILD_QDATA, child);
952   }
953   res = _ges_save_timeline_if_needed (timeline, structure, error);
954
955 beach:
956   gst_clear_object (&asset);
957   return res;
958 }
959
960 gboolean
961 _ges_set_child_property_from_struct (GESTimeline * timeline,
962     GstStructure * structure, GError ** error)
963 {
964   const GValue *value;
965   GValue prop_value = G_VALUE_INIT;
966   gboolean prop_value_set = FALSE;
967   gchar *property_name;
968   GESTimelineElement *element;
969   gchar *serialized;
970   gboolean res;
971
972   const gchar *valid_fields[] =
973       { "element-name", "property", "value", "project-uri", NULL };
974
975   FieldsError fields_error = { valid_fields, NULL };
976
977   if (!_check_fields (structure, fields_error, error))
978     return FALSE;
979
980   GET_AND_CHECK ("property", G_TYPE_STRING, &property_name, err);
981
982   if (!(element =
983           find_element_for_property (timeline, structure, &property_name, FALSE,
984               error)))
985     goto err;
986
987   value = gst_structure_get_value (structure, "value");
988
989   if (G_VALUE_TYPE (value) == G_TYPE_STRING) {
990     GParamSpec *pspec;
991     if (ges_timeline_element_lookup_child (element, property_name, NULL,
992             &pspec)) {
993       GType p_type = pspec->value_type;
994       g_param_spec_unref (pspec);
995       if (p_type != G_TYPE_STRING) {
996         const gchar *val_string = g_value_get_string (value);
997         g_value_init (&prop_value, p_type);
998         if (!gst_value_deserialize (&prop_value, val_string)) {
999           *error = g_error_new (GES_ERROR, 0, "Could not set the property %s "
1000               "because the value %s could not be deserialized to the %s type",
1001               property_name, val_string, g_type_name (p_type));
1002           return FALSE;
1003         }
1004         prop_value_set = TRUE;
1005       }
1006     }
1007     /* else, let the setter fail below */
1008   }
1009
1010   if (!prop_value_set) {
1011     g_value_init (&prop_value, G_VALUE_TYPE (value));
1012     g_value_copy (value, &prop_value);
1013   }
1014
1015   serialized = gst_value_serialize (&prop_value);
1016   GST_INFO_OBJECT (element, "Setting property %s to %s\n", property_name,
1017       serialized);
1018   g_free (serialized);
1019
1020   res = ges_timeline_element_set_child_property (element, property_name,
1021       &prop_value);
1022   g_value_unset (&prop_value);
1023   if (!res) {
1024     guint n_specs, i;
1025     GParamSpec **specs =
1026         ges_timeline_element_list_children_properties (element, &n_specs);
1027     GString *errstr = g_string_new (NULL);
1028
1029     g_string_append_printf (errstr,
1030         "\n  Could not set property `%s` on `%s`, valid properties:\n",
1031         property_name, GES_TIMELINE_ELEMENT_NAME (element));
1032
1033     for (i = 0; i < n_specs; i++)
1034       g_string_append_printf (errstr, "    - %s\n", specs[i]->name);
1035     g_free (specs);
1036
1037     *error = g_error_new_literal (GES_ERROR, 0, errstr->str);
1038     g_string_free (errstr, TRUE);
1039
1040     return FALSE;
1041   }
1042   g_free (property_name);
1043   return _ges_save_timeline_if_needed (timeline, structure, error);
1044
1045 err:
1046   g_free (property_name);
1047   return FALSE;
1048 }
1049
1050 gboolean
1051 _ges_set_control_source_from_struct (GESTimeline * timeline,
1052     GstStructure * structure, GError ** error)
1053 {
1054   guint mode;
1055   gboolean res = FALSE;
1056   GESTimelineElement *element = NULL;
1057
1058   GstControlSource *source = NULL;
1059   gchar *property_name, *binding_type = NULL,
1060       *source_type = NULL, *interpolation_mode = NULL;
1061
1062   GET_AND_CHECK ("property-name", G_TYPE_STRING, &property_name, beach);
1063
1064   if (!(element =
1065           find_element_for_property (timeline, structure, &property_name, TRUE,
1066               error)))
1067     goto beach;
1068
1069   if (GES_IS_CLIP (element)) {
1070     GList *tmp;
1071     for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
1072       if (ges_timeline_element_lookup_child (tmp->data, property_name, NULL,
1073               NULL)) {
1074         gst_object_replace ((GstObject **) & element, tmp->data);
1075
1076         break;
1077       }
1078     }
1079   }
1080
1081   REPORT_UNLESS (GES_IS_TRACK_ELEMENT (element), beach,
1082       "Could not find TrackElement from %" GST_PTR_FORMAT, structure);
1083
1084   TRY_GET ("binding-type", G_TYPE_STRING, &binding_type, NULL);
1085   TRY_GET ("source-type", G_TYPE_STRING, &source_type, NULL);
1086   TRY_GET ("interpolation-mode", G_TYPE_STRING, &interpolation_mode, NULL);
1087
1088   if (!binding_type)
1089     binding_type = g_strdup ("direct");
1090
1091   REPORT_UNLESS (source_type == NULL
1092       || !g_strcmp0 (source_type, "interpolation"), beach,
1093       "Interpolation type %s not supported", source_type);
1094   source = gst_interpolation_control_source_new ();
1095
1096   if (interpolation_mode)
1097     REPORT_UNLESS (enum_from_str (GST_TYPE_INTERPOLATION_MODE,
1098             interpolation_mode, &mode), beach,
1099         "Wrong interpolation mode: %s", interpolation_mode);
1100   else
1101     mode = GST_INTERPOLATION_MODE_LINEAR;
1102
1103   g_object_set (source, "mode", mode, NULL);
1104
1105   res = ges_track_element_set_control_source (GES_TRACK_ELEMENT (element),
1106       source, property_name, binding_type);
1107
1108 beach:
1109   gst_clear_object (&element);
1110   gst_clear_object (&source);
1111   g_free (property_name);
1112   g_free (binding_type);
1113   g_free (source_type);
1114   g_free (interpolation_mode);
1115
1116   return res;
1117 }
1118
1119 #undef GET_AND_CHECK
1120 #undef TRY_GET