Port gtk-doc comments to their equivalent markdown syntax
[platform/upstream/gstreamer.git] / libs / gst / controller / gstdirectcontrolbinding.c
index 40768d0..9e5955d 100644 (file)
  *
  * You should have received a copy of the GNU Library General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 /**
  * SECTION:gstdirectcontrolbinding
- * @short_description: direct attachment for control source sources
+ * @title: GstDirectControlBinding
+ * @short_description: direct attachment for control sources
  *
- * A value mapping object that attaches control sources to gobject properties.
+ * A value mapping object that attaches control sources to gobject properties. It
+ * will map the control values directly to the target property range. If a
+ * non-absolute direct control binding is used, the value range [0.0 ... 1.0]
+ * is mapped to full target property range, and all values outside the range
+ * will be clipped. An absolute control binding will not do any value
+ * transformations.
  */
 
-
 #include <glib-object.h>
 #include <gst/gst.h>
 
 #include "gstdirectcontrolbinding.h"
 
-#include <math.h>
+#include <gst/math-compat.h>
 
 #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,
@@ -52,12 +58,16 @@ static GValue *gst_direct_control_binding_get_value (GstControlBinding * _self,
     GstClockTime timestamp);
 static gboolean gst_direct_control_binding_get_value_array (GstControlBinding *
     _self, GstClockTime timestamp, GstClockTime interval, guint n_values,
+    gpointer values);
+static gboolean gst_direct_control_binding_get_g_value_array (GstControlBinding
+    * _self, GstClockTime timestamp, GstClockTime interval, guint n_values,
     GValue * values);
 
 #define _do_init \
   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gstdirectcontrolbinding", 0, \
       "dynamic parameter control source attachment");
 
+#define gst_direct_control_binding_parent_class parent_class
 G_DEFINE_TYPE_WITH_CODE (GstDirectControlBinding, gst_direct_control_binding,
     GST_TYPE_CONTROL_BINDING, _do_init);
 
@@ -65,6 +75,7 @@ enum
 {
   PROP_0,
   PROP_CS,
+  PROP_ABSOLUTE,
   PROP_LAST
 };
 
@@ -72,36 +83,72 @@ static GParamSpec *properties[PROP_LAST];
 
 /* mapping functions */
 
-#define DEFINE_CONVERT(type,Type,TYPE) \
+#define DEFINE_CONVERT(type,Type,TYPE,ROUNDING_OP) \
 static void \
-convert_to_##type (GstDirectControlBinding *self, gdouble s, GValue *d) \
+convert_g_value_to_##type (GstDirectControlBinding *self, gdouble s, GValue *d) \
 { \
   GParamSpec##Type *pspec = G_PARAM_SPEC_##TYPE (((GstControlBinding *)self)->pspec); \
   g##type v; \
   \
   s = CLAMP (s, 0.0, 1.0); \
-  v = pspec->minimum + (g##type) ((pspec->maximum - pspec->minimum) * s); \
+  v = (g##type) ROUNDING_OP (pspec->minimum * (1-s)) + (g##type) ROUNDING_OP (pspec->maximum * s); \
+  g_value_set_##type (d, v); \
+} \
+\
+static void \
+convert_value_to_##type (GstDirectControlBinding *self, gdouble s, gpointer d_) \
+{ \
+  GParamSpec##Type *pspec = G_PARAM_SPEC_##TYPE (((GstControlBinding *)self)->pspec); \
+  g##type *d = (g##type *)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);
-DEFINE_CONVERT (uint, UInt, UINT);
-DEFINE_CONVERT (long, Long, LONG);
-DEFINE_CONVERT (ulong, ULong, ULONG);
-DEFINE_CONVERT (int64, Int64, INT64);
-DEFINE_CONVERT (uint64, UInt64, UINT64);
-DEFINE_CONVERT (float, Float, FLOAT);
-DEFINE_CONVERT (double, Double, DOUBLE);
+DEFINE_CONVERT (int, Int, INT, rint);
+DEFINE_CONVERT (uint, UInt, UINT, rint);
+DEFINE_CONVERT (long, Long, LONG, rint);
+DEFINE_CONVERT (ulong, ULong, ULONG, rint);
+DEFINE_CONVERT (int64, Int64, INT64, rint);
+DEFINE_CONVERT (uint64, UInt64, UINT64, rint);
+DEFINE_CONVERT (float, Float, FLOAT, /*NOOP*/);
+DEFINE_CONVERT (double, Double, DOUBLE, /*NOOP*/);
 
 static void
-convert_to_boolean (GstDirectControlBinding * self, gdouble s, GValue * d)
+convert_g_value_to_boolean (GstDirectControlBinding * self, gdouble s,
+    GValue * d)
 {
   s = CLAMP (s, 0.0, 1.0);
   g_value_set_boolean (d, (gboolean) (s + 0.5));
 }
 
 static void
-convert_to_enum (GstDirectControlBinding * self, gdouble s, GValue * d)
+convert_value_to_boolean (GstDirectControlBinding * self, gdouble s,
+    gpointer d_)
+{
+  gboolean *d = (gboolean *) d_;
+
+  s = CLAMP (s, 0.0, 1.0);
+  *d = (gboolean) (s + 0.5);
+}
+
+static void
+convert_g_value_to_enum (GstDirectControlBinding * self, gdouble s, GValue * d)
 {
   GParamSpecEnum *pspec =
       G_PARAM_SPEC_ENUM (((GstControlBinding *) self)->pspec);
@@ -113,6 +160,18 @@ convert_to_enum (GstDirectControlBinding * self, gdouble s, GValue * d)
   g_value_set_enum (d, e->values[v].value);
 }
 
+static void
+convert_value_to_enum (GstDirectControlBinding * self, gdouble s, gpointer d_)
+{
+  GParamSpecEnum *pspec =
+      G_PARAM_SPEC_ENUM (((GstControlBinding *) self)->pspec);
+  GEnumClass *e = pspec->enum_class;
+  gint *d = (gint *) d_;
+
+  s = CLAMP (s, 0.0, 1.0);
+  *d = e->values[(gint) (s * (e->n_values - 1))].value;
+}
+
 /* vmethods */
 
 static void
@@ -132,11 +191,19 @@ gst_direct_control_binding_class_init (GstDirectControlBindingClass * klass)
   control_binding_class->get_value = gst_direct_control_binding_get_value;
   control_binding_class->get_value_array =
       gst_direct_control_binding_get_value_array;
+  control_binding_class->get_g_value_array =
+      gst_direct_control_binding_get_g_value_array;
 
   properties[PROP_CS] =
       g_param_spec_object ("control-source", "ControlSource",
       "The control source",
       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);
@@ -154,9 +221,8 @@ gst_direct_control_binding_constructor (GType type, guint n_construct_params,
   GstDirectControlBinding *self;
 
   self =
-      GST_DIRECT_CONTROL_BINDING (G_OBJECT_CLASS
-      (gst_direct_control_binding_parent_class)
-      ->constructor (type, n_construct_params, construct_params));
+      GST_DIRECT_CONTROL_BINDING (G_OBJECT_CLASS (parent_class)->constructor
+      (type, n_construct_params, construct_params));
 
   if (GST_CONTROL_BINDING_PSPEC (self)) {
     GType type, base;
@@ -168,37 +234,54 @@ gst_direct_control_binding_constructor (GType type, guint n_construct_params,
 
     GST_DEBUG ("  using type %s", g_type_name (base));
 
-    // select mapping function
+    /* select mapping function */
+
+#define SET_CONVERT_FUNCTION(type) \
+    if (self->ABI.abi.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 = convert_to_int;
+        SET_CONVERT_FUNCTION (int);
         break;
       case G_TYPE_UINT:
-        self->convert = convert_to_uint;
+        SET_CONVERT_FUNCTION (uint);
         break;
       case G_TYPE_LONG:
-        self->convert = convert_to_long;
+        SET_CONVERT_FUNCTION (long);
         break;
       case G_TYPE_ULONG:
-        self->convert = convert_to_ulong;
+        SET_CONVERT_FUNCTION (ulong);
         break;
       case G_TYPE_INT64:
-        self->convert = convert_to_int64;
+        SET_CONVERT_FUNCTION (int64);
         break;
       case G_TYPE_UINT64:
-        self->convert = convert_to_uint64;
+        SET_CONVERT_FUNCTION (uint64);
         break;
       case G_TYPE_FLOAT:
-        self->convert = convert_to_float;
+        SET_CONVERT_FUNCTION (float);
         break;
       case G_TYPE_DOUBLE:
-        self->convert = convert_to_double;
+        SET_CONVERT_FUNCTION (double);
         break;
       case G_TYPE_BOOLEAN:
-        self->convert = convert_to_boolean;
+        self->convert_g_value = convert_g_value_to_boolean;
+        self->convert_value = convert_value_to_boolean;
+        self->byte_size = sizeof (gboolean);
         break;
       case G_TYPE_ENUM:
-        self->convert = convert_to_enum;
+        self->convert_g_value = convert_g_value_to_enum;
+        self->convert_value = convert_value_to_enum;
+        self->byte_size = sizeof (gint);
         break;
       default:
         GST_WARNING ("incomplete implementation for paramspec type '%s'",
@@ -218,7 +301,10 @@ gst_direct_control_binding_set_property (GObject * object, guint prop_id,
 
   switch (prop_id) {
     case PROP_CS:
-      self->cs = g_value_get_object (value);
+      self->cs = g_value_dup_object (value);
+      break;
+    case PROP_ABSOLUTE:
+      self->ABI.abi.want_absolute = g_value_get_boolean (value);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -236,6 +322,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->ABI.abi.want_absolute);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -249,6 +338,8 @@ gst_direct_control_binding_dispose (GObject * object)
 
   if (self->cs)
     gst_object_replace ((GstObject **) & self->cs, NULL);
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
 static void
@@ -256,7 +347,10 @@ gst_direct_control_binding_finalize (GObject * object)
 {
   GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (object);
 
-  g_value_unset (&self->cur_value);
+  if (G_IS_VALUE (&self->cur_value))
+    g_value_unset (&self->cur_value);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
 static gboolean
@@ -286,7 +380,7 @@ gst_direct_control_binding_sync_values (GstControlBinding * _self,
       GST_LOG_OBJECT (object, "  mapping %s to value of type %s", _self->name,
           G_VALUE_TYPE_NAME (dst_val));
       /* run mapping function to convert gdouble to GValue */
-      self->convert (self, src_val, dst_val);
+      self->convert_g_value (self, src_val, dst_val);
       /* we can make this faster
        * http://bugzilla.gnome.org/show_bug.cgi?id=536939
        */
@@ -315,7 +409,7 @@ gst_direct_control_binding_get_value (GstControlBinding * _self,
   if (gst_control_source_get_value (self->cs, timestamp, &src_val)) {
     dst_val = g_new0 (GValue, 1);
     g_value_init (dst_val, G_PARAM_SPEC_VALUE_TYPE (_self->pspec));
-    self->convert (self, src_val, dst_val);
+    self->convert_g_value (self, src_val, dst_val);
   } else {
     GST_LOG ("no control value for property %s at ts %" GST_TIME_FORMAT,
         _self->name, GST_TIME_ARGS (timestamp));
@@ -327,6 +421,49 @@ gst_direct_control_binding_get_value (GstControlBinding * _self,
 static gboolean
 gst_direct_control_binding_get_value_array (GstControlBinding * _self,
     GstClockTime timestamp, GstClockTime interval, guint n_values,
+    gpointer values_)
+{
+  GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self);
+  gint i;
+  gdouble *src_val;
+  gboolean res = FALSE;
+  GstDirectControlBindingConvertValue convert;
+  gint byte_size;
+  guint8 *values = (guint8 *) values_;
+
+  g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), FALSE);
+  g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
+  g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), FALSE);
+  g_return_val_if_fail (values, FALSE);
+  g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE);
+
+  convert = self->convert_value;
+  byte_size = self->byte_size;
+
+  src_val = g_new0 (gdouble, n_values);
+  if ((res = gst_control_source_get_value_array (self->cs, timestamp,
+              interval, n_values, src_val))) {
+    for (i = 0; i < n_values; i++) {
+      /* we will only get NAN for sparse control sources, such as triggers */
+      if (!isnan (src_val[i])) {
+        convert (self, src_val[i], (gpointer) values);
+      } else {
+        GST_LOG ("no control value for property %s at index %d", _self->name,
+            i);
+      }
+      values += byte_size;
+    }
+  } else {
+    GST_LOG ("failed to get control value for property %s at ts %"
+        GST_TIME_FORMAT, _self->name, GST_TIME_ARGS (timestamp));
+  }
+  g_free (src_val);
+  return res;
+}
+
+static gboolean
+gst_direct_control_binding_get_g_value_array (GstControlBinding * _self,
+    GstClockTime timestamp, GstClockTime interval, guint n_values,
     GValue * values)
 {
   GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self);
@@ -334,7 +471,7 @@ gst_direct_control_binding_get_value_array (GstControlBinding * _self,
   gdouble *src_val;
   gboolean res = FALSE;
   GType type;
-  GstDirectControlBindingConvert convert;
+  GstDirectControlBindingConvertGValue convert;
 
   g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), FALSE);
   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
@@ -342,13 +479,14 @@ gst_direct_control_binding_get_value_array (GstControlBinding * _self,
   g_return_val_if_fail (values, FALSE);
   g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE);
 
-  convert = self->convert;
+  convert = self->convert_g_value;
   type = G_PARAM_SPEC_VALUE_TYPE (_self->pspec);
 
   src_val = g_new0 (gdouble, n_values);
   if ((res = gst_control_source_get_value_array (self->cs, timestamp,
               interval, n_values, src_val))) {
     for (i = 0; i < n_values; i++) {
+      /* we will only get NAN for sparse control sources, such as triggers */
       if (!isnan (src_val[i])) {
         g_value_init (&values[i], type);
         convert (self, src_val[i], &values[i]);
@@ -371,10 +509,11 @@ gst_direct_control_binding_get_value_array (GstControlBinding * _self,
  * gst_direct_control_binding_new:
  * @object: the object of the property
  * @property_name: the property-name to attach the control source
- * @csource: the control source
+ * @cs: the control source
  *
  * Create a new control-binding that attaches the #GstControlSource to the
- * #GObject property.
+ * #GObject property. It will map the control source range [0.0 ... 1.0] to
+ * the full target property range, and clip all values outside this range.
  *
  * Returns: (transfer floating): the new #GstDirectControlBinding
  */
@@ -385,3 +524,26 @@ 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. It will directly map the control source values to the
+ * target property range without any transformations.
+ *
+ * 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);
+}