structured-interface: Move set_control_source from ges-validate

So it can be reused in the command line formatter.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/merge_requests/227>
This commit is contained in:
Thibault Saunier 2021-01-15 09:25:11 -03:00
parent 811d63439f
commit ad5626dab8
3 changed files with 179 additions and 83 deletions

View file

@ -100,6 +100,21 @@ typedef struct
GList *invalid_fields;
} 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)
{
@ -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

View 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

View 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",