mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-27 11:32:51 +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
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
|
||||
|
||||
static GObject *gst_direct_control_binding_constructor (GType type,
|
||||
guint n_construct_params, GObjectConstructParam * construct_params);
|
||||
static void gst_direct_control_binding_set_property (GObject * object,
|
||||
|
@ -70,6 +71,7 @@ enum
|
|||
{
|
||||
PROP_0,
|
||||
PROP_CS,
|
||||
PROP_ABSOLUTE,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
|
@ -97,9 +99,23 @@ convert_value_to_##type (GstDirectControlBinding *self, gdouble s, gpointer d_)
|
|||
\
|
||||
s = CLAMP (s, 0.0, 1.0); \
|
||||
*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 (uint, UInt, UINT, rint);
|
||||
DEFINE_CONVERT (long, Long, LONG, rint);
|
||||
|
@ -180,6 +196,12 @@ gst_direct_control_binding_class_init (GstDirectControlBindingClass * klass)
|
|||
GST_TYPE_CONTROL_SOURCE,
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -209,46 +231,43 @@ gst_direct_control_binding_constructor (GType type, guint n_construct_params,
|
|||
GST_DEBUG (" using type %s", g_type_name (base));
|
||||
|
||||
/* 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) {
|
||||
case G_TYPE_INT:
|
||||
self->convert_g_value = convert_g_value_to_int;
|
||||
self->convert_value = convert_value_to_int;
|
||||
self->byte_size = sizeof (gint);
|
||||
SET_CONVERT_FUNCTION (int);
|
||||
break;
|
||||
case G_TYPE_UINT:
|
||||
self->convert_g_value = convert_g_value_to_uint;
|
||||
self->convert_value = convert_value_to_uint;
|
||||
self->byte_size = sizeof (guint);
|
||||
SET_CONVERT_FUNCTION (uint);
|
||||
break;
|
||||
case G_TYPE_LONG:
|
||||
self->convert_g_value = convert_g_value_to_long;
|
||||
self->convert_value = convert_value_to_long;
|
||||
self->byte_size = sizeof (glong);
|
||||
SET_CONVERT_FUNCTION (long);
|
||||
break;
|
||||
case G_TYPE_ULONG:
|
||||
self->convert_g_value = convert_g_value_to_ulong;
|
||||
self->convert_value = convert_value_to_ulong;
|
||||
self->byte_size = sizeof (gulong);
|
||||
SET_CONVERT_FUNCTION (ulong);
|
||||
break;
|
||||
case G_TYPE_INT64:
|
||||
self->convert_g_value = convert_g_value_to_int64;
|
||||
self->convert_value = convert_value_to_int64;
|
||||
self->byte_size = sizeof (gint64);
|
||||
SET_CONVERT_FUNCTION (int64);
|
||||
break;
|
||||
case G_TYPE_UINT64:
|
||||
self->convert_g_value = convert_g_value_to_uint64;
|
||||
self->convert_value = convert_value_to_uint64;
|
||||
self->byte_size = sizeof (guint64);
|
||||
SET_CONVERT_FUNCTION (uint64);
|
||||
break;
|
||||
case G_TYPE_FLOAT:
|
||||
self->convert_g_value = convert_g_value_to_float;
|
||||
self->convert_value = convert_value_to_float;
|
||||
self->byte_size = sizeof (gfloat);
|
||||
SET_CONVERT_FUNCTION (float);
|
||||
break;
|
||||
case G_TYPE_DOUBLE:
|
||||
self->convert_g_value = convert_g_value_to_double;
|
||||
self->convert_value = convert_value_to_double;
|
||||
self->byte_size = sizeof (gdouble);
|
||||
SET_CONVERT_FUNCTION (double);
|
||||
break;
|
||||
case G_TYPE_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:
|
||||
self->cs = g_value_dup_object (value);
|
||||
break;
|
||||
case PROP_ABSOLUTE:
|
||||
self->want_absolute = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -296,6 +318,9 @@ gst_direct_control_binding_get_property (GObject * object, guint prop_id,
|
|||
case PROP_CS:
|
||||
g_value_set_object (value, self->cs);
|
||||
break;
|
||||
case PROP_ABSOLUTE:
|
||||
g_value_set_boolean (value, self->want_absolute);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
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,
|
||||
"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;
|
||||
gdouble last_value;
|
||||
gint byte_size;
|
||||
gboolean want_absolute;
|
||||
|
||||
GstDirectControlBindingConvertValue convert_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,
|
||||
GstControlSource * cs);
|
||||
|
||||
GstControlBinding * gst_direct_control_binding_new_absolute (GstObject * object, const gchar * property_name,
|
||||
GstControlSource * cs);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_DIRECT_CONTROL_BINDING_H__ */
|
||||
|
|
|
@ -597,6 +597,72 @@ GST_START_TEST (controller_interpolation_unset_all)
|
|||
|
||||
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() */
|
||||
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_unset);
|
||||
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_invalid_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
|
||||
control-sources
|
||||
text-color-example
|
||||
absolute-example
|
||||
*.bb
|
||||
*.bbg
|
||||
*.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
|
||||
|
||||
|
|
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