#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,
{
PROP_0,
PROP_CS,
+ PROP_ABSOLUTE,
PROP_LAST
};
\
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);
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);
}
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;
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;
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;
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);
+}
GValue cur_value;
gdouble last_value;
gint byte_size;
+ gboolean want_absolute;
GstDirectControlBindingConvertValue convert_value;
GstDirectControlBindingConvertGValue convert_g_value;
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__ */
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)
{
GstControlSource *cs;
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);
audio-example
control-sources
text-color-example
+absolute-example
*.bb
*.bbg
*.da
-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
--- /dev/null
+/*
+ * 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);
+}