controller: Added absolute direct control binding, example and test
authorLazar Claudiu <lazar.claudiu.florin@gmail.com>
Wed, 27 May 2015 09:29:41 +0000 (12:29 +0300)
committerStefan Sauer <ensonic@users.sf.net>
Fri, 12 Jun 2015 08:07:24 +0000 (10:07 +0200)
Fixes: 740502
API: gst_direct_control_binding_new_absolute

libs/gst/controller/gstdirectcontrolbinding.c
libs/gst/controller/gstdirectcontrolbinding.h
tests/check/libs/controller.c
tests/examples/controller/.gitignore
tests/examples/controller/Makefile.am
tests/examples/controller/absolute-example.c [new file with mode: 0644]

index 9c2e626..6916556 100644 (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);
+}
index 597e5b0..ade2ea4 100644 (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__ */
index f385c6b..3a736cd 100644 (file)
@@ -598,6 +598,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)
 {
   GstControlSource *cs;
@@ -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);
index 120e16c..d650224 100644 (file)
@@ -1,6 +1,7 @@
 audio-example
 control-sources
 text-color-example
+absolute-example
 *.bb
 *.bbg
 *.da
index fd50697..6ead70c 100644 (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
 
diff --git a/tests/examples/controller/absolute-example.c b/tests/examples/controller/absolute-example.c
new file mode 100644 (file)
index 0000000..2bce7e7
--- /dev/null
@@ -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);
+}