structured-interface: Move set_control_source from ges-validate
authorThibault Saunier <tsaunier@igalia.com>
Fri, 15 Jan 2021 12:25:11 +0000 (09:25 -0300)
committerThibault Saunier <tsaunier@igalia.com>
Wed, 10 Feb 2021 19:14:47 +0000 (16:14 -0300)
So it can be reused in the command line formatter.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/merge_requests/227>

ges/ges-structured-interface.c
ges/ges-structured-interface.h
ges/ges-validate.c

index 753e848..253b9b4 100644 (file)
@@ -101,6 +101,21 @@ typedef struct
 } FieldsError;
 
 static gboolean
+enum_from_str (GType type, const gchar * str_enum, guint * enum_value)
+{
+  GValue value = G_VALUE_INIT;
+  g_value_init (&value, type);
+
+  if (!gst_value_deserialize (&value, str_enum))
+    return FALSE;
+
+  *enum_value = g_value_get_enum (&value);
+  g_value_unset (&value);
+
+  return TRUE;
+}
+
+static gboolean
 _check_field (GQuark field_id, const GValue * value, FieldsError * fields_error)
 {
   guint i;
@@ -237,6 +252,69 @@ _ges_save_timeline_if_needed (GESTimeline * timeline, GstStructure * structure,
   return res;
 }
 
+typedef struct
+{
+  GstTimedValueControlSource *source;
+  GstStructure *structure;
+  GError *error;
+  const gchar *property_name;
+  gboolean res;
+} SetKeyframesData;
+
+static gboolean
+un_set_keyframes_foreach (GQuark field_id, const GValue * value,
+    SetKeyframesData * d)
+{
+  GValue v = G_VALUE_INIT;
+  GError **error = &d->error;
+  gchar *tmp;
+  gint i;
+  const gchar *valid_fields[] = {
+    "element-name", "property-name", "value", "timestamp", "project-uri",
+    "binding-type", "source-type", "interpolation-mode", "interpolation-mode",
+    NULL
+  };
+  const gchar *field = g_quark_to_string (field_id);
+  gdouble ts;
+
+  for (i = 0; valid_fields[i]; i++) {
+    if (g_quark_from_string (valid_fields[i]) == field_id)
+      return TRUE;
+  }
+
+  errno = 0;
+  ts = g_strtod (field, &tmp);
+
+  REPORT_UNLESS (errno == 0 && field != tmp, err,
+      "Could not convert `%s` to GstClockTime (%s)", field, g_strerror (errno));
+
+  if (gst_structure_has_name (d->structure, "remove-keyframe")) {
+    REPORT_UNLESS (gst_timed_value_control_source_unset (d->source,
+            ts * GST_SECOND), err, "Could not unset keyframe at %f", ts);
+
+    return TRUE;
+  }
+
+  g_value_init (&v, G_TYPE_DOUBLE);
+  REPORT_UNLESS (g_value_transform (value, &v), err,
+      "Could not convert keyframe %f value %s to double", ts,
+      gst_value_serialize (value));
+
+  REPORT_UNLESS (gst_timed_value_control_source_set (d->source, ts * GST_SECOND,
+          g_value_get_double (&v)), err, "Could not set keyframe %f=%f", ts,
+      g_value_get_double (&v));
+
+  g_value_reset (&v);
+  return TRUE;
+
+err:
+  if (v.g_type)
+    g_value_reset (&v);
+  d->res = FALSE;
+  return FALSE;
+}
+
+
 gboolean
 _ges_add_remove_keyframe_from_struct (GESTimeline * timeline,
     GstStructure * structure, GError ** error)
@@ -260,11 +338,15 @@ _ges_add_remove_keyframe_from_struct (GESTimeline * timeline,
 
   FieldsError fields_error = { valid_fields, NULL };
 
-  if (!_check_fields (structure, fields_error, error))
-    return FALSE;
-
-  GET_AND_CHECK ("property-name", G_TYPE_STRING, &property_name, done);
-  GET_AND_CHECK ("timestamp", GST_TYPE_CLOCK_TIME, &timestamp, done);
+  if (gst_structure_has_field (structure, "value")) {
+    if (!_check_fields (structure, fields_error, error))
+      return FALSE;
+    GET_AND_CHECK ("timestamp", GST_TYPE_CLOCK_TIME, &timestamp, done);
+  } else {
+    REPORT_UNLESS (!gst_structure_has_field (structure, "timestamp"), done,
+        "Doesn't have a `value` field in %" GST_PTR_FORMAT
+        " but has a `timestamp`" " that can't work!", structure);
+  }
 
   GET_AND_CHECK ("property-name", G_TYPE_STRING, &property_name, done);
   if (!(element =
@@ -286,6 +368,18 @@ _ges_add_remove_keyframe_from_struct (GESTimeline * timeline,
       " only on GstTimedValueControlSource not %s",
       G_OBJECT_TYPE_NAME (source));
 
+  if (!gst_structure_has_field (structure, "value")) {
+    SetKeyframesData d = {
+      source, structure, NULL, property_name, TRUE,
+    };
+    gst_structure_foreach (structure,
+        (GstStructureForeachFunc) un_set_keyframes_foreach, &d);
+    if (!d.res)
+      g_propagate_error (error, d.error);
+
+    return d.res;
+  }
+
   g_object_get (binding, "absolute", &absolute, NULL);
   if (absolute) {
     GParamSpec *pspec;
@@ -585,17 +679,11 @@ _ges_add_clip_from_struct (GESTimeline * timeline, GstStructure * structure,
 
     if (GES_IS_TEST_CLIP (clip)) {
       if (pattern) {
-        GEnumClass *enum_class =
-            G_ENUM_CLASS (g_type_class_ref (GES_VIDEO_TEST_PATTERN_TYPE));
-        GEnumValue *value = g_enum_get_value_by_nick (enum_class, pattern);
+        guint v;
 
-        if (!value) {
-          res = FALSE;
-          goto beach;
-        }
-
-        ges_test_clip_set_vpattern (GES_TEST_CLIP (clip), value->value);
-        g_type_class_unref (enum_class);
+        REPORT_UNLESS (enum_from_str (GES_VIDEO_TEST_PATTERN_TYPE, pattern, &v),
+            beach, "Invalid pattern: %s", pattern);
+        ges_test_clip_set_vpattern (GES_TEST_CLIP (clip), v);
       }
     }
 
@@ -919,5 +1007,74 @@ err:
   return FALSE;
 }
 
+gboolean
+_ges_set_control_source_from_struct (GESTimeline * timeline,
+    GstStructure * structure, GError ** error)
+{
+  guint mode;
+  gboolean res = FALSE;
+  GESTimelineElement *element = NULL;
+
+  GstControlSource *source = NULL;
+  gchar *property_name, *binding_type = NULL,
+      *source_type = NULL, *interpolation_mode = NULL;
+
+  GET_AND_CHECK ("property-name", G_TYPE_STRING, &property_name, beach);
+
+  if (!(element =
+          find_element_for_property (timeline, structure, &property_name, TRUE,
+              error)))
+    goto beach;
+
+  if (GES_IS_CLIP (element)) {
+    GList *tmp;
+    for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
+      if (ges_timeline_element_lookup_child (tmp->data, property_name, NULL,
+              NULL)) {
+        gst_object_replace ((GstObject **) & element, tmp->data);
+
+        break;
+      }
+    }
+  }
+
+  REPORT_UNLESS (GES_IS_TRACK_ELEMENT (element), beach,
+      "Could not find TrackElement from %" GST_PTR_FORMAT, structure);
+
+  TRY_GET ("binding-type", G_TYPE_STRING, &binding_type, NULL);
+  TRY_GET ("source-type", G_TYPE_STRING, &source_type, NULL);
+  TRY_GET ("interpolation-mode", G_TYPE_STRING, &interpolation_mode, NULL);
+
+  if (!binding_type)
+    binding_type = g_strdup ("direct");
+
+  REPORT_UNLESS (source_type == NULL
+      || !g_strcmp0 (source_type, "interpolation"), beach,
+      "Interpolation type %s not supported", source_type);
+  source = gst_interpolation_control_source_new ();
+
+  if (interpolation_mode)
+    REPORT_UNLESS (enum_from_str (GST_TYPE_INTERPOLATION_MODE,
+            interpolation_mode, &mode), beach,
+        "Wrong interpolation mode: %s", interpolation_mode);
+  else
+    mode = GST_INTERPOLATION_MODE_LINEAR;
+
+  g_object_set (source, "mode", mode, NULL);
+
+  res = ges_track_element_set_control_source (GES_TRACK_ELEMENT (element),
+      source, property_name, binding_type);
+
+beach:
+  gst_clear_object (&element);
+  gst_clear_object (&source);
+  g_free (property_name);
+  g_free (binding_type);
+  g_free (source_type);
+  g_free (interpolation_mode);
+
+  return res;
+}
+
 #undef GET_AND_CHECK
 #undef TRY_GET
index 13efc16..9dd7a69 100644 (file)
@@ -62,4 +62,8 @@ _ges_get_layer_by_priority                    (GESTimeline * timeline,
 G_GNUC_INTERNAL gboolean
 _ges_save_timeline_if_needed (GESTimeline* timeline, GstStructure* structure, GError** error);
 
+G_GNUC_INTERNAL gboolean
+_ges_set_control_source_from_struct (GESTimeline * timeline,
+    GstStructure * structure, GError ** error);
+
 G_END_DECLS
index ace70e8..7354b6c 100644 (file)
@@ -876,73 +876,6 @@ beach:
 
 GST_END_VALIDATE_ACTION;
 
-GES_START_VALIDATE_ACTION (_set_control_source)
-{
-  guint mode;
-  GESTrackElement *element = NULL;
-
-  GstControlSource *source = NULL;
-  gchar *element_name, *property_name, *binding_type = NULL,
-      *source_type = NULL, *interpolation_mode = NULL;
-
-  REPORT_UNLESS (gst_structure_get (action->structure,
-          "element-name", G_TYPE_STRING, &element_name,
-          "property-name", G_TYPE_STRING, &property_name, NULL),
-      beach, "Wrong parameters");
-
-  TRY_GET ("binding-type", G_TYPE_STRING, &binding_type, NULL);
-  TRY_GET ("source-type", G_TYPE_STRING, &source_type, NULL);
-  TRY_GET ("interpolation-mode", G_TYPE_STRING, &interpolation_mode, NULL);
-
-  element =
-      (GESTrackElement *) (ges_timeline_get_element (timeline, element_name));
-  if (GES_IS_CLIP (element)) {
-    GList *tmp;
-    for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
-      if (ges_timeline_element_lookup_child (tmp->data, property_name, NULL,
-              NULL)) {
-        gst_object_replace ((GstObject **) & element, tmp->data);
-
-        break;
-      }
-    }
-  }
-  REPORT_UNLESS (GES_IS_TRACK_ELEMENT (element), beach,
-      "Could not find track element element %s (got %" GST_PTR_FORMAT ")",
-      element_name, element);
-
-  if (!binding_type)
-    binding_type = g_strdup ("direct");
-
-  REPORT_UNLESS (source_type == NULL
-      || !g_strcmp0 (source_type, "interpolation"), beach,
-      "Interpolation type %s not supported", source_type);
-  source = gst_interpolation_control_source_new ();
-
-  if (interpolation_mode)
-    REPORT_UNLESS (gst_validate_utils_enum_from_str
-        (GST_TYPE_INTERPOLATION_MODE, interpolation_mode, &mode), beach,
-        "Wrong intorpolation mode: %s", interpolation_mode);
-  else
-    mode = GST_INTERPOLATION_MODE_LINEAR;
-
-  g_object_set (source, "mode", mode, NULL);
-
-  res = ges_track_element_set_control_source (element,
-      source, property_name, binding_type);
-
-beach:
-  gst_clear_object (&element);
-  gst_clear_object (&source);
-  g_free (property_name);
-  g_free (element_name);
-  g_free (binding_type);
-  g_free (source_type);
-  g_free (interpolation_mode);
-}
-
-GST_END_VALIDATE_ACTION;
-
 GES_START_VALIDATE_ACTION (_validate_action_execute)
 {
   GError *err = NULL;
@@ -952,6 +885,8 @@ GES_START_VALIDATE_ACTION (_validate_action_execute)
   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, "set-control-source")) {
+    func = _ges_set_control_source_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")) {
@@ -1743,7 +1678,7 @@ ges_validate_register_action_types (void)
         {NULL}
       }, "Ungroup children of @container-name.", FALSE);
 
-  gst_validate_register_action_type ("set-control-source", "ges", _set_control_source,
+  gst_validate_register_action_type ("set-control-source", "ges", _validate_action_execute,
       (GstValidateActionParameter []) {
         {
           .name = "element-name",