completion: Update to new gstreamer core helpers
[platform/upstream/gstreamer.git] / ges / ges-validate.c
1 /* GStreamer Editing Services
2  *
3  * Copyright (C) <2014> Thibault Saunier <thibault.saunier@collabora.com>
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
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <ges/ges.h>
26
27 #ifdef HAVE_GST_VALIDATE
28 #include <gst/validate/validate.h>
29 #include <gst/validate/gst-validate-scenario.h>
30 #include <gst/validate/gst-validate-utils.h>
31 #include "ges-internal.h"
32 #include "ges-structured-interface.h"
33
34 #define MONITOR_ON_PIPELINE "validate-monitor"
35 #define RUNNER_ON_PIPELINE "runner-monitor"
36
37 static GESTimeline *
38 get_timeline (GstValidateScenario * scenario)
39 {
40   GESTimeline *timeline;
41
42   g_object_get (scenario->pipeline, "timeline", &timeline, NULL);
43
44   return timeline;
45 }
46
47 static gboolean
48 _serialize_project (GstValidateScenario * scenario, GstValidateAction * action)
49 {
50   const gchar *uri = gst_structure_get_string (action->structure, "uri");
51   GESTimeline *timeline = get_timeline (scenario);
52   gboolean res;
53
54   gst_validate_printf (action, "Saving project to %s", uri);
55
56   res = ges_timeline_save_to_uri (timeline, uri, NULL, TRUE, NULL);
57
58   g_object_unref (timeline);
59   return res;
60 }
61
62 static gboolean
63 _remove_asset (GstValidateScenario * scenario, GstValidateAction * action)
64 {
65   const gchar *id = NULL;
66   const gchar *type_string = NULL;
67   GType type;
68   GESTimeline *timeline = get_timeline (scenario);
69   GESProject *project = ges_timeline_get_project (timeline);
70   GESAsset *asset;
71   gboolean res = FALSE;
72
73   id = gst_structure_get_string (action->structure, "id");
74   type_string = gst_structure_get_string (action->structure, "type");
75
76   if (!type_string || !id) {
77     GST_ERROR ("Missing parameters, we got type %s and id %s", type_string, id);
78     goto beach;
79   }
80
81   if (!(type = g_type_from_name (type_string))) {
82     GST_ERROR ("This type doesn't exist : %s", type_string);
83     goto beach;
84   }
85
86   asset = ges_project_get_asset (project, id, type);
87
88   if (!asset) {
89     GST_ERROR ("No asset with id %s and type %s", id, type_string);
90     goto beach;
91   }
92
93   res = ges_project_remove_asset (project, asset);
94
95 beach:
96   g_object_unref (timeline);
97   return res;
98 }
99
100 static gboolean
101 _add_asset (GstValidateScenario * scenario, GstValidateAction * action)
102 {
103   const gchar *id = NULL;
104   const gchar *type_string = NULL;
105   GType type;
106   GESTimeline *timeline = get_timeline (scenario);
107   GESProject *project = ges_timeline_get_project (timeline);
108   GESAsset *asset;
109   gboolean res = FALSE;
110
111   id = gst_structure_get_string (action->structure, "id");
112   type_string = gst_structure_get_string (action->structure, "type");
113
114   gst_validate_printf (action, "Adding asset of type %s with ID %s\n",
115       id, type_string);
116
117   if (!type_string || !id) {
118     GST_ERROR ("Missing parameters, we got type %s and id %s", type_string, id);
119     goto beach;
120   }
121
122   if (!(type = g_type_from_name (type_string))) {
123     GST_ERROR ("This type doesn't exist : %s", type_string);
124     goto beach;
125   }
126
127   asset = _ges_get_asset_from_timeline (timeline, type, id, NULL);
128
129   if (!asset) {
130     res = FALSE;
131
132     goto beach;
133   }
134
135   res = ges_project_add_asset (project, asset);
136
137 beach:
138   g_object_unref (timeline);
139   return res;
140 }
141
142 static gboolean
143 _add_layer (GstValidateScenario * scenario, GstValidateAction * action)
144 {
145   GESTimeline *timeline = get_timeline (scenario);
146   GESLayer *layer;
147   gint priority;
148   gboolean res = TRUE, auto_transition = FALSE;
149
150   if (!gst_structure_get_int (action->structure, "priority", &priority)) {
151     GST_ERROR ("priority is needed when adding a layer");
152     goto failed;
153   }
154
155   gst_validate_printf (action, "Adding layer with priority %d\n", priority);
156   layer = _ges_get_layer_by_priority (timeline, priority);
157
158   gst_structure_get_boolean (action->structure, "auto-transition",
159       &auto_transition);
160   g_object_set (layer, "priority", priority, "auto-transition", auto_transition,
161       NULL);
162
163
164 beach:
165   g_object_unref (timeline);
166   return res;
167
168 failed:
169   goto beach;
170 }
171
172 static gboolean
173 _remove_layer (GstValidateScenario * scenario, GstValidateAction * action)
174 {
175   GESTimeline *timeline = get_timeline (scenario);
176   GESLayer *layer;
177   gint priority;
178   gboolean res = FALSE;
179
180   if (!gst_structure_get_int (action->structure, "priority", &priority)) {
181     GST_ERROR ("priority is needed when removing a layer");
182     goto beach;
183   }
184
185   layer = _ges_get_layer_by_priority (timeline, priority);
186
187   if (layer) {
188     res = ges_timeline_remove_layer (timeline, layer);
189     gst_object_unref (layer);
190   } else {
191     GST_ERROR ("No layer with priority %d", priority);
192   }
193
194 beach:
195   g_object_unref (timeline);
196   return res;
197 }
198
199 static gboolean
200 _remove_clip (GstValidateScenario * scenario, GstValidateAction * action)
201 {
202   GESTimeline *timeline = get_timeline (scenario);
203   GESTimelineElement *clip;
204   GESLayer *layer;
205   const gchar *name;
206   gboolean res = FALSE;
207
208   name = gst_structure_get_string (action->structure, "name");
209   clip = ges_timeline_get_element (timeline, name);
210   g_return_val_if_fail (GES_IS_CLIP (clip), FALSE);
211
212   gst_validate_printf (action, "removing clip with ID %s\n", name);
213   layer = ges_clip_get_layer (GES_CLIP (clip));
214
215   if (layer) {
216     res = ges_layer_remove_clip (layer, GES_CLIP (clip));
217     gst_object_unref (layer);
218   } else {
219     GST_ERROR ("No layer for clip %s", ges_timeline_element_get_name (clip));
220   }
221
222   g_object_unref (timeline);
223   return res;
224 }
225
226
227 static gboolean
228 _edit_container (GstValidateScenario * scenario, GstValidateAction * action)
229 {
230   GList *layers = NULL;
231   GESTimeline *timeline;
232   GESTimelineElement *container;
233   GstClockTime position;
234   gboolean res = FALSE;
235
236   gint new_layer_priority = -1;
237   guint edge = GES_EDGE_NONE;
238   guint mode = GES_EDIT_MODE_NORMAL;
239
240   const gchar *edit_mode_str = NULL, *edge_str = NULL;
241   const gchar *clip_name;
242
243   clip_name = gst_structure_get_string (action->structure, "container-name");
244
245   timeline = get_timeline (scenario);
246   g_return_val_if_fail (timeline, FALSE);
247
248   container = ges_timeline_get_element (timeline, clip_name);
249   g_return_val_if_fail (GES_IS_CONTAINER (container), FALSE);
250
251   if (!gst_validate_action_get_clocktime (scenario, action,
252           "position", &position)) {
253     GST_WARNING ("Could not get position");
254     goto beach;
255   }
256
257   if ((edit_mode_str =
258           gst_structure_get_string (action->structure, "edit-mode")))
259     g_return_val_if_fail (gst_validate_utils_enum_from_str (GES_TYPE_EDIT_MODE,
260             edit_mode_str, &mode), FALSE);
261
262   if ((edge_str = gst_structure_get_string (action->structure, "edge")))
263     g_return_val_if_fail (gst_validate_utils_enum_from_str (GES_TYPE_EDGE,
264             edge_str, &edge), FALSE);
265
266   gst_structure_get_int (action->structure, "new-layer-priority",
267       &new_layer_priority);
268
269   gst_validate_printf (action, "Editing %s to %" GST_TIME_FORMAT
270       " in %s mode, edge: %s "
271       "with new layer prio: %d \n\n",
272       clip_name, GST_TIME_ARGS (position),
273       edit_mode_str ? edit_mode_str : "normal",
274       edge_str ? edge_str : "None", new_layer_priority);
275
276   if (!(res = ges_container_edit (GES_CONTAINER (container), layers,
277               new_layer_priority, mode, edge, position))) {
278     gst_object_unref (container);
279     GST_ERROR ("HERE");
280     goto beach;
281   }
282   gst_object_unref (container);
283
284 beach:
285   g_object_unref (timeline);
286   return res;
287 }
288
289
290 static void
291 _commit_done_cb (GstBus * bus, GstMessage * message, GstValidateAction * action)
292 {
293   gst_validate_action_set_done (action);
294
295   g_signal_handlers_disconnect_by_func (bus, _commit_done_cb, action);
296 }
297
298 static gboolean
299 _commit (GstValidateScenario * scenario, GstValidateAction * action)
300 {
301   GESTimeline *timeline = get_timeline (scenario);
302   GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (scenario->pipeline));
303   GstState state;
304
305   gst_validate_printf (action, "Commiting timeline %s\n",
306       GST_OBJECT_NAME (timeline));
307
308   g_signal_connect (bus, "message::async-done", G_CALLBACK (_commit_done_cb),
309       action);
310
311   gst_element_get_state (scenario->pipeline, &state, NULL, 0);
312   if (!ges_timeline_commit (timeline) || state < GST_STATE_PAUSED) {
313     g_signal_handlers_disconnect_by_func (bus, G_CALLBACK (_commit_done_cb),
314         action);
315     gst_object_unref (timeline);
316     gst_object_unref (bus);
317
318     return TRUE;
319   }
320   gst_object_unref (bus);
321   gst_object_unref (timeline);
322
323   return GST_VALIDATE_EXECUTE_ACTION_ASYNC;
324 }
325
326 static gboolean
327 _split_clip (GstValidateScenario * scenario, GstValidateAction * action)
328 {
329   GESTimeline *timeline;
330   const gchar *clip_name;
331   GESTimelineElement *element;
332   GstClockTime position;
333
334   clip_name = gst_structure_get_string (action->structure, "clip-name");
335
336   timeline = get_timeline (scenario);
337   g_return_val_if_fail (timeline, FALSE);
338
339   element = ges_timeline_get_element (timeline, clip_name);
340   g_return_val_if_fail (GES_IS_CLIP (element), FALSE);
341   g_object_unref (timeline);
342
343   g_return_val_if_fail (gst_validate_action_get_clocktime (scenario, action,
344           "position", &position), FALSE);
345
346   return (ges_clip_split (GES_CLIP (element), position) != NULL);
347 }
348
349 static gboolean
350 _set_track_restriction_caps (GstValidateScenario * scenario,
351     GstValidateAction * action)
352 {
353   GList *tmp;
354   GstCaps *caps;
355   gboolean res = FALSE;
356   GESTrackType track_types;
357
358   GESTimeline *timeline = get_timeline (scenario);
359   const gchar *track_type_str =
360       gst_structure_get_string (action->structure, "track-type");
361   const gchar *caps_str = gst_structure_get_string (action->structure, "caps");
362
363   g_return_val_if_fail ((track_types =
364           gst_validate_utils_flags_from_str (GES_TYPE_TRACK_TYPE,
365               track_type_str)), FALSE);
366
367   g_return_val_if_fail ((caps =
368           gst_caps_from_string (caps_str)) != NULL, FALSE);
369
370   timeline = get_timeline (scenario);
371
372   for (tmp = timeline->tracks; tmp; tmp = tmp->next) {
373     GESTrack *track = tmp->data;
374
375     if (track->type & track_types) {
376       gchar *str;
377
378       str = gst_caps_to_string (caps);
379       gst_validate_printf (action, "Setting restriction caps %s on track: %s\n",
380           str, GST_ELEMENT_NAME (track));
381       g_free (str);
382
383       ges_track_set_restriction_caps (track, caps);
384
385       res = TRUE;
386     }
387   }
388   gst_caps_unref (caps);
389   gst_object_unref (timeline);
390
391   return res;
392 }
393
394 static gboolean
395 _set_asset_on_element (GstValidateScenario * scenario,
396     GstValidateAction * action)
397 {
398   GESAsset *asset;
399   GESTimelineElement *element;
400   const gchar *element_name, *id;
401
402   gboolean res = TRUE;
403   GESTimeline *timeline = get_timeline (scenario);
404
405   element_name = gst_structure_get_string (action->structure, "element-name");
406   element = ges_timeline_get_element (timeline, element_name);
407   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (element), FALSE);
408
409   id = gst_structure_get_string (action->structure, "asset-id");
410
411   gst_validate_printf (action, "Setting asset %s on element %s\n",
412       id, element_name);
413
414   asset = _ges_get_asset_from_timeline (timeline, G_OBJECT_TYPE (element), id,
415       NULL);
416   if (asset == NULL) {
417     res = FALSE;
418     GST_ERROR ("Could not find asset: %s", id);
419     goto beach;
420   }
421
422   res = ges_extractable_set_asset (GES_EXTRACTABLE (element), asset);
423
424 beach:
425   gst_object_unref (timeline);
426
427   return res;
428 }
429
430 static gboolean
431 _container_remove_child (GstValidateScenario * scenario,
432     GstValidateAction * action)
433 {
434   GESContainer *container;
435   GESTimelineElement *child;
436   const gchar *container_name, *child_name;
437
438   gboolean res = TRUE;
439   GESTimeline *timeline = get_timeline (scenario);
440
441   container_name =
442       gst_structure_get_string (action->structure, "container-name");
443   container =
444       GES_CONTAINER (ges_timeline_get_element (timeline, container_name));
445   g_return_val_if_fail (GES_IS_CONTAINER (container), FALSE);
446
447   child_name = gst_structure_get_string (action->structure, "child-name");
448   child = ges_timeline_get_element (timeline, child_name);
449   g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (child), FALSE);
450
451   gst_validate_printf (action, "Remove child %s from container %s\n",
452       child_name, GES_TIMELINE_ELEMENT_NAME (container));
453
454   res = ges_container_remove (container, child);
455
456   gst_object_unref (timeline);
457
458   return res;
459 }
460
461 static gboolean
462 _set_control_source (GstValidateScenario * scenario, GstValidateAction * action)
463 {
464   GESTrackElement *element;
465
466   gboolean ret = FALSE;
467   GstControlSource *source = NULL;
468   gchar *element_name, *property_name, *binding_type = NULL,
469       *source_type = NULL, *interpolation_mode = NULL;
470
471   GESTimeline *timeline = get_timeline (scenario);
472
473   g_return_val_if_fail (gst_structure_get (action->structure,
474           "element-name", G_TYPE_STRING, &element_name,
475           "property-name", G_TYPE_STRING, &property_name,
476           "binding-type", G_TYPE_STRING, &binding_type,
477           "source-type", G_TYPE_STRING, &source_type,
478           "interpolation-mode", G_TYPE_STRING, &interpolation_mode, NULL),
479       FALSE);
480
481   element =
482       GES_TRACK_ELEMENT (ges_timeline_get_element (timeline, element_name));
483
484   g_return_val_if_fail (GES_IS_TRACK_ELEMENT (element), FALSE);
485
486   if (!binding_type)
487     binding_type = g_strdup ("direct");
488
489   if (source_type == NULL || !g_strcmp0 (source_type, "interpolation")) {
490     guint mode;
491
492     source = gst_interpolation_control_source_new ();
493
494     if (interpolation_mode)
495       g_return_val_if_fail (gst_validate_utils_enum_from_str
496           (GST_TYPE_INTERPOLATION_MODE, interpolation_mode, &mode), FALSE);
497     else
498       mode = GST_INTERPOLATION_MODE_LINEAR;
499
500     g_object_set (source, "mode", mode, NULL);
501
502   } else {
503     GST_ERROR_OBJECT (scenario, "Interpolation type %s not supported",
504         source_type);
505
506     goto done;
507   }
508
509   gst_validate_printf (action, "Setting control source on %s:%s\n",
510       element_name, property_name);
511   ret = ges_track_element_set_control_source (element,
512       source, property_name, binding_type);
513
514
515 done:
516   gst_object_unref (timeline);
517   g_free (element_name);
518   g_free (binding_type);
519   g_free (source_type);
520   g_free (interpolation_mode);
521
522   return ret;
523 }
524
525 static gboolean
526 _validate_action_execute (GstValidateScenario * scenario,
527     GstValidateAction * action)
528 {
529   GError *err = NULL;
530   GESTimeline *timeline = get_timeline (scenario);
531   ActionFromStructureFunc func;
532
533   if (gst_structure_has_name (action->structure, "add-keyframe") ||
534       gst_structure_has_name (action->structure, "remove-keyframe")) {
535     func = _ges_add_remove_keyframe_from_struct;
536   } else if (gst_structure_has_name (action->structure, "add-clip")) {
537     func = _ges_add_clip_from_struct;
538   } else if (gst_structure_has_name (action->structure, "container-add-child")) {
539     func = _ges_container_add_child_from_struct;
540   } else if (gst_structure_has_name (action->structure, "set-child-property")) {
541     func = _ges_set_child_property_from_struct;
542   } else {
543     g_assert_not_reached ();
544   }
545
546   if (!func (timeline, action->structure, &err)) {
547     GST_VALIDATE_REPORT (scenario,
548         g_quark_from_string ("scenario::execution-error"),
549         "Could not execute %s (error: %s)",
550         gst_structure_get_name (action->structure),
551         err ? err->message : "None");
552
553     g_clear_error (&err);
554
555     return TRUE;
556   }
557
558   gst_object_unref (timeline);
559
560   return TRUE;
561 }
562
563 static void
564 _project_loaded_cb (GESProject * project, GESTimeline * timeline,
565     GstValidateAction * action)
566 {
567   gst_validate_action_set_done (action);
568 }
569
570 static gboolean
571 _load_project (GstValidateScenario * scenario, GstValidateAction * action)
572 {
573   GESProject *project;
574   GList *tmp, *tmp_full;
575
576   gchar *uri = NULL;
577   GError *error = NULL;
578   const gchar *content = NULL;
579
580   gchar *tmpfile = g_strdup_printf ("%s%s%s", g_get_tmp_dir (),
581       G_DIR_SEPARATOR_S, "tmpxgesload.xges");
582
583   GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_ASYNC;
584   GESTimeline *timeline = get_timeline (scenario);
585
586   gst_validate_printf (action, "Loading project from serialized content\n");
587
588   if (!GES_IS_PIPELINE (scenario->pipeline)) {
589     GST_VALIDATE_REPORT (scenario,
590         g_quark_from_string ("scenario::execution-error"),
591         "Not a GES pipeline, can't work with it");
592
593     goto fail;
594   }
595
596   content = gst_structure_get_string (action->structure, "serialized-content");
597
598   g_file_set_contents (tmpfile, content, -1, &error);
599   if (error) {
600     GST_VALIDATE_REPORT (scenario,
601         g_quark_from_string ("scenario::execution-error"),
602         "Could not set XML content: %s", error->message);
603
604     goto fail;
605   }
606
607   uri = gst_filename_to_uri (tmpfile, &error);
608   if (error) {
609     GST_VALIDATE_REPORT (scenario,
610         g_quark_from_string ("scenario::execution-error"),
611         "Could not set filename to URI: %s", error->message);
612
613     goto fail;
614   }
615
616   tmp_full = ges_timeline_get_layers (timeline);
617   for (tmp = tmp_full; tmp; tmp = tmp->next)
618     ges_timeline_remove_layer (timeline, tmp->data);
619   g_list_free_full (tmp_full, gst_object_unref);
620
621   tmp_full = ges_timeline_get_tracks (timeline);
622   for (tmp = tmp_full; tmp; tmp = tmp->next)
623     ges_timeline_remove_track (timeline, tmp->data);
624   g_list_free_full (tmp_full, gst_object_unref);
625
626   project = ges_project_new (uri);
627   g_signal_connect (project, "loaded", G_CALLBACK (_project_loaded_cb), action);
628   ges_project_load (project, timeline, &error);
629   if (error) {
630     GST_VALIDATE_REPORT (scenario,
631         g_quark_from_string ("scenario::execution-error"),
632         "Could not load timeline: %s", error->message);
633
634     goto fail;
635   }
636
637 done:
638   if (error)
639     g_error_free (error);
640
641   if (uri)
642     g_free (uri);
643
644   g_free (tmpfile);
645
646   return res;
647
648 fail:
649
650   /* We reported the issue ourself, so do not ask GstValidate
651    * to do that for us */
652   res = GST_VALIDATE_EXECUTE_ACTION_OK;
653
654   goto done;
655
656 }
657
658 #endif
659
660 gboolean
661 ges_validate_register_action_types (void)
662 {
663 #ifdef HAVE_GST_VALIDATE
664   gst_validate_init ();
665
666   /*  *INDENT-OFF* */
667   gst_validate_register_action_type ("edit-container", "ges", _edit_container,
668       (GstValidateActionParameter [])  {
669         {
670          .name = "container-name",
671          .description = "The name of the GESContainer to edit",
672          .mandatory = TRUE,
673          .types = "string",
674         },
675         {
676           .name = "position",
677           .description = "The new position of the GESContainer",
678           .mandatory = TRUE,
679           .types = "double or string",
680           .possible_variables = "position: The current position in the stream\n"
681             "duration: The duration of the stream",
682            NULL
683         },
684         {
685           .name = "edit-mode",
686           .description = "The GESEditMode to use to edit @container-name",
687           .mandatory = FALSE,
688           .types = "string",
689           .def = "normal",
690         },
691         {
692           .name = "edge",
693           .description = "The GESEdge to use to edit @container-name\n"
694                          "should be in [ edge_start, edge_end, edge_none ] ",
695           .mandatory = FALSE,
696           .types = "string",
697           .def = "edge_none",
698         },
699         {
700           .name = "new-layer-priority",
701           .description = "The priority of the layer @container should land in.\n"
702                          "If the layer you're trying to move the container to doesn't exist, it will\n"
703                          "be created automatically. -1 means no move.",
704           .mandatory = FALSE,
705           .types = "int",
706           .def = "-1",
707         },
708         {NULL}
709        },
710        "Allows to edit a container (like a GESClip), for more details, have a look at:\n"
711        "ges_container_edit documentation, Note that the timeline will\n"
712        "be commited, and flushed so that the edition is taken into account",
713        GST_VALIDATE_ACTION_TYPE_NONE);
714
715   gst_validate_register_action_type ("add-asset", "ges", _add_asset,
716       (GstValidateActionParameter [])  {
717         {
718           .name = "id",
719           .description = "Adds an asset to a project.",
720           .mandatory = TRUE,
721           NULL
722         },
723         {
724           .name = "type",
725           .description = "The type of asset to add",
726           .mandatory = TRUE,
727           NULL
728         },
729         {NULL}
730       },
731       "Allows to add an asset to the current project", GST_VALIDATE_ACTION_TYPE_NONE);
732
733   gst_validate_register_action_type ("remove-asset", "ges", _remove_asset,
734       (GstValidateActionParameter [])  {
735         {
736           .name = "id",
737           .description = "The ID of the clip to remove",
738           .mandatory = TRUE,
739           NULL
740         },
741         {
742           .name = "type",
743           .description = "The type of asset to remove",
744           .mandatory = TRUE,
745           NULL
746         },
747         { NULL }
748       },
749       "Allows to remove an asset from the current project", GST_VALIDATE_ACTION_TYPE_NONE);
750
751   gst_validate_register_action_type ("add-layer", "ges", _add_layer,
752       (GstValidateActionParameter [])  {
753         {
754           .name = "priority",
755           .description = "The priority of the new layer to add,"
756                          "if not specified, the new layer will be"
757                          " appended to the timeline",
758           .mandatory = FALSE,
759           NULL
760         },
761         { NULL }
762       },
763       "Allows to add a layer to the current timeline", GST_VALIDATE_ACTION_TYPE_NONE);
764
765   gst_validate_register_action_type ("remove-layer", "ges", _remove_layer,
766       (GstValidateActionParameter [])  {
767         {
768           .name = "priority",
769           .description = "The priority of the layer to remove",
770           .mandatory = TRUE,
771           NULL
772         },
773         {
774           .name = "auto-transition",
775           .description = "Wheter auto-transition is activated on the new layer.",
776           .mandatory = FALSE,
777           .types="boolean",
778           .def = "False"
779         },
780         { NULL }
781       },
782       "Allows to remove a layer from the current timeline", GST_VALIDATE_ACTION_TYPE_NONE);
783
784   gst_validate_register_action_type ("add-clip", "ges", _validate_action_execute,
785       (GstValidateActionParameter []) {
786         {
787           .name = "name",
788           .description = "The name of the clip to add",
789           .types = "string",
790           .mandatory = TRUE,
791         },
792         {
793           .name = "layer-priority",
794           .description = "The priority of the clip to add",
795           .types = "int",
796           .mandatory = TRUE,
797         },
798         {
799           .name = "asset-id",
800           .description = "The id of the asset from which to extract the clip",
801           .types = "string",
802           .mandatory = TRUE,
803         },
804         {
805           .name = "type",
806           .description = "The type of the clip to create",
807           .types = "string",
808           .mandatory = TRUE,
809         },
810         {
811           .name = "start",
812           .description = "The start value to set on the new GESClip.",
813           .types = "double or string",
814           .mandatory = FALSE,
815         },
816         {
817           .name = "inpoint",
818           .description = "The  inpoint value to set on the new GESClip",
819           .types = "double or string",
820           .mandatory = FALSE,
821         },
822         {
823           .name = "duration",
824           .description = "The  duration value to set on the new GESClip",
825           .types = "double or string",
826           .mandatory = FALSE,
827         },
828         {NULL}
829       }, "Allows to add a clip to a given layer", GST_VALIDATE_ACTION_TYPE_NONE);
830
831   gst_validate_register_action_type ("remove-clip", "ges", _remove_clip,
832       (GstValidateActionParameter []) {
833         {
834           .name = "name",
835           .description = "The name of the clip to remove",
836           .types = "string",
837           .mandatory = TRUE,
838         },
839         {NULL}
840       }, "Allows to remove a clip from a given layer", GST_VALIDATE_ACTION_TYPE_NONE);
841
842   gst_validate_register_action_type ("serialize-project", "ges", _serialize_project,
843       (GstValidateActionParameter []) {
844         {
845           .name = "uri",
846           .description = "The uri where to store the serialized project",
847           .types = "string",
848           .mandatory = TRUE,
849         },
850         {NULL}
851       }, "serializes a project", GST_VALIDATE_ACTION_TYPE_NONE);
852
853   gst_validate_register_action_type ("set-child-property", "ges", _validate_action_execute,
854       (GstValidateActionParameter []) {
855         {
856           .name = "element-name",
857           .description = "The name of the element on which to modify the property",
858           .types = "string",
859           .mandatory = TRUE,
860         },
861         {
862           .name = "property",
863           .description = "The name of the property to modify",
864           .types = "string",
865           .mandatory = TRUE,
866         },
867         {
868           .name = "value",
869           .description = "The value of the property",
870           .types = "gvalue",
871           .mandatory = TRUE,
872         },
873         {NULL}
874       }, "Allows to change child property of an object", GST_VALIDATE_ACTION_TYPE_NONE);
875
876   gst_validate_register_action_type ("split-clip", "ges", _split_clip,
877       (GstValidateActionParameter []) {
878         {
879           .name = "clip-name",
880           .description = "The name of the clip to split",
881           .types = "string",
882           .mandatory = TRUE,
883         },
884         {
885           .name = "position",
886           .description = "The position at which to split the clip",
887           .types = "double or string",
888           .mandatory = TRUE,
889         },
890         {NULL}
891       }, "Split a clip at a specified position.", GST_VALIDATE_ACTION_TYPE_NONE);
892
893   gst_validate_register_action_type ("set-track-restriction-caps", "ges", _set_track_restriction_caps,
894       (GstValidateActionParameter []) {
895         {
896           .name = "track-type",
897           .description = "The type of track to set restriction caps on",
898           .types = "string",
899           .mandatory = TRUE,
900         },
901         {
902           .name = "caps",
903           .description = "The caps to set on the track",
904           .types = "string",
905           .mandatory = TRUE,
906         },
907         {NULL}
908       }, "Sets restriction caps on tracks of a specific type.", GST_VALIDATE_ACTION_TYPE_NONE);
909
910   gst_validate_register_action_type ("element-set-asset", "ges", _set_asset_on_element,
911       (GstValidateActionParameter []) {
912         {
913           .name = "element-name",
914           .description = "The name of the TimelineElement to set an asset on",
915           .types = "string",
916           .mandatory = TRUE,
917         },
918         {
919           .name = "asset-id",
920           .description = "The id of the asset from which to extract the clip",
921           .types = "string",
922           .mandatory = TRUE,
923         },
924         {NULL}
925       }, "Sets restriction caps on tracks of a specific type.", GST_VALIDATE_ACTION_TYPE_NONE);
926
927
928   gst_validate_register_action_type ("container-add-child", "ges", _validate_action_execute,
929       (GstValidateActionParameter []) {
930         {
931           .name = "container-name",
932           .description = "The name of the GESContainer to add a child to",
933           .types = "string",
934           .mandatory = TRUE,
935         },
936         {
937           .name = "child-name",
938           .description = "The name of the child to add to @container-name",
939           .types = "string",
940           .mandatory = FALSE,
941           .def = "NULL"
942         },
943         {
944           .name = "asset-id",
945           .description = "The id of the asset from which to extract the child",
946           .types = "string",
947           .mandatory = TRUE,
948           .def = "NULL"
949         },
950         {
951           .name = "child-type",
952           .description = "The type of the child to create",
953           .types = "string",
954           .mandatory = FALSE,
955           .def = "NULL"
956         },
957         {NULL}
958       }, "Add a child to @container-name. If asset-id and child-type are specified,"
959        " the child will be created and added. Otherwize @child-name has to be specified"
960        " and will be added to the container.", GST_VALIDATE_ACTION_TYPE_NONE);
961
962   gst_validate_register_action_type ("container-remove-child", "ges", _container_remove_child,
963       (GstValidateActionParameter []) {
964         {
965           .name = "container-name",
966           .description = "The name of the GESContainer to remove a child from",
967           .types = "string",
968           .mandatory = TRUE,
969         },
970         {
971           .name = "child-name",
972           .description = "The name of the child to reomve from @container-name",
973           .types = "string",
974           .mandatory = TRUE,
975         },
976         {NULL}
977       }, "Remove a child from @container-name.", FALSE);
978
979   gst_validate_register_action_type ("set-control-source", "ges", _set_control_source,
980       (GstValidateActionParameter []) {
981         {
982           .name = "element-name",
983           .description = "The name of the GESTrackElement to set the control source on",
984           .types = "string",
985           .mandatory = TRUE,
986         },
987         {
988           .name = "property-name",
989           .description = "The name of the property for which to set a control source",
990           .types = "string",
991           .mandatory = TRUE,
992         },
993         {
994           .name = "binding-type",
995           .description = "The name of the type of binding to use",
996           .types = "string",
997           .mandatory = FALSE,
998           .def = "direct",
999         },
1000         {
1001           .name = "source-type",
1002           .description = "The name of the type of ControlSource to use",
1003           .types = "string",
1004           .mandatory = FALSE,
1005           .def = "interpolation",
1006         },
1007         {
1008           .name = "interpolation-mode",
1009           .description = "The name of the GstInterpolationMode to on the source",
1010           .types = "string",
1011           .mandatory = FALSE,
1012           .def = "linear",
1013         },
1014         {NULL}
1015       }, "Adds a GstControlSource on @element-name::@property-name"
1016          " allowing you to then add keyframes on that property.", GST_VALIDATE_ACTION_TYPE_NONE);
1017
1018   gst_validate_register_action_type ("add-keyframe", "ges", _validate_action_execute,
1019       (GstValidateActionParameter []) {
1020         {
1021           .name = "element-name",
1022           .description = "The name of the GESTrackElement to add a keyframe on",
1023           .types = "string",
1024           .mandatory = TRUE,
1025         },
1026         {
1027           .name = "property-name",
1028           .description = "The name of the property for which to add a keyframe on",
1029           .types = "string",
1030           .mandatory = TRUE,
1031         },
1032         {
1033           .name = "timestamp",
1034           .description = "The timestamp of the keyframe",
1035           .types = "string or float",
1036           .mandatory = TRUE,
1037         },
1038         {
1039           .name = "value",
1040           .description = "The value of the keyframe",
1041           .types = "float",
1042           .mandatory = TRUE,
1043         },
1044         {NULL}
1045       }, "Remove a child from @container-name.", GST_VALIDATE_ACTION_TYPE_NONE);
1046
1047   gst_validate_register_action_type ("remove-keyframe", "ges", _validate_action_execute,
1048       (GstValidateActionParameter []) {
1049         {
1050           .name = "element-name",
1051           .description = "The name of the GESTrackElement to add a keyframe on",
1052           .types = "string",
1053           .mandatory = TRUE,
1054         },
1055         {
1056           .name = "property-name",
1057           .description = "The name of the property for which to add a keyframe on",
1058           .types = "string",
1059           .mandatory = TRUE,
1060         },
1061         {
1062           .name = "timestamp",
1063           .description = "The timestamp of the keyframe",
1064           .types = "string or float",
1065           .mandatory = TRUE,
1066         },
1067         {NULL}
1068       }, "Remove a child from @container-name.", GST_VALIDATE_ACTION_TYPE_NONE);
1069
1070   gst_validate_register_action_type ("load-project", "ges", _load_project,
1071       (GstValidateActionParameter [])  {
1072         {
1073           .name = "serialized-content",
1074           .description = "The full content of the XML describing project in XGES formet.",
1075           .mandatory = TRUE,
1076           NULL
1077         },
1078         {NULL}
1079       },
1080       "Loads a project either from its content passed in the serialized-content field.\n"
1081       "Note that it will completely clean the previous timeline",
1082       GST_VALIDATE_ACTION_TYPE_NONE);
1083
1084
1085   gst_validate_register_action_type ("commit", "ges", _commit, NULL,
1086        "Commit the timeline.", GST_VALIDATE_ACTION_TYPE_ASYNC);
1087   /*  *INDENT-ON* */
1088
1089   return TRUE;
1090 #else
1091   return FALSE;
1092 #endif
1093 }