mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-30 20:59:44 +00:00
controller: Added absolute direct control binding, example and test
Fixes: 740502 API: gst_direct_control_binding_new_absolute
This commit is contained in:
parent
d61ba38118
commit
cb2c141eac
6 changed files with 243 additions and 26 deletions
|
@ -38,6 +38,7 @@
|
||||||
#define GST_CAT_DEFAULT control_binding_debug
|
#define GST_CAT_DEFAULT control_binding_debug
|
||||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||||
|
|
||||||
|
|
||||||
static GObject *gst_direct_control_binding_constructor (GType type,
|
static GObject *gst_direct_control_binding_constructor (GType type,
|
||||||
guint n_construct_params, GObjectConstructParam * construct_params);
|
guint n_construct_params, GObjectConstructParam * construct_params);
|
||||||
static void gst_direct_control_binding_set_property (GObject * object,
|
static void gst_direct_control_binding_set_property (GObject * object,
|
||||||
|
@ -70,6 +71,7 @@ enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_CS,
|
PROP_CS,
|
||||||
|
PROP_ABSOLUTE,
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -97,9 +99,23 @@ convert_value_to_##type (GstDirectControlBinding *self, gdouble s, gpointer d_)
|
||||||
\
|
\
|
||||||
s = CLAMP (s, 0.0, 1.0); \
|
s = CLAMP (s, 0.0, 1.0); \
|
||||||
*d = (g##type) ROUNDING_OP (pspec->minimum * (1-s)) + (g##type) ROUNDING_OP (pspec->maximum * s); \
|
*d = (g##type) ROUNDING_OP (pspec->minimum * (1-s)) + (g##type) ROUNDING_OP (pspec->maximum * s); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static void \
|
||||||
|
abs_convert_g_value_to_##type (GstDirectControlBinding *self, gdouble s, GValue *d) \
|
||||||
|
{ \
|
||||||
|
g##type v; \
|
||||||
|
v = (g##type) ROUNDING_OP (s); \
|
||||||
|
g_value_set_##type (d, v); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static void \
|
||||||
|
abs_convert_value_to_##type (GstDirectControlBinding *self, gdouble s, gpointer d_) \
|
||||||
|
{ \
|
||||||
|
g##type *d = (g##type *)d_; \
|
||||||
|
*d = (g##type) ROUNDING_OP (s); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DEFINE_CONVERT (int, Int, INT, rint);
|
DEFINE_CONVERT (int, Int, INT, rint);
|
||||||
DEFINE_CONVERT (uint, UInt, UINT, rint);
|
DEFINE_CONVERT (uint, UInt, UINT, rint);
|
||||||
DEFINE_CONVERT (long, Long, LONG, rint);
|
DEFINE_CONVERT (long, Long, LONG, rint);
|
||||||
|
@ -180,6 +196,12 @@ gst_direct_control_binding_class_init (GstDirectControlBindingClass * klass)
|
||||||
GST_TYPE_CONTROL_SOURCE,
|
GST_TYPE_CONTROL_SOURCE,
|
||||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
properties[PROP_ABSOLUTE] =
|
||||||
|
g_param_spec_boolean ("absolute", "Absolute",
|
||||||
|
"Whether the control values are absolute",
|
||||||
|
FALSE,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
g_object_class_install_properties (gobject_class, PROP_LAST, properties);
|
g_object_class_install_properties (gobject_class, PROP_LAST, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,46 +231,43 @@ gst_direct_control_binding_constructor (GType type, guint n_construct_params,
|
||||||
GST_DEBUG (" using type %s", g_type_name (base));
|
GST_DEBUG (" using type %s", g_type_name (base));
|
||||||
|
|
||||||
/* select mapping function */
|
/* select mapping function */
|
||||||
|
|
||||||
|
#define SET_CONVERT_FUNCTION(type) \
|
||||||
|
if (self->want_absolute) { \
|
||||||
|
self->convert_g_value = abs_convert_g_value_to_##type; \
|
||||||
|
self->convert_value = abs_convert_value_to_##type; \
|
||||||
|
} \
|
||||||
|
else { \
|
||||||
|
self->convert_g_value = convert_g_value_to_##type; \
|
||||||
|
self->convert_value = convert_value_to_##type; \
|
||||||
|
} \
|
||||||
|
self->byte_size = sizeof (g##type);
|
||||||
|
|
||||||
|
|
||||||
switch (base) {
|
switch (base) {
|
||||||
case G_TYPE_INT:
|
case G_TYPE_INT:
|
||||||
self->convert_g_value = convert_g_value_to_int;
|
SET_CONVERT_FUNCTION (int);
|
||||||
self->convert_value = convert_value_to_int;
|
|
||||||
self->byte_size = sizeof (gint);
|
|
||||||
break;
|
break;
|
||||||
case G_TYPE_UINT:
|
case G_TYPE_UINT:
|
||||||
self->convert_g_value = convert_g_value_to_uint;
|
SET_CONVERT_FUNCTION (uint);
|
||||||
self->convert_value = convert_value_to_uint;
|
|
||||||
self->byte_size = sizeof (guint);
|
|
||||||
break;
|
break;
|
||||||
case G_TYPE_LONG:
|
case G_TYPE_LONG:
|
||||||
self->convert_g_value = convert_g_value_to_long;
|
SET_CONVERT_FUNCTION (long);
|
||||||
self->convert_value = convert_value_to_long;
|
|
||||||
self->byte_size = sizeof (glong);
|
|
||||||
break;
|
break;
|
||||||
case G_TYPE_ULONG:
|
case G_TYPE_ULONG:
|
||||||
self->convert_g_value = convert_g_value_to_ulong;
|
SET_CONVERT_FUNCTION (ulong);
|
||||||
self->convert_value = convert_value_to_ulong;
|
|
||||||
self->byte_size = sizeof (gulong);
|
|
||||||
break;
|
break;
|
||||||
case G_TYPE_INT64:
|
case G_TYPE_INT64:
|
||||||
self->convert_g_value = convert_g_value_to_int64;
|
SET_CONVERT_FUNCTION (int64);
|
||||||
self->convert_value = convert_value_to_int64;
|
|
||||||
self->byte_size = sizeof (gint64);
|
|
||||||
break;
|
break;
|
||||||
case G_TYPE_UINT64:
|
case G_TYPE_UINT64:
|
||||||
self->convert_g_value = convert_g_value_to_uint64;
|
SET_CONVERT_FUNCTION (uint64);
|
||||||
self->convert_value = convert_value_to_uint64;
|
|
||||||
self->byte_size = sizeof (guint64);
|
|
||||||
break;
|
break;
|
||||||
case G_TYPE_FLOAT:
|
case G_TYPE_FLOAT:
|
||||||
self->convert_g_value = convert_g_value_to_float;
|
SET_CONVERT_FUNCTION (float);
|
||||||
self->convert_value = convert_value_to_float;
|
|
||||||
self->byte_size = sizeof (gfloat);
|
|
||||||
break;
|
break;
|
||||||
case G_TYPE_DOUBLE:
|
case G_TYPE_DOUBLE:
|
||||||
self->convert_g_value = convert_g_value_to_double;
|
SET_CONVERT_FUNCTION (double);
|
||||||
self->convert_value = convert_value_to_double;
|
|
||||||
self->byte_size = sizeof (gdouble);
|
|
||||||
break;
|
break;
|
||||||
case G_TYPE_BOOLEAN:
|
case G_TYPE_BOOLEAN:
|
||||||
self->convert_g_value = convert_g_value_to_boolean;
|
self->convert_g_value = convert_g_value_to_boolean;
|
||||||
|
@ -280,6 +299,9 @@ gst_direct_control_binding_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_CS:
|
case PROP_CS:
|
||||||
self->cs = g_value_dup_object (value);
|
self->cs = g_value_dup_object (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_ABSOLUTE:
|
||||||
|
self->want_absolute = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -296,6 +318,9 @@ gst_direct_control_binding_get_property (GObject * object, guint prop_id,
|
||||||
case PROP_CS:
|
case PROP_CS:
|
||||||
g_value_set_object (value, self->cs);
|
g_value_set_object (value, self->cs);
|
||||||
break;
|
break;
|
||||||
|
case PROP_ABSOLUTE:
|
||||||
|
g_value_set_boolean (value, self->want_absolute);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -493,3 +518,25 @@ gst_direct_control_binding_new (GstObject * object, const gchar * property_name,
|
||||||
return (GstControlBinding *) g_object_new (GST_TYPE_DIRECT_CONTROL_BINDING,
|
return (GstControlBinding *) g_object_new (GST_TYPE_DIRECT_CONTROL_BINDING,
|
||||||
"object", object, "name", property_name, "control-source", cs, NULL);
|
"object", object, "name", property_name, "control-source", cs, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_direct_control_binding_new_absolute:
|
||||||
|
* @object: the object of the property
|
||||||
|
* @property_name: the property-name to attach the control source
|
||||||
|
* @cs: the control source
|
||||||
|
*
|
||||||
|
* Create a new control-binding that attaches the #GstControlSource to the
|
||||||
|
* #GObject property.
|
||||||
|
*
|
||||||
|
* Returns: (transfer floating): the new #GstDirectControlBinding
|
||||||
|
*
|
||||||
|
* Since: 1.6
|
||||||
|
*/
|
||||||
|
GstControlBinding *
|
||||||
|
gst_direct_control_binding_new_absolute (GstObject * object,
|
||||||
|
const gchar * property_name, GstControlSource * cs)
|
||||||
|
{
|
||||||
|
return (GstControlBinding *) g_object_new (GST_TYPE_DIRECT_CONTROL_BINDING,
|
||||||
|
"object", object, "name", property_name, "control-source", cs, "absolute",
|
||||||
|
TRUE, NULL);
|
||||||
|
}
|
||||||
|
|
|
@ -81,6 +81,7 @@ struct _GstDirectControlBinding {
|
||||||
GValue cur_value;
|
GValue cur_value;
|
||||||
gdouble last_value;
|
gdouble last_value;
|
||||||
gint byte_size;
|
gint byte_size;
|
||||||
|
gboolean want_absolute;
|
||||||
|
|
||||||
GstDirectControlBindingConvertValue convert_value;
|
GstDirectControlBindingConvertValue convert_value;
|
||||||
GstDirectControlBindingConvertGValue convert_g_value;
|
GstDirectControlBindingConvertGValue convert_g_value;
|
||||||
|
@ -110,6 +111,10 @@ GType gst_direct_control_binding_get_type (void);
|
||||||
|
|
||||||
GstControlBinding * gst_direct_control_binding_new (GstObject * object, const gchar * property_name,
|
GstControlBinding * gst_direct_control_binding_new (GstObject * object, const gchar * property_name,
|
||||||
GstControlSource * cs);
|
GstControlSource * cs);
|
||||||
|
|
||||||
|
GstControlBinding * gst_direct_control_binding_new_absolute (GstObject * object, const gchar * property_name,
|
||||||
|
GstControlSource * cs);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GST_DIRECT_CONTROL_BINDING_H__ */
|
#endif /* __GST_DIRECT_CONTROL_BINDING_H__ */
|
||||||
|
|
|
@ -597,6 +597,72 @@ GST_START_TEST (controller_interpolation_unset_all)
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
|
/* test retrieval of an array of values with get_value_array() */
|
||||||
|
GST_START_TEST (controller_interpolation_linear_absolute_value_array)
|
||||||
|
{
|
||||||
|
GstControlSource *cs;
|
||||||
|
GstTimedValueControlSource *tvcs;
|
||||||
|
GstElement *elem;
|
||||||
|
gdouble *raw_values;
|
||||||
|
GValue *g_values;
|
||||||
|
gint *values;
|
||||||
|
|
||||||
|
elem = gst_element_factory_make ("testobj", NULL);
|
||||||
|
|
||||||
|
/* new interpolation control source */
|
||||||
|
cs = gst_interpolation_control_source_new ();
|
||||||
|
tvcs = (GstTimedValueControlSource *) cs;
|
||||||
|
|
||||||
|
fail_unless (gst_object_add_control_binding (GST_OBJECT (elem),
|
||||||
|
gst_direct_control_binding_new_absolute (GST_OBJECT (elem), "int",
|
||||||
|
cs)));
|
||||||
|
|
||||||
|
/* set interpolation mode */
|
||||||
|
g_object_set (cs, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL);
|
||||||
|
|
||||||
|
/* set control values */
|
||||||
|
fail_unless (gst_timed_value_control_source_set (tvcs, 0 * GST_SECOND, 0));
|
||||||
|
fail_unless (gst_timed_value_control_source_set (tvcs, 1 * GST_SECOND, 100));
|
||||||
|
|
||||||
|
/* now pull in raw-values for some timestamps */
|
||||||
|
raw_values = g_new (gdouble, 3);
|
||||||
|
|
||||||
|
fail_unless (gst_control_source_get_value_array (cs,
|
||||||
|
0, GST_SECOND / 2, 3, raw_values));
|
||||||
|
fail_unless_equals_float ((raw_values)[0], 0);
|
||||||
|
fail_unless_equals_float ((raw_values)[1], 50);
|
||||||
|
fail_unless_equals_float ((raw_values)[2], 100);
|
||||||
|
|
||||||
|
g_free (raw_values);
|
||||||
|
|
||||||
|
/* now pull in mapped GValues for some timestamps */
|
||||||
|
g_values = g_new0 (GValue, 3);
|
||||||
|
|
||||||
|
fail_unless (gst_object_get_g_value_array (GST_OBJECT (elem), "int",
|
||||||
|
0, GST_SECOND / 2, 3, g_values));
|
||||||
|
fail_unless_equals_int (g_value_get_int (&g_values[0]), 0);
|
||||||
|
fail_unless_equals_int (g_value_get_int (&g_values[1]), 50);
|
||||||
|
fail_unless_equals_int (g_value_get_int (&g_values[2]), 100);
|
||||||
|
|
||||||
|
g_free (g_values);
|
||||||
|
|
||||||
|
/* now pull in mapped values for some timestamps */
|
||||||
|
values = g_new0 (gint, 3);
|
||||||
|
|
||||||
|
fail_unless (gst_object_get_value_array (GST_OBJECT (elem), "int",
|
||||||
|
0, GST_SECOND / 2, 3, values));
|
||||||
|
fail_unless_equals_int (values[0], 0);
|
||||||
|
fail_unless_equals_int (values[1], 50);
|
||||||
|
fail_unless_equals_int (values[2], 100);
|
||||||
|
|
||||||
|
g_free (values);
|
||||||
|
|
||||||
|
gst_object_unref (cs);
|
||||||
|
gst_object_unref (elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
/* test retrieval of an array of values with get_value_array() */
|
/* test retrieval of an array of values with get_value_array() */
|
||||||
GST_START_TEST (controller_interpolation_linear_value_array)
|
GST_START_TEST (controller_interpolation_linear_value_array)
|
||||||
{
|
{
|
||||||
|
@ -1477,6 +1543,7 @@ gst_controller_suite (void)
|
||||||
tcase_add_test (tc, controller_interpolation_cubic_too_few_cp);
|
tcase_add_test (tc, controller_interpolation_cubic_too_few_cp);
|
||||||
tcase_add_test (tc, controller_interpolation_unset);
|
tcase_add_test (tc, controller_interpolation_unset);
|
||||||
tcase_add_test (tc, controller_interpolation_unset_all);
|
tcase_add_test (tc, controller_interpolation_unset_all);
|
||||||
|
tcase_add_test (tc, controller_interpolation_linear_absolute_value_array);
|
||||||
tcase_add_test (tc, controller_interpolation_linear_value_array);
|
tcase_add_test (tc, controller_interpolation_linear_value_array);
|
||||||
tcase_add_test (tc, controller_interpolation_linear_invalid_values);
|
tcase_add_test (tc, controller_interpolation_linear_invalid_values);
|
||||||
tcase_add_test (tc, controller_interpolation_linear_default_values);
|
tcase_add_test (tc, controller_interpolation_linear_default_values);
|
||||||
|
|
1
tests/examples/controller/.gitignore
vendored
1
tests/examples/controller/.gitignore
vendored
|
@ -1,6 +1,7 @@
|
||||||
audio-example
|
audio-example
|
||||||
control-sources
|
control-sources
|
||||||
text-color-example
|
text-color-example
|
||||||
|
absolute-example
|
||||||
*.bb
|
*.bb
|
||||||
*.bbg
|
*.bbg
|
||||||
*.da
|
*.da
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
noinst_PROGRAMS = audio-example control-sources text-color-example
|
noinst_PROGRAMS = audio-example control-sources text-color-example absolute-example
|
||||||
|
|
||||||
AM_CFLAGS = $(GST_OBJ_CFLAGS) -I$(top_builddir)/libs
|
AM_CFLAGS = $(GST_OBJ_CFLAGS) -I$(top_builddir)/libs
|
||||||
|
|
||||||
|
|
97
tests/examples/controller/absolute-example.c
Normal file
97
tests/examples/controller/absolute-example.c
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* text-color-example.c
|
||||||
|
*
|
||||||
|
* Builds a pipeline with [videotestsrc ! textoverlay ! ximagesink] and
|
||||||
|
* moves text
|
||||||
|
*
|
||||||
|
* Needs gst-plugins-base installed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
#include <gst/controller/gstinterpolationcontrolsource.h>
|
||||||
|
#include <gst/controller/gstlfocontrolsource.h>
|
||||||
|
#include <gst/controller/gstargbcontrolbinding.h>
|
||||||
|
#include <gst/controller/gstdirectcontrolbinding.h>
|
||||||
|
|
||||||
|
gint
|
||||||
|
main (gint argc, gchar ** argv)
|
||||||
|
{
|
||||||
|
gint res = 1;
|
||||||
|
GstElement *src, *text, *sink;
|
||||||
|
GstElement *bin;
|
||||||
|
GstControlSource *cs;
|
||||||
|
GstClock *clock;
|
||||||
|
GstClockID clock_id;
|
||||||
|
GstClockReturn wait_ret;
|
||||||
|
|
||||||
|
gst_init (&argc, &argv);
|
||||||
|
|
||||||
|
/* build pipeline */
|
||||||
|
bin = gst_pipeline_new ("pipeline");
|
||||||
|
clock = gst_pipeline_get_clock (GST_PIPELINE (bin));
|
||||||
|
src = gst_element_factory_make ("videotestsrc", NULL);
|
||||||
|
if (!src) {
|
||||||
|
GST_WARNING ("need videotestsrc from gst-plugins-base");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
g_object_set (src, "pattern", /* red */ 4,
|
||||||
|
NULL);
|
||||||
|
text = gst_element_factory_make ("textoverlay", NULL);
|
||||||
|
if (!text) {
|
||||||
|
GST_WARNING ("need textoverlay from gst-plugins-base");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
g_object_set (text,
|
||||||
|
"text", "GStreamer rocks!",
|
||||||
|
"font-desc", "Sans, 30",
|
||||||
|
"xpos", 0.0, "wrap-mode", -1, "halignment", /* position */ 4,
|
||||||
|
"valignment", /* position */ 3,
|
||||||
|
NULL);
|
||||||
|
sink = gst_element_factory_make ("ximagesink", NULL);
|
||||||
|
if (!sink) {
|
||||||
|
GST_WARNING ("need ximagesink from gst-plugins-base");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_bin_add_many (GST_BIN (bin), src, text, sink, NULL);
|
||||||
|
if (!gst_element_link_many (src, text, sink, NULL)) {
|
||||||
|
GST_WARNING ("can't link elements");
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setup control sources */
|
||||||
|
cs = gst_interpolation_control_source_new ();
|
||||||
|
gst_object_add_control_binding (GST_OBJECT_CAST (text),
|
||||||
|
gst_direct_control_binding_new_absolute (GST_OBJECT_CAST (text), "deltax",
|
||||||
|
cs));
|
||||||
|
|
||||||
|
g_object_set (cs, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL);
|
||||||
|
|
||||||
|
// At second 0 the text will be at 0px on the x-axis
|
||||||
|
gst_timed_value_control_source_set ((GstTimedValueControlSource *) cs, 0, 0);
|
||||||
|
// At second 5 the text will be at 1000px on the x-axis
|
||||||
|
gst_timed_value_control_source_set ((GstTimedValueControlSource *) cs,
|
||||||
|
GST_SECOND * 5, 1000);
|
||||||
|
|
||||||
|
gst_object_unref (cs);
|
||||||
|
|
||||||
|
/* run for 10 seconds */
|
||||||
|
clock_id =
|
||||||
|
gst_clock_new_single_shot_id (clock,
|
||||||
|
gst_clock_get_time (clock) + (10 * GST_SECOND));
|
||||||
|
|
||||||
|
if (gst_element_set_state (bin, GST_STATE_PLAYING)) {
|
||||||
|
if ((wait_ret = gst_clock_id_wait (clock_id, NULL)) != GST_CLOCK_OK) {
|
||||||
|
GST_WARNING ("clock_id_wait returned: %d", wait_ret);
|
||||||
|
}
|
||||||
|
gst_element_set_state (bin, GST_STATE_NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cleanup */
|
||||||
|
gst_clock_id_unref (clock_id);
|
||||||
|
gst_object_unref (G_OBJECT (clock));
|
||||||
|
gst_object_unref (G_OBJECT (bin));
|
||||||
|
res = 0;
|
||||||
|
Error:
|
||||||
|
return (res);
|
||||||
|
}
|
Loading…
Reference in a new issue