v4l2: add a property for arbitrary v4l2 controls
authorMichael Olbrich <m.olbrich@pengutronix.de>
Mon, 20 May 2013 14:45:37 +0000 (16:45 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Wed, 29 May 2013 18:18:11 +0000 (20:18 +0200)
This makes it possible to set any controls that can be set with
VIDIOC_S_CTRL.
The controls are set when the property is set (if the device is open)
and when the device is opened.

https://bugzilla.gnome.org/show_bug.cgi?id=698837

sys/v4l2/gstv4l2object.c
sys/v4l2/gstv4l2object.h
sys/v4l2/v4l2_calls.c
sys/v4l2/v4l2_calls.h

index 9e3212b..0957597 100644 (file)
@@ -490,6 +490,20 @@ gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class,
           "I/O mode",
           GST_TYPE_V4L2_IO_MODE, DEFAULT_PROP_IO_MODE,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstV4l2Src:extra-controls
+   *
+   * Additional v4l2 controls for the device. The controls are identified
+   * by the control name (lowercase with '_' for any non-alphanumeric
+   * characters).
+   *
+   * Since: 1.2
+   */
+  g_object_class_install_property (gobject_class, PROP_EXTRA_CONTROLS,
+      g_param_spec_boxed ("extra-controls", "Extra Controls",
+          "Extra v4l2 controls (CIDs) for the device",
+          GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
 GstV4l2Object *
@@ -654,6 +668,17 @@ gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
     case PROP_IO_MODE:
       v4l2object->req_mode = g_value_get_enum (value);
       break;
+    case PROP_EXTRA_CONTROLS:{
+      const GstStructure *s = gst_value_get_structure (value);
+
+      if (v4l2object->extra_controls)
+        gst_structure_free (v4l2object->extra_controls);
+
+      v4l2object->extra_controls = s ? gst_structure_copy (s) : NULL;
+      if (GST_V4L2_IS_OPEN (v4l2object))
+        gst_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
+      break;
+    }
     default:
       return FALSE;
       break;
@@ -730,6 +755,9 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
     case PROP_IO_MODE:
       g_value_set_enum (value, v4l2object->req_mode);
       break;
+    case PROP_EXTRA_CONTROLS:
+      gst_value_set_structure (value, v4l2object->extra_controls);
+      break;
     default:
       return FALSE;
       break;
index af58b61..d4fa9fe 100644 (file)
@@ -143,11 +143,13 @@ struct _GstV4l2Object {
   GList *colors;
   GList *norms;
   GList *channels;
+  GData *controls;
 
   /* properties */
   v4l2_std_id tv_norm;
   gchar *channel;
   gulong frequency;
+  GstStructure *extra_controls;
 
   /* X-overlay */
   GstV4l2Xv *xv;
@@ -176,7 +178,8 @@ GType gst_v4l2_object_get_type (void);
     PROP_SATURATION,                   \
     PROP_HUE,                           \
     PROP_TV_NORM,                       \
-    PROP_IO_MODE
+    PROP_IO_MODE,                       \
+    PROP_EXTRA_CONTROLS
 
 /* create/destroy */
 GstV4l2Object *        gst_v4l2_object_new              (GstElement * element,
index 21262ba..8b0d7fc 100644 (file)
@@ -270,6 +270,32 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
       GST_DEBUG_OBJECT (e, "skipping disabled control");
       continue;
     }
+    switch (control.type) {
+      case V4L2_CTRL_TYPE_INTEGER:
+      case V4L2_CTRL_TYPE_BOOLEAN:
+      case V4L2_CTRL_TYPE_MENU:
+      case V4L2_CTRL_TYPE_INTEGER_MENU:
+      case V4L2_CTRL_TYPE_BITMASK:
+      case V4L2_CTRL_TYPE_BUTTON:{
+        int i;
+        control.name[31] = '\0';
+        for (i = 0; control.name[i]; ++i) {
+          control.name[i] = g_ascii_tolower (control.name[i]);
+          if (!g_ascii_isalnum (control.name[i]))
+            control.name[i] = '_';
+        }
+        GST_INFO_OBJECT (e, "adding generic controls '%s'", control.name);
+        g_datalist_id_set_data (&v4l2object->controls,
+            g_quark_from_string ((const gchar *) control.name),
+            GINT_TO_POINTER (n));
+        break;
+      }
+      default:
+        GST_DEBUG_OBJECT (e,
+            "Control type for '%s' not suppored for extra controls.",
+            control.name);
+        break;
+    }
 
     switch (n) {
       case V4L2_CID_BRIGHTNESS:
@@ -407,6 +433,8 @@ gst_v4l2_empty_lists (GstV4l2Object * v4l2object)
   g_list_foreach (v4l2object->colors, (GFunc) g_object_unref, NULL);
   g_list_free (v4l2object->colors);
   v4l2object->colors = NULL;
+
+  g_datalist_clear (&v4l2object->controls);
 }
 
 /******************************************************
@@ -486,6 +514,9 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
   else
     gst_poll_fd_ctl_write (v4l2object->poll, &pollfd, TRUE);
 
+  if (v4l2object->extra_controls)
+    gst_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
+
   return TRUE;
 
   /* ERRORS */
@@ -811,6 +842,33 @@ ctrl_failed:
   }
 }
 
+static gboolean
+set_contol (GQuark field_id, const GValue * value, gpointer user_data)
+{
+  GstV4l2Object *v4l2object = user_data;
+  gpointer *d = g_datalist_id_get_data (&v4l2object->controls, field_id);
+  if (!d) {
+    GST_WARNING_OBJECT (v4l2object,
+        "Control '%s' does not exist or has an unsupported type.",
+        g_quark_to_string (field_id));
+    return TRUE;
+  }
+  if (!G_VALUE_HOLDS (value, G_TYPE_INT)) {
+    GST_WARNING_OBJECT (v4l2object,
+        "'int' value expected for control '%s'.", g_quark_to_string (field_id));
+    return TRUE;
+  }
+  gst_v4l2_set_attribute (v4l2object, GPOINTER_TO_INT (d),
+      g_value_get_int (value));
+  return TRUE;
+}
+
+gboolean
+gst_v4l2_set_controls (GstV4l2Object * v4l2object, GstStructure * controls)
+{
+  return gst_structure_foreach (controls, set_contol, v4l2object);
+}
+
 gboolean
 gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input)
 {
index 8261d3a..221d26e 100644 (file)
@@ -126,6 +126,9 @@ gboolean    gst_v4l2_set_attribute          (GstV4l2Object *v4l2object,
                                                 int             attribute,
                                                 const int       value);
 
+gboolean       gst_v4l2_set_controls           (GstV4l2Object * v4l2object,
+                                                GstStructure * controls);
+
 gboolean        gst_v4l2_get_capabilities       (GstV4l2Object * v4l2object);