--- /dev/null
+/* GStreamer Editing Services
+ *
+ * Copyright (C) <2015> Thibault Saunier <tsaunier@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include "ges-structured-interface.h"
+
+
+gboolean
+_ges_add_remove_keyframe_from_struct (GESTimeline * timeline,
+ GstStructure * structure, GError ** error)
+{
+ GESTrackElement *element;
+
+ gdouble value;
+ GstClockTime timestamp;
+ GstControlBinding *binding = NULL;
+ GstTimedValueControlSource *source = NULL;
+ gchar *element_name = NULL, *property_name = NULL;
+
+ gboolean ret = FALSE;
+
+
+ if (!gst_structure_get (structure,
+ "element-name", G_TYPE_STRING, &element_name,
+ "property-name", G_TYPE_STRING, &property_name,
+ "value", G_TYPE_DOUBLE, &value,
+ "timestamp", GST_TYPE_CLOCK_TIME, ×tamp, NULL)) {
+ *error = g_error_new (GES_ERROR, 0, "Could not get one of the mandatory"
+ " fields in %s", gst_structure_get_name (structure));
+
+ goto done;
+ }
+
+ element =
+ GES_TRACK_ELEMENT (ges_timeline_get_element (timeline, element_name));
+
+ if (!GES_IS_TRACK_ELEMENT (element)) {
+ *error =
+ g_error_new (GES_ERROR, 0, "Could not find TrackElement %s",
+ element_name);
+
+ goto done;
+ }
+
+ binding = ges_track_element_get_control_binding (element, property_name);
+ if (binding == NULL) {
+ *error = g_error_new (GES_ERROR, 0, "No control binding found for %s:%s"
+ " you should first set-control-binding on it",
+ element_name, property_name);
+
+ goto done;
+ }
+
+ g_object_get (binding, "control-source", &source, NULL);
+
+ if (source == NULL) {
+ *error = g_error_new (GES_ERROR, 0, "No control source found for %s:%s"
+ " you should first set-control-binding on it",
+ element_name, property_name);
+
+ goto done;
+ }
+
+ if (!GST_IS_TIMED_VALUE_CONTROL_SOURCE (source)) {
+ *error = g_error_new (GES_ERROR, 0, "You can use add-keyframe"
+ " only on GstTimedValueControlSource not %s",
+ G_OBJECT_TYPE_NAME (source));
+
+ goto done;
+ }
+
+ if (!g_strcmp0 (gst_structure_get_name (structure), "add-keyframe"))
+ ret = gst_timed_value_control_source_set (source, timestamp, value);
+ else {
+ ret = gst_timed_value_control_source_unset (source, timestamp);
+
+ if (!ret) {
+ *error =
+ g_error_new (GES_ERROR, 0,
+ "Could not unset value for timestamp: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp));
+ }
+ }
+
+done:
+ if (source)
+ gst_object_unref (source);
+ g_free (element_name);
+ g_free (property_name);
+
+ return ret;
+
+}
+
+GESAsset *
+_ges_get_asset_from_timeline (GESTimeline * timeline, GType type,
+ const gchar * id)
+{
+ GESAsset *asset;
+ GError *error = NULL;
+ GESProject *project = ges_timeline_get_project (timeline);
+
+ asset = ges_project_create_asset_sync (project, id, type, &error);
+ if (!asset || error) {
+ GST_ERROR
+ ("There was an error requesting the asset with id %s and type %s (%s)",
+ id, g_type_name (type), error ? error->message : "unknown");
+
+ return NULL;
+ }
+
+ return asset;
+}
+
+/* Unref after usage */
+GESLayer *
+_ges_get_layer_by_priority (GESTimeline * timeline, gint priority)
+{
+ GList *layers, *tmp;
+ GESLayer *layer = NULL;
+
+ layers = ges_timeline_get_layers (timeline);
+ if (priority == (gint) g_list_length (layers)) {
+ layer = gst_object_ref (ges_timeline_append_layer (timeline));
+
+ goto done;
+ }
+
+ for (tmp = layers; tmp; tmp = tmp->next) {
+ GESLayer *tmp_layer = GES_LAYER (tmp->data);
+ guint tmp_priority;
+
+ g_object_get (tmp_layer, "priority", &tmp_priority, NULL);
+ if ((gint) tmp_priority == priority) {
+ layer = gst_object_ref (tmp_layer);
+ break;
+ }
+ }
+
+done:
+ g_list_free_full (layers, gst_object_unref);
+
+ return layer;
+}
+
+#define GET_AND_CHECK(name,type,var) G_STMT_START {\
+ if (!gst_structure_get (structure, name, type, var, NULL)) {\
+ *error = g_error_new (GES_ERROR, 0, "Could not get mandatory field: %s in %s",\
+ name, gst_structure_get_name (structure)); \
+ goto beach;\
+ } \
+} G_STMT_END
+
+#define TRY_GET(name,type,var,def) G_STMT_START {\
+ if (!gst_structure_get (structure, name, type, var, NULL)) {\
+ *var = def; \
+ } \
+} G_STMT_END
+
+gboolean
+_ges_add_clip_from_struct (GESTimeline * timeline, GstStructure * structure,
+ GError ** error)
+{
+ GESAsset *asset;
+ GESLayer *layer;
+ GESClip *clip;
+ gint layer_priority;
+ const gchar *name;
+ const gchar *asset_id;
+ const gchar *type_string;
+ GType type;
+ gboolean res = FALSE;
+ GstClockTime duration = 1 * GST_SECOND, inpoint = 0, start =
+ GST_CLOCK_TIME_NONE;
+
+ GET_AND_CHECK ("asset-id", G_TYPE_STRING, &asset_id);
+
+ TRY_GET ("name", G_TYPE_STRING, &name, NULL);
+ TRY_GET ("layer-priority", G_TYPE_INT, &layer_priority,
+ g_list_length (timeline->layers));
+ TRY_GET ("type", G_TYPE_STRING, &type_string, "GESUriClip");
+ TRY_GET ("start", GST_TYPE_CLOCK_TIME, &start, 0);
+ TRY_GET ("inpoint", GST_TYPE_CLOCK_TIME, &inpoint, 0);
+ TRY_GET ("duration", GST_TYPE_CLOCK_TIME, &duration, GST_CLOCK_TIME_NONE);
+
+ if (!(type = g_type_from_name (type_string))) {
+ *error = g_error_new (GES_ERROR, 0, "This type doesn't exist : %s",
+ type_string);
+
+ goto beach;
+ }
+
+ asset = _ges_get_asset_from_timeline (timeline, type, asset_id);
+ if (!asset) {
+ res = FALSE;
+
+ goto beach;
+ }
+
+ layer = _ges_get_layer_by_priority (timeline, layer_priority);
+
+ if (!layer) {
+ g_error_new (GES_ERROR, 0, "No layer with priority %d", layer_priority);
+ goto beach;
+ }
+
+ clip = ges_layer_add_asset (layer, asset, start, inpoint, duration,
+ GES_TRACK_TYPE_UNKNOWN);
+
+ if (clip) {
+ res = TRUE;
+ if (name
+ && !ges_timeline_element_set_name (GES_TIMELINE_ELEMENT (clip), name)) {
+ res = FALSE;
+ g_error_new (GES_ERROR, 0, "couldn't set name %s on clip with id %s",
+ name, asset_id);
+ }
+ } else {
+ g_error_new (GES_ERROR, 0,
+ "Couldn't add clip with id %s to layer with priority %d", asset_id,
+ layer_priority);
+ }
+
+ gst_object_unref (layer);
+
+beach:
+ return res;
+}
+
+#undef GET_AND_CHECK
+#undef TRY_GET
+
+gboolean
+_ges_container_add_child_from_struct (GESTimeline * timeline,
+ GstStructure * structure, GError ** error)
+{
+ GESAsset *asset;
+ GESContainer *container;
+ GESTimelineElement *child = NULL;
+ const gchar *container_name, *child_name, *child_type, *id;
+
+ gboolean res = TRUE;
+
+ container_name = gst_structure_get_string (structure, "container-name");
+ container =
+ GES_CONTAINER (ges_timeline_get_element (timeline, container_name));
+ g_return_val_if_fail (GES_IS_CONTAINER (container), FALSE);
+
+ id = gst_structure_get_string (structure, "asset-id");
+ child_type = gst_structure_get_string (structure, "child-type");
+
+ if (id && child_type) {
+ asset =
+ _ges_get_asset_from_timeline (timeline, g_type_from_name (child_type),
+ id);
+
+ if (asset == NULL) {
+ res = FALSE;
+ g_error_new (GES_ERROR, 0, "Could not find asset: %s", id);
+ goto beach;
+ }
+
+ child = GES_TIMELINE_ELEMENT (ges_asset_extract (asset, NULL));
+ if (!GES_IS_TIMELINE_ELEMENT (child)) {
+ g_error_new (GES_ERROR, 0, "Could not extract child element");
+
+ goto beach;
+ }
+ }
+
+ child_name = gst_structure_get_string (structure, "child-name");
+ if (!child && child_name) {
+ child = ges_timeline_get_element (timeline, child_name);
+ if (!GES_IS_TIMELINE_ELEMENT (child)) {
+ g_error_new (GES_ERROR, 0, "Could not find child element");
+
+ goto beach;
+ }
+ }
+
+ if (!child) {
+ g_error_new (GES_ERROR, 0, "Wong parametters, could not get a child");
+
+ return FALSE;
+ }
+
+ if (child_name)
+ ges_timeline_element_set_name (child, child_name);
+ else
+ child_name = GES_TIMELINE_ELEMENT_NAME (child);
+
+ res = ges_container_add (container, child);
+ if (res == FALSE) {
+ g_error_new (GES_ERROR, 0, "Could not add child to container");
+ }
+
+beach:
+ return res;
+}
+
+gboolean
+_ges_set_child_property_from_struct (GESTimeline * timeline,
+ GstStructure * structure, GError ** error)
+{
+ const GValue *value;
+ GESTimelineElement *element;
+ const gchar *property_name, *element_name;
+
+ element_name = gst_structure_get_string (structure, "element-name");
+ element = ges_timeline_get_element (timeline, element_name);
+ if (!GES_IS_TRACK_ELEMENT (element)) {
+ *error =
+ g_error_new (GES_ERROR, 0, "Could not find TrackElement %s",
+ element_name);
+
+ return FALSE;
+ }
+
+ property_name = gst_structure_get_string (structure, "property");
+ value = gst_structure_get_value (structure, "value");
+
+ GST_DEBUG ("%s Setting %s property to %p",
+ element->name, property_name, value);
+
+ ges_track_element_set_child_property (GES_TRACK_ELEMENT (element),
+ property_name, (GValue *) value);
+
+ return TRUE;
+}
#include <gst/validate/validate.h>
#include <gst/validate/gst-validate-scenario.h>
#include <gst/validate/gst-validate-utils.h>
+#include "ges-internal.h"
+#include "ges-structured-interface.h"
#define MONITOR_ON_PIPELINE "validate-monitor"
#define RUNNER_ON_PIPELINE "runner-monitor"
}
static gboolean
-_set_child_property (GstValidateScenario * scenario, GstValidateAction * action)
-{
- const GValue *value;
- GESTimeline *timeline;
- GESTimelineElement *element;
- const gchar *property_name, *element_name;
-
- element_name = gst_structure_get_string (action->structure, "element-name");
-
- timeline = get_timeline (scenario);
- g_return_val_if_fail (timeline, FALSE);
-
- element = ges_timeline_get_element (timeline, element_name);
- g_return_val_if_fail (GES_IS_TRACK_ELEMENT (element), FALSE);
-
- property_name = gst_structure_get_string (action->structure, "property");
- value = gst_structure_get_value (action->structure, "value");
-
- GST_DEBUG ("%s Setting %s property to %p",
- element->name, property_name, value);
- ges_track_element_set_child_property (GES_TRACK_ELEMENT (element),
- property_name, (GValue *) value);
-
- g_object_unref (timeline);
-
- return TRUE;
-}
-
-static gboolean
_serialize_project (GstValidateScenario * scenario, GstValidateAction * action)
{
const gchar *uri = gst_structure_get_string (action->structure, "uri");
return res;
}
-static GESAsset *
-_get_asset (GESTimeline * timeline, GType type, const gchar * id)
-{
- GESAsset *asset;
- GError *error = NULL;
- GESProject *project = ges_timeline_get_project (timeline);
-
- asset = ges_project_create_asset_sync (project, id, type, &error);
- if (!asset || error) {
- GST_ERROR
- ("There was an error requesting the asset with id %s and type %s (%s)",
- id, g_type_name (type), error ? error->message : "unknown");
-
- return NULL;
- }
-
- return asset;
-}
-
static gboolean
_add_asset (GstValidateScenario * scenario, GstValidateAction * action)
{
goto beach;
}
- asset = _get_asset (timeline, type, id);
+ asset = _ges_get_asset_from_timeline (timeline, type, id);
if (!asset) {
res = FALSE;
return res;
}
-/* Unref after usage */
-static GESLayer *
-_get_layer_by_priority (GESTimeline * timeline, gint priority)
-{
- GList *layers, *tmp;
- GESLayer *layer = NULL;
-
- layers = ges_timeline_get_layers (timeline);
- for (tmp = layers; tmp; tmp = tmp->next) {
- GESLayer *tmp_layer = GES_LAYER (tmp->data);
- guint tmp_priority;
- g_object_get (tmp_layer, "priority", &tmp_priority, NULL);
- if ((gint) tmp_priority == priority) {
- layer = gst_object_ref (tmp_layer);
- break;
- }
- }
-
- g_list_free_full (layers, gst_object_unref);
- return layer;
-}
-
static gboolean
_add_layer (GstValidateScenario * scenario, GstValidateAction * action)
{
goto beach;
}
- layer = _get_layer_by_priority (timeline, priority);
+ layer = _ges_get_layer_by_priority (timeline, priority);
if (layer != NULL) {
GST_ERROR
goto beach;
}
- layer = _get_layer_by_priority (timeline, priority);
+ layer = _ges_get_layer_by_priority (timeline, priority);
if (layer) {
res = ges_timeline_remove_layer (timeline, layer);
return res;
}
-static gboolean
-_add_clip (GstValidateScenario * scenario, GstValidateAction * action)
-{
- GESTimeline *timeline = get_timeline (scenario);
- GESAsset *asset;
- GESLayer *layer;
- GESClip *clip;
- gint layer_priority;
- const gchar *name;
- const gchar *asset_id;
- const gchar *type_string;
- GType type;
- gboolean res = FALSE;
- GstClockTime duration = 1 * GST_SECOND, inpoint = 0, start =
- GST_CLOCK_TIME_NONE;
-
- gst_structure_get_int (action->structure, "layer-priority", &layer_priority);
- name = gst_structure_get_string (action->structure, "name");
- asset_id = gst_structure_get_string (action->structure, "asset-id");
- type_string = gst_structure_get_string (action->structure, "type");
-
- gst_validate_action_get_clocktime (scenario, action, "start", &start);
- gst_validate_action_get_clocktime (scenario, action, "inpoint", &inpoint);
- gst_validate_action_get_clocktime (scenario, action, "duration", &duration);
-
- gst_validate_printf (action, "Adding clip from asset of type %s with ID %s"
- " wanted name: %s"
- " -- start: %" GST_TIME_FORMAT
- ", inpoint: %" GST_TIME_FORMAT
- ", duration: %" GST_TIME_FORMAT "\n",
- type_string, asset_id, name,
- GST_TIME_ARGS (start), GST_TIME_ARGS (inpoint), GST_TIME_ARGS (duration));
-
- if (!(type = g_type_from_name (type_string))) {
- GST_ERROR ("This type doesn't exist : %s", type_string);
- goto beach;
- }
-
- asset = _get_asset (timeline, type, asset_id);
- if (!asset) {
- res = FALSE;
-
- goto beach;
- }
-
- layer = _get_layer_by_priority (timeline, layer_priority);
-
- if (!layer) {
- GST_ERROR ("No layer with priority %d", layer_priority);
- goto beach;
- }
-
- clip = ges_layer_add_asset (layer, asset, start, inpoint, duration,
- GES_TRACK_TYPE_UNKNOWN);
-
- if (clip) {
- res = TRUE;
- if (!ges_timeline_element_set_name (GES_TIMELINE_ELEMENT (clip), name)) {
- res = FALSE;
- GST_ERROR ("couldn't set name %s on clip with id %s", name, asset_id);
- }
- } else {
- GST_ERROR ("Couldn't add clip with id %s to layer with priority %d",
- asset_id, layer_priority);
- }
-
- gst_object_unref (layer);
-
-beach:
- g_object_unref (timeline);
- return res;
-}
static gboolean
_edit_container (GstValidateScenario * scenario, GstValidateAction * action)
gst_validate_printf (action, "Setting asset %s on element %s\n",
id, element_name);
- asset = _get_asset (timeline, G_OBJECT_TYPE (element), id);
+ asset = _ges_get_asset_from_timeline (timeline, G_OBJECT_TYPE (element), id);
if (asset == NULL) {
res = FALSE;
GST_ERROR ("Could not find asset: %s", id);
}
static gboolean
-_container_add_child (GstValidateScenario * scenario,
- GstValidateAction * action)
-{
- GESAsset *asset;
- GESContainer *container;
- GESTimelineElement *child = NULL;
- const gchar *container_name, *child_name, *child_type, *id;
-
- gboolean res = TRUE;
- GESTimeline *timeline = get_timeline (scenario);
-
- container_name =
- gst_structure_get_string (action->structure, "container-name");
- container =
- GES_CONTAINER (ges_timeline_get_element (timeline, container_name));
- g_return_val_if_fail (GES_IS_CONTAINER (container), FALSE);
-
- id = gst_structure_get_string (action->structure, "asset-id");
- child_type = gst_structure_get_string (action->structure, "child-type");
-
- if (id && child_type) {
- asset = _get_asset (timeline, g_type_from_name (child_type), id);
-
- if (asset == NULL) {
- res = FALSE;
- GST_ERROR ("Could not find asset: %s", id);
- goto beach;
- }
-
- child = GES_TIMELINE_ELEMENT (ges_asset_extract (asset, NULL));
- g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (child), FALSE);
- }
-
- child_name = gst_structure_get_string (action->structure, "child-name");
- if (!child && child_name) {
- child = ges_timeline_get_element (timeline, child_name);
- g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (child), FALSE);
- }
-
- if (!child) {
- GST_ERROR_OBJECT (scenario, "Wong parametters, could not get a child");
-
- return FALSE;
- }
-
- if (child_name)
- ges_timeline_element_set_name (child, child_name);
- else
- child_name = GES_TIMELINE_ELEMENT_NAME (child);
-
- gst_validate_printf (action, "Adding child %s to container %s\n",
- child_name, GES_TIMELINE_ELEMENT_NAME (container));
-
- res = ges_container_add (container, child);
-
-beach:
- gst_object_unref (timeline);
-
- return res;
-}
-
-static gboolean
_container_remove_child (GstValidateScenario * scenario,
GstValidateAction * action)
{
}
static gboolean
-_add_remove_keyframe (GstValidateScenario * scenario,
+_validate_action_execute (GstValidateScenario * scenario,
GstValidateAction * action)
{
- GESTrackElement *element;
-
- gdouble value;
- GstClockTime timestamp;
- GstControlBinding *binding = NULL;
- GstTimedValueControlSource *source = NULL;
- gchar *element_name, *property_name;
-
- gboolean ret = FALSE;
+ GError *err = NULL;
GESTimeline *timeline = get_timeline (scenario);
-
- g_return_val_if_fail (gst_structure_get (action->structure,
- "element-name", G_TYPE_STRING, &element_name,
- "property-name", G_TYPE_STRING, &property_name,
- "value", G_TYPE_DOUBLE, &value, NULL), FALSE);
-
- gst_validate_action_get_clocktime (scenario, action, "timestamp", ×tamp);
-
- element =
- GES_TRACK_ELEMENT (ges_timeline_get_element (timeline, element_name));
- g_return_val_if_fail (GES_IS_TRACK_ELEMENT (element), FALSE);
-
- binding = ges_track_element_get_control_binding (element, property_name);
- if (binding == NULL) {
- GST_ERROR_OBJECT (scenario, "No control binding found for %s:%s"
- " you should first set-control-binding on it",
- element_name, property_name);
-
- goto done;
+ ActionFromStructureFunc func;
+
+ if (gst_structure_has_name (action->structure, "add-keyframe") ||
+ gst_structure_has_name (action->structure, "remove-keyframe")) {
+ func = _ges_add_remove_keyframe_from_struct;
+ } else if (gst_structure_has_name (action->structure, "add-clip")) {
+ func = _ges_add_clip_from_struct;
+ } else if (gst_structure_has_name (action->structure, "container-add-child")) {
+ func = _ges_container_add_child_from_struct;
+ } else if (gst_structure_has_name (action->structure, "set-child-property")) {
+ func = _ges_set_child_property_from_struct;
+ } else {
+ g_assert_not_reached ();
}
- g_object_get (binding, "control-source", &source, NULL);
-
- if (source == NULL) {
- GST_ERROR_OBJECT (scenario, "No control source found for %s:%s"
- " you should first set-control-binding on it",
- element_name, property_name);
-
- goto done;
- }
+ if (!func (timeline, action->structure, &err)) {
+ GST_VALIDATE_REPORT (scenario,
+ g_quark_from_string ("scenario::execution-error"), err->message);
- if (!GST_IS_TIMED_VALUE_CONTROL_SOURCE (source)) {
- GST_ERROR_OBJECT (scenario, "You can use add-keyframe"
- " only on GstTimedValueControlSource not %s",
- G_OBJECT_TYPE_NAME (source));
+ g_clear_error (&err);
- goto done;
+ return TRUE;
}
- if (!g_strcmp0 (action->type, "add-keyframe"))
- ret = gst_timed_value_control_source_set (source, timestamp, value);
- else
- ret = gst_timed_value_control_source_unset (source, timestamp);
-
-done:
gst_object_unref (timeline);
- if (source)
- gst_object_unref (source);
- g_free (element_name);
- g_free (property_name);
- return ret;
+ return TRUE;
}
static void
(GstValidateActionParameter []) {
{
.name = "priority",
- .description = "The priority of the new layer to add",
- .mandatory = TRUE,
+ .description = "The priority of the new layer to add,"
+ "if not specified, the new layer will be"
+ " appended to the timeline",
+ .mandatory = FALSE,
NULL
},
{ NULL }
},
"Allows to remove a layer from the current timeline", GST_VALIDATE_ACTION_TYPE_NONE);
- gst_validate_register_action_type ("add-clip", "ges", _add_clip,
+ gst_validate_register_action_type ("add-clip", "ges", _validate_action_execute,
(GstValidateActionParameter []) {
{
.name = "name",
{NULL}
}, "serializes a project", GST_VALIDATE_ACTION_TYPE_NONE);
- gst_validate_register_action_type ("set-child-property", "ges", _set_child_property,
+ gst_validate_register_action_type ("set-child-property", "ges", _validate_action_execute,
(GstValidateActionParameter []) {
{
.name = "element-name",
}, "Sets restriction caps on tracks of a specific type.", GST_VALIDATE_ACTION_TYPE_NONE);
- gst_validate_register_action_type ("container-add-child", "ges", _container_add_child,
+ gst_validate_register_action_type ("container-add-child", "ges", _validate_action_execute,
(GstValidateActionParameter []) {
{
.name = "container-name",
}, "Adds a GstControlSource on @element-name::@property-name"
" allowing you to then add keyframes on that property.", GST_VALIDATE_ACTION_TYPE_NONE);
- gst_validate_register_action_type ("add-keyframe", "ges", _add_remove_keyframe,
+ gst_validate_register_action_type ("add-keyframe", "ges", _validate_action_execute,
(GstValidateActionParameter []) {
{
.name = "element-name",
{NULL}
}, "Remove a child from @container-name.", GST_VALIDATE_ACTION_TYPE_NONE);
- gst_validate_register_action_type ("remove-keyframe", "ges", _add_remove_keyframe,
+ gst_validate_register_action_type ("remove-keyframe", "ges", _validate_action_execute,
(GstValidateActionParameter []) {
{
.name = "element-name",