controller: Added absolute direct control binding, example and test

Fixes: 740502
API: gst_direct_control_binding_new_absolute
This commit is contained in:
Lazar Claudiu 2015-05-27 12:29:41 +03:00 committed by Stefan Sauer
parent d61ba38118
commit cb2c141eac
6 changed files with 243 additions and 26 deletions

View file

@ -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);
}

View file

@ -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__ */

View file

@ -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);

View file

@ -1,6 +1,7 @@
audio-example
control-sources
text-color-example
absolute-example
*.bb
*.bbg
*.da

View file

@ -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

View 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);
}