]> git.sesse.net Git - vlc/blobdiff - modules/access/v4l2/controls.c
decklink: update build rules
[vlc] / modules / access / v4l2 / controls.c
index 9cef84c2984120707b8a1e520086ccf532d999f0..0479d2931a052f083e26925ec519dbb45de74e3b 100644 (file)
@@ -1,40 +1,44 @@
 /*****************************************************************************
  * controls.c : Video4Linux2 device controls for vlc
  *****************************************************************************
- * Copyright (C) 2002-2011 the VideoLAN team
+ * Copyright (C) 2002-2011 VLC authors and VideoLAN
  *
  * Authors: Benjamin Pracht <bigben at videolan dot org>
  *          Richard Hosking <richard at hovis dot net>
  *          Antoine Cellerier <dionoea at videolan d.t org>
  *          Dennis Lou <dlou99 at yahoo dot com>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
 
-#include "v4l2.h"
+#include <stdio.h>
 #include <ctype.h>
 #include <assert.h>
 #include <sys/ioctl.h>
 
+#include <vlc_common.h>
+
+#include "v4l2.h"
+
 typedef struct vlc_v4l2_ctrl_name
 {
-    const char name[20];
+    const char name[28];
     uint32_t cid;
 } vlc_v4l2_ctrl_name_t;
 
@@ -51,34 +55,45 @@ static const vlc_v4l2_ctrl_name_t controls[] =
     { "audio-treble", V4L2_CID_AUDIO_TREBLE },
     { "audio-mute", V4L2_CID_AUDIO_MUTE },
     { "audio-loudness", V4L2_CID_AUDIO_LOUDNESS },
-    { "black-level", V4L2_CID_BLACK_LEVEL },
     { "auto-white-balance", V4L2_CID_AUTO_WHITE_BALANCE },
     { "do-white-balance", V4L2_CID_DO_WHITE_BALANCE },
     { "red-balance", V4L2_CID_RED_BALANCE },
     { "blue-balance", V4L2_CID_BLUE_BALANCE },
     { "gamma", V4L2_CID_GAMMA },
-    { "exposure", V4L2_CID_EXPOSURE },
     { "autogain", V4L2_CID_AUTOGAIN },
     { "gain", V4L2_CID_GAIN },
     { "hflip", V4L2_CID_HFLIP },
     { "vflip", V4L2_CID_VFLIP },
-    { "hcenter", V4L2_CID_HCENTER },
-    { "vcenter", V4L2_CID_VCENTER },
-    /* TODO: add more standardized controls */
+    { "power-line-frequency", V4L2_CID_POWER_LINE_FREQUENCY },
+    { "hue-auto", V4L2_CID_HUE_AUTO },
+    { "white-balance-temperature", V4L2_CID_WHITE_BALANCE_TEMPERATURE },
+    { "sharpness", V4L2_CID_SHARPNESS },
+    { "backlight-compensation", V4L2_CID_BACKLIGHT_COMPENSATION },
+    { "chroma-gain-auto", V4L2_CID_CHROMA_AGC },
+    { "color-killer", V4L2_CID_COLOR_KILLER },
+    { "color-effect", V4L2_CID_COLORFX },
+    { "rotate", V4L2_CID_ROTATE },
+    { "bg-color", V4L2_CID_BG_COLOR }, // NOTE: output only
+    { "chroma-gain", V4L2_CID_CHROMA_GAIN },
+    { "brightness-auto", V4L2_CID_AUTOBRIGHTNESS },
+    { "band-stop-filter", V4L2_CID_BAND_STOP_FILTER },
+
+    { "illuminators-1", V4L2_CID_ILLUMINATORS_1 }, // NOTE: don't care?
+    { "illuminators-2", V4L2_CID_ILLUMINATORS_2 },
 #define CTRL_CID_KNOWN(cid) \
     ((((uint32_t)cid) - V4L2_CID_BRIGHTNESS) \
-        <= (V4L2_CID_VCENTER - V4L2_CID_BRIGHTNESS))
+        <= (V4L2_CID_BAND_STOP_FILTER - V4L2_CID_BRIGHTNESS))
 };
 
-typedef struct vlc_v4l2_ctrl
+struct vlc_v4l2_ctrl
 {
     int                   fd;
     uint32_t              id;
-    enum v4l2_ctrl_type   type;
+    uint8_t               type;
     char                  name[32];
     int32_t               default_value;
     struct vlc_v4l2_ctrl *next;
-} vlc_v4l2_ctrl_t;
+};
 
 static int ControlSet (const vlc_v4l2_ctrl_t *c, int_fast32_t value)
 {
@@ -96,8 +111,27 @@ static int ControlSet64 (const vlc_v4l2_ctrl_t *c, int64_t value)
     struct v4l2_ext_control ext_ctrl = {
         .id = c->id,
         .size = 0,
-        .value64 = value,
     };
+    ext_ctrl.value64 = value;
+    struct v4l2_ext_controls ext_ctrls = {
+        .ctrl_class = V4L2_CTRL_ID2CLASS(c->id),
+        .count = 1,
+        .error_idx = 0,
+        .controls = &ext_ctrl,
+    };
+
+    if (v4l2_ioctl (c->fd, VIDIOC_S_EXT_CTRLS, &ext_ctrls) < 0)
+        return -1;
+    return 0;
+}
+
+static int ControlSetStr (const vlc_v4l2_ctrl_t *c, const char *restrict value)
+{
+    struct v4l2_ext_control ext_ctrl = {
+        .id = c->id,
+        .size = strlen (value) + 1,
+    };
+    ext_ctrl.string = (char *)value;
     struct v4l2_ext_controls ext_ctrls = {
         .ctrl_class = V4L2_CTRL_ID2CLASS(c->id),
         .count = 1,
@@ -121,6 +155,7 @@ static int ControlSetCallback (vlc_object_t *obj, const char *var,
         case V4L2_CTRL_TYPE_INTEGER:
         case V4L2_CTRL_TYPE_MENU:
         case V4L2_CTRL_TYPE_BITMASK:
+        case V4L2_CTRL_TYPE_INTEGER_MENU:
             ret = ControlSet (ctrl, cur.i_int);
             break;
         case V4L2_CTRL_TYPE_BOOLEAN:
@@ -132,6 +167,9 @@ static int ControlSetCallback (vlc_object_t *obj, const char *var,
         case V4L2_CTRL_TYPE_INTEGER64:
             ret = ControlSet64 (ctrl, cur.i_int);
             break;
+        case V4L2_CTRL_TYPE_STRING:
+            ret = ControlSetStr (ctrl, cur.psz_string);
+            break;
         default:
             assert (0);
     }
@@ -153,6 +191,7 @@ static void ControlsReset (vlc_object_t *obj, vlc_v4l2_ctrl_t *list)
         {
             case V4L2_CTRL_TYPE_INTEGER:
             case V4L2_CTRL_TYPE_MENU:
+            case V4L2_CTRL_TYPE_INTEGER_MENU:
                 var_SetInteger (obj, list->name, list->default_value);
                 break;
             case V4L2_CTRL_TYPE_BOOLEAN:
@@ -215,6 +254,7 @@ next:
                     case V4L2_CTRL_TYPE_INTEGER:
                     case V4L2_CTRL_TYPE_BOOLEAN:
                     case V4L2_CTRL_TYPE_MENU:
+                    case V4L2_CTRL_TYPE_INTEGER_MENU:
                     {
                         long val = strtol (value, &end, 0);
                         if (*end)
@@ -240,6 +280,10 @@ next:
                         break;
                     }
 
+                    case V4L2_CTRL_TYPE_STRING:
+                        ControlSetStr (c, value);
+                        break;
+
                     case V4L2_CTRL_TYPE_BITMASK:
                     {
                         unsigned long val = strtoul (value, &end, 0);
@@ -301,7 +345,7 @@ static vlc_v4l2_ctrl_t *ControlCreate (int fd,
         for (i = 0; query->name[i]; i++)
         {
             unsigned char c = query->name[i];
-            if (c == ' ')
+            if (c == ' ' || c == ',')
                 c = '_';
             if (c < 128)
                 c = tolower (c);
@@ -324,7 +368,7 @@ static vlc_v4l2_ctrl_t *ControlAddInteger (vlc_object_t *obj, int fd,
                                            const struct v4l2_queryctrl *query)
 {
     msg_Dbg (obj, " integer  %s (%08"PRIX32")", query->name, query->id);
-    if (query->flags & (CTRL_FLAGS_IGNORE | V4L2_CTRL_FLAG_WRITE_ONLY))
+    if (query->flags & CTRL_FLAGS_IGNORE)
         return NULL;
 
     vlc_v4l2_ctrl_t *c = ControlCreate (fd, query);
@@ -365,7 +409,7 @@ static vlc_v4l2_ctrl_t *ControlAddBoolean (vlc_object_t *obj, int fd,
                                            const struct v4l2_queryctrl *query)
 {
     msg_Dbg (obj, " boolean  %s (%08"PRIX32")", query->name, query->id);
-    if (query->flags & (CTRL_FLAGS_IGNORE | V4L2_CTRL_FLAG_WRITE_ONLY))
+    if (query->flags & CTRL_FLAGS_IGNORE)
         return NULL;
 
     vlc_v4l2_ctrl_t *c = ControlCreate (fd, query);
@@ -398,7 +442,7 @@ static vlc_v4l2_ctrl_t *ControlAddMenu (vlc_object_t *obj, int fd,
                                         const struct v4l2_queryctrl *query)
 {
     msg_Dbg (obj, " menu     %s (%08"PRIX32")", query->name, query->id);
-    if (query->flags & (CTRL_FLAGS_IGNORE | V4L2_CTRL_FLAG_WRITE_ONLY))
+    if (query->flags & CTRL_FLAGS_IGNORE)
         return NULL;
 
     vlc_v4l2_ctrl_t *c = ControlCreate (fd, query);
@@ -422,12 +466,12 @@ static vlc_v4l2_ctrl_t *ControlAddMenu (vlc_object_t *obj, int fd,
         val.i_int = ctrl.value;
         var_Change (obj, c->name, VLC_VAR_SETVALUE, &val, NULL);
     }
-    val.b_bool = query->default_value;
-    var_Change (obj, c->name, VLC_VAR_SETDEFAULT, &val, NULL);
     val.i_int = query->minimum;
     var_Change (obj, c->name, VLC_VAR_SETMIN, &val, NULL);
     val.i_int = query->maximum;
     var_Change (obj, c->name, VLC_VAR_SETMAX, &val, NULL);
+    val.i_int = query->default_value;
+    var_Change (obj, c->name, VLC_VAR_SETDEFAULT, &val, NULL);
 
     /* Import menu choices */
     for (uint_fast32_t idx = query->minimum;
@@ -460,8 +504,10 @@ static vlc_v4l2_ctrl_t *ControlAddButton (vlc_object_t *obj, int fd,
         return NULL;
 
     if (var_Create (obj, c->name, VLC_VAR_VOID | VLC_VAR_ISCOMMAND))
+    {
+        free (c);
         return NULL;
-    (void) fd;
+    }
     return c;
 }
 
@@ -469,7 +515,7 @@ static vlc_v4l2_ctrl_t *ControlAddInteger64 (vlc_object_t *obj, int fd,
                                             const struct v4l2_queryctrl *query)
 {
     msg_Dbg (obj, " 64-bits  %s (%08"PRIX32")", query->name, query->id);
-    if (query->flags & (CTRL_FLAGS_IGNORE | V4L2_CTRL_FLAG_WRITE_ONLY))
+    if (query->flags & CTRL_FLAGS_IGNORE)
         return NULL;
 
     vlc_v4l2_ctrl_t *c = ControlCreate (fd, query);
@@ -482,6 +528,22 @@ static vlc_v4l2_ctrl_t *ControlAddInteger64 (vlc_object_t *obj, int fd,
         return NULL;
     }
 
+    struct v4l2_ext_control ext_ctrl = { .id = c->id, .size = 0, };
+    struct v4l2_ext_controls ext_ctrls = {
+        .ctrl_class = V4L2_CTRL_ID2CLASS(c->id),
+        .count = 1,
+        .error_idx = 0,
+        .controls = &ext_ctrl,
+    };
+
+    if (v4l2_ioctl (c->fd, VIDIOC_G_EXT_CTRLS, &ext_ctrls) >= 0)
+    {
+        vlc_value_t val = { .i_int = ext_ctrl.value64 };
+
+        msg_Dbg (obj, "  current: %"PRId64, val.i_int);
+        var_Change (obj, c->name, VLC_VAR_SETVALUE, &val, NULL);
+    }
+
     return c;
 }
 
@@ -493,11 +555,57 @@ static vlc_v4l2_ctrl_t *ControlAddClass (vlc_object_t *obj, int fd,
     return NULL;
 }
 
+static vlc_v4l2_ctrl_t *ControlAddString (vlc_object_t *obj, int fd,
+                                          const struct v4l2_queryctrl *query)
+{
+    msg_Dbg (obj, " string   %s (%08"PRIX32")", query->name, query->id);
+    if ((query->flags & CTRL_FLAGS_IGNORE) || query->maximum > 65535)
+        return NULL;
+
+    vlc_v4l2_ctrl_t *c = ControlCreate (fd, query);
+    if (unlikely(c == NULL))
+        return NULL;
+
+    if (var_Create (obj, c->name, VLC_VAR_STRING | VLC_VAR_ISCOMMAND))
+    {
+        free (c);
+        return NULL;
+    }
+
+    /* Get current value */
+    char *buf = malloc (query->maximum + 1);
+    if (likely(buf != NULL))
+    {
+        struct v4l2_ext_control ext_ctrl = {
+            .id = c->id,
+            .size = query->maximum + 1,
+        };
+        ext_ctrl.string = buf;
+        struct v4l2_ext_controls ext_ctrls = {
+            .ctrl_class = V4L2_CTRL_ID2CLASS(c->id),
+            .count = 1,
+            .error_idx = 0,
+            .controls = &ext_ctrl,
+        };
+
+        if (v4l2_ioctl (c->fd, VIDIOC_G_EXT_CTRLS, &ext_ctrls) >= 0)
+        {
+            vlc_value_t val = { .psz_string = buf };
+
+            msg_Dbg (obj, "  current: \"%s\"", buf);
+            var_Change (obj, c->name, VLC_VAR_SETVALUE, &val, NULL);
+        }
+        free (buf);
+    }
+
+    return c;
+}
+
 static vlc_v4l2_ctrl_t *ControlAddBitMask (vlc_object_t *obj, int fd,
                                            const struct v4l2_queryctrl *query)
 {
     msg_Dbg (obj, " bit mask %s (%08"PRIX32")", query->name, query->id);
-    if (query->flags & (CTRL_FLAGS_IGNORE | V4L2_CTRL_FLAG_WRITE_ONLY))
+    if (query->flags & CTRL_FLAGS_IGNORE)
         return NULL;
 
     vlc_v4l2_ctrl_t *c = ControlCreate (fd, query);
@@ -529,6 +637,62 @@ static vlc_v4l2_ctrl_t *ControlAddBitMask (vlc_object_t *obj, int fd,
     return c;
 }
 
+static vlc_v4l2_ctrl_t *ControlAddIntMenu (vlc_object_t *obj, int fd,
+                                           const struct v4l2_queryctrl *query)
+{
+    msg_Dbg (obj, " int menu %s (%08"PRIX32")", query->name, query->id);
+    if (query->flags & CTRL_FLAGS_IGNORE)
+        return NULL;
+
+    vlc_v4l2_ctrl_t *c = ControlCreate (fd, query);
+    if (unlikely(c == NULL))
+        return NULL;
+
+    if (var_Create (obj, c->name, VLC_VAR_INTEGER | VLC_VAR_HASCHOICE
+                                                  | VLC_VAR_ISCOMMAND))
+    {
+        free (c);
+        return NULL;
+    }
+
+    vlc_value_t val;
+    struct v4l2_control ctrl = { .id = query->id };
+
+    if (v4l2_ioctl (fd, VIDIOC_G_CTRL, &ctrl) >= 0)
+    {
+        msg_Dbg (obj, "  current: %"PRId32", default: %"PRId32,
+                 ctrl.value, query->default_value);
+        val.i_int = ctrl.value;
+        var_Change (obj, c->name, VLC_VAR_SETVALUE, &val, NULL);
+    }
+    val.i_int = query->minimum;
+    var_Change (obj, c->name, VLC_VAR_SETMIN, &val, NULL);
+    val.i_int = query->maximum;
+    var_Change (obj, c->name, VLC_VAR_SETMAX, &val, NULL);
+    val.i_int = query->default_value;
+    var_Change (obj, c->name, VLC_VAR_SETDEFAULT, &val, NULL);
+
+    /* Import menu choices */
+    for (uint_fast32_t idx = query->minimum;
+         idx <= (uint_fast32_t)query->maximum;
+         idx++)
+    {
+        struct v4l2_querymenu menu = { .id = query->id, .index = idx };
+        char name[sizeof ("-9223372036854775808")];
+
+        if (v4l2_ioctl (fd, VIDIOC_QUERYMENU, &menu) < 0)
+            continue;
+        msg_Dbg (obj, "  choice %"PRIu32") %"PRId64, menu.index, menu.value);
+
+        vlc_value_t text;
+        val.i_int = menu.index;
+        sprintf (name, "%"PRId64, menu.value);
+        text.psz_string = name;
+        var_Change (obj, c->name, VLC_VAR_ADDCHOICE, &val, &text);
+    }
+    return c;
+}
+
 static vlc_v4l2_ctrl_t *ControlAddUnknown (vlc_object_t *obj, int fd,
                                            const struct v4l2_queryctrl *query)
 {
@@ -559,7 +723,9 @@ vlc_v4l2_ctrl_t *ControlsInit (vlc_object_t *obj, int fd)
         [V4L2_CTRL_TYPE_BUTTON] = ControlAddButton,
         [V4L2_CTRL_TYPE_INTEGER64] = ControlAddInteger64,
         [V4L2_CTRL_TYPE_CTRL_CLASS] = ControlAddClass,
+        [V4L2_CTRL_TYPE_STRING] = ControlAddString,
         [V4L2_CTRL_TYPE_BITMASK] = ControlAddBitMask,
+        [V4L2_CTRL_TYPE_INTEGER_MENU] = ControlAddIntMenu,
     };
 
     vlc_v4l2_ctrl_t *list = NULL;