On Mon, Jul 13, 2020 at 07:39:41PM +0100, Laurence Tratt wrote:

> video(1) allows users to adjust controls such as brightness, saturation
> (etc.) depending on the input device in question. These values persist even
> after video(1) has quit, allowing you to e.g. increase the brightness of a
> webcam before connecting to a video call. However, the only way to adjust
> values is to hold down keys in the GUI, which is slow, error prone, and
> can't easily be scripted.
> 
> This patch adds a "-c" option to video(1) which either takes the special
> value "reset" or a "control=value" pair. For example:
> 
>   $ video -c reset
> 
> resets all the controls to their default values. Assuming the input device
> in question supports brightness one can set that as follows:
> 
>   $ video -c brightness=200
> 
> Note that the available controls, and their min/max values, will vary from
> device to device.
> 
> To keep the patch simple, only one "-c" option can be passed to video(1) at
> a time. Note that passing this option causes video(1) to quit before
> displaying video (in identical fashion to "-q") which makes it useful for
> scripting purposes.

The attached patch reworks things a bit. First, it now works with
white_balance_temperature, which (at least on my C920) requires mmap_init to
be called first. Second, the previous patch sometimes set controls to
surprising values because it called what is (in effect) a "change control by
X" function. This patch now renames the "old" function to "dev_inc_ctrl" and
introduces a new "dev_set_ctrl_abs". This then provides an obvious
opportunity to simplify the reset function.

With this patch I can do things like:

  $ video -c white_balance_temperature=6500
  $ video -c brightness=200
  $ video && video -c reset && video

and see changes being made as appropriate.


Laurie



Index: video.1
===================================================================
RCS file: /cvs/xenocara/app/video/video.1,v
retrieving revision 1.15
diff -u -r1.15 video.1
--- video.1     17 Jul 2020 07:51:23 -0000      1.15
+++ video.1     17 Jul 2020 21:44:49 -0000
@@ -27,6 +27,7 @@
 .Bk -words
 .Op Fl \&gqRv
 .Op Fl a Ar adaptor
+.Op Fl c Ar reset | control=value
 .Op Fl e Ar encoding
 .Op Fl f Ar file
 .Op Fl i Ar input
@@ -81,6 +82,15 @@
 adaptor to use.
 The default is 0, the first adaptor reported by
 .Xr X 7 .
+.It Fl c Ar reset | control=value
+Set control value (e.g. brightness) and exit. The special name
+.Ql reset
+resets all values to their default. The available controls can be found
+with
+.Fl q
+and the default values with
+.Fl c Ar reset
+.Fl v .
 .It Fl e Ar encoding
 Lowercase FOURCC name of video encoding to use.
 Valid arguments are
Index: video.c
===================================================================
RCS file: /cvs/xenocara/app/video/video.c,v
retrieving revision 1.31
diff -u -r1.31 video.c
--- video.c     17 Jul 2020 07:51:23 -0000      1.31
+++ video.c     17 Jul 2020 21:44:49 -0000
@@ -192,7 +192,10 @@
 #define M_IN_FILE      0x4
 #define M_OUT_FILE     0x8
 #define M_QUERY                0x10
+#define M_RESET                0x20
+#define M_SET_CTRL     0x40
        int              mode;
+       char            *set_ctrl_str;
        int              verbose;
 };
 
@@ -212,10 +215,12 @@
 void dev_dump_info(struct video *);
 void dev_dump_query(struct video *);
 int dev_init(struct video *);
-void dev_set_ctrl(struct video *, int, int);
+void dev_inc_ctrl(struct video *, int, int);
+void dev_set_ctrl_abs(struct video *vid, int, int);
 void dev_set_ctrl_auto_white_balance(struct video *, int);
 void dev_reset_ctrls(struct video *);
 
+int parse_ctrl(struct video *, int *, int *);
 int parse_size(struct video *);
 int choose_size(struct video *);
 int choose_enc(struct video *);
@@ -241,9 +246,9 @@
 usage(void)
 {
        fprintf(stderr, "usage: %s [-gqRv] "
-           "[-a adaptor] [-e encoding] [-f file] [-i input] [-O output]\n"
-           "       %*s [-o output] [-r rate] [-s size]\n", __progname,
-           (int)strlen(__progname), "");
+           "[-a adaptor] [-c reset|control=value] [-e encoding] [-f file]\n"
+           "       %*s [-i input] [-O output] [-o output] [-r rate] [-s 
size]\n",
+           __progname, (int)strlen(__progname), "");
 }
 
 int
@@ -657,46 +662,46 @@
                        switch (str) {
                        case 'A':
                                if (vid->mode & M_IN_DEV)
-                                       dev_set_ctrl(vid, CTRL_SHARPNESS, 1);
+                                       dev_inc_ctrl(vid, CTRL_SHARPNESS, 1);
                                break;
                        case 'a':
                                if (vid->mode & M_IN_DEV)
-                                       dev_set_ctrl(vid, CTRL_SHARPNESS, -1);
+                                       dev_inc_ctrl(vid, CTRL_SHARPNESS, -1);
                                break;
                        case 'B':
                                if (vid->mode & M_IN_DEV)
-                                       dev_set_ctrl(vid, CTRL_BRIGHTNESS, 1);
+                                       dev_inc_ctrl(vid, CTRL_BRIGHTNESS, 1);
                                break;
                        case 'b':
                                if (vid->mode & M_IN_DEV)
-                                       dev_set_ctrl(vid, CTRL_BRIGHTNESS, -1);
+                                       dev_inc_ctrl(vid, CTRL_BRIGHTNESS, -1);
                                break;
                        case 'C':
                                if (vid->mode & M_IN_DEV)
-                                       dev_set_ctrl(vid, CTRL_CONTRAST, 1);
+                                       dev_inc_ctrl(vid, CTRL_CONTRAST, 1);
                                break;
                        case 'c':
                                if (vid->mode & M_IN_DEV)
-                                       dev_set_ctrl(vid, CTRL_CONTRAST, -1);
+                                       dev_inc_ctrl(vid, CTRL_CONTRAST, -1);
                                break;
                        case 'f':
                                resize_window(vid, 1);
                                break;
                        case 'G':
                                if (vid->mode & M_IN_DEV)
-                                       dev_set_ctrl(vid, CTRL_GAIN, 1);
+                                       dev_inc_ctrl(vid, CTRL_GAIN, 1);
                                break;
                        case 'g':
                                if (vid->mode & M_IN_DEV)
-                                       dev_set_ctrl(vid, CTRL_GAIN, -1);
+                                       dev_inc_ctrl(vid, CTRL_GAIN, -1);
                                break;
                        case 'H':
                                if (vid->mode & M_IN_DEV)
-                                       dev_set_ctrl(vid, CTRL_HUE, 1);
+                                       dev_inc_ctrl(vid, CTRL_HUE, 1);
                                break;
                        case 'h':
                                if (vid->mode & M_IN_DEV)
-                                       dev_set_ctrl(vid, CTRL_HUE, -1);
+                                       dev_inc_ctrl(vid, CTRL_HUE, -1);
                                break;
                        case 'O':
                                if (!wout && vid->verbose > 0)
@@ -710,11 +715,11 @@
                                break;
                        case 'M':
                                if (vid->mode & M_IN_DEV)
-                                       dev_set_ctrl(vid, CTRL_GAMMA, 1);
+                                       dev_inc_ctrl(vid, CTRL_GAMMA, 1);
                                break;
                        case 'm':
                                if (vid->mode & M_IN_DEV)
-                                       dev_set_ctrl(vid, CTRL_GAMMA, -1);
+                                       dev_inc_ctrl(vid, CTRL_GAMMA, -1);
                                break;
                        case 'p':
                                hold = !hold;
@@ -728,20 +733,20 @@
                                break;
                        case 'S':
                                if (vid->mode & M_IN_DEV)
-                                       dev_set_ctrl(vid, CTRL_SATURATION, 1);
+                                       dev_inc_ctrl(vid, CTRL_SATURATION, 1);
                                break;
                        case 's':
                                if (vid->mode & M_IN_DEV)
-                                       dev_set_ctrl(vid, CTRL_SATURATION, -1);
+                                       dev_inc_ctrl(vid, CTRL_SATURATION, -1);
                                break;
                        case 'W':
                                if (vid->mode & M_IN_DEV)
-                                       dev_set_ctrl(vid,
+                                       dev_inc_ctrl(vid,
                                            CTRL_WHITE_BALANCE_TEMPERATURE, 10);
                                break;
                        case 'w':
                                if (vid->mode & M_IN_DEV)
-                                       dev_set_ctrl(vid,
+                                       dev_inc_ctrl(vid,
                                            CTRL_WHITE_BALANCE_TEMPERATURE, 
-10);
                                break;
                        default:
@@ -1010,10 +1015,9 @@
 }
 
 void
-dev_set_ctrl(struct video *vid, int ctrl, int change)
+dev_inc_ctrl(struct video *vid, int ctrl, int change)
 {
        struct dev *d = &vid->dev;
-       struct v4l2_control control;
        int val;
 
        if (ctrl < 0 || ctrl >= CTRL_LAST) {
@@ -1025,6 +1029,25 @@
                    ctrls[ctrl].name, d->path);
                return;
        }
+       val = ctrls[ctrl].cur + ctrls[ctrl].step * change;
+       dev_set_ctrl_abs(vid, ctrl, val);
+}
+
+void
+dev_set_ctrl_abs(struct video *vid, int ctrl, int val)
+{
+       struct dev *d = &vid->dev;
+       struct v4l2_control control;
+
+       if (ctrl < 0 || ctrl >= CTRL_LAST) {
+               warnx("invalid control");
+               return;
+       }
+       if (!ctrls[ctrl].supported) {
+               warnx("control %s not supported by %s",
+                   ctrls[ctrl].name, d->path);
+               return;
+       }
        if (ctrl == CTRL_WHITE_BALANCE_TEMPERATURE) {
                /*
                 * The spec requires auto-white balance to be off before
@@ -1032,7 +1055,6 @@
                 */
                dev_set_ctrl_auto_white_balance(vid, 0);
        }
-       val = ctrls[ctrl].cur + ctrls[ctrl].step * change;
        if (val > ctrls[ctrl].max)
                val = ctrls[ctrl].max;
        else if (val < ctrls[ctrl].min)
@@ -1081,25 +1103,7 @@
        for (i = 0; i < CTRL_LAST; i++) {
                if (!ctrls[i].supported)
                        continue;
-               if (i == CTRL_WHITE_BALANCE_TEMPERATURE) {
-                       /*
-                        * We might be asked to reset before the white balance
-                        * temperature has been adjusted, so we need to make
-                        * sure that auto-white balance really is off.
-                        */
-                       dev_set_ctrl_auto_white_balance(vid, 0);
-               }
-               control.id = ctrls[i].id;
-               control.value = ctrls[i].def;
-               if (ioctl(d->fd, VIDIOC_S_CTRL, &control) != 0)
-                       warn("VIDIOC_S_CTRL(%s)", ctrls[i].name);
-               control.id = ctrls[i].id;
-               if (ioctl(d->fd, VIDIOC_G_CTRL, &control) != 0)
-                       warn("VIDIOC_G_CTRL(%s)", ctrls[i].name);
-               ctrls[i].cur = control.value;
-               if (vid->verbose > 0)
-                       fprintf(stderr, "%s now %d\n", ctrls[i].name,
-                           ctrls[i].cur);
+               dev_set_ctrl_abs(vid, i, ctrls[i].def);
                if (i == CTRL_WHITE_BALANCE_TEMPERATURE) {
                        dev_set_ctrl_auto_white_balance(vid, 1);
                }
@@ -1221,6 +1225,39 @@
        return 1;
 }
 
+
+int
+parse_ctrl(struct video *vid, int *ctrl_id, int *ctrl_val)
+{
+       char *valp;
+       const char *errstr;
+
+       if (!vid->set_ctrl_str) {
+               return 0;
+       }
+
+       valp = strsep(&vid->set_ctrl_str, "=");
+       if (*valp == '\0' || vid->set_ctrl_str == '\0') {
+               return 0;
+       }
+       for (*ctrl_id = 0; *ctrl_id < CTRL_LAST; (*ctrl_id)++) {
+               if (strcmp(valp, ctrls[*ctrl_id].name) == 0) {
+                       break;
+               }
+       }
+       if (*ctrl_id == CTRL_LAST) {
+               warnx("Unknown control '%s'", valp);
+               return 0;
+       }
+       *ctrl_val = strtonum(vid->set_ctrl_str, ctrls[*ctrl_id].min,
+           ctrls[*ctrl_id].max, &errstr);
+       if (errstr != NULL) {
+               warnx("control value '%s' is %s", valp, errstr);
+               return 0;
+       }
+       return 1;
+}
+
 int
 parse_size(struct video *vid)
 {
@@ -1481,6 +1518,8 @@
 int
 setup(struct video *vid)
 {
+       int ctrl_id, ctrl_val;
+
        if (vid->mode & M_IN_FILE) {
                if (!strcmp(vid->iofile, "-"))
                        vid->iofile_fd = STDIN_FILENO;
@@ -1520,6 +1559,7 @@
        if (!parse_size(vid) || !choose_size(vid))
                return 0;
 
+
        vid->bpf = vid->width * vid->height * encs[vid->enc].bpp / NBBY;
 
        if (vid->verbose > 0) {
@@ -1553,17 +1593,30 @@
        if ((vid->mode & M_IN_DEV) && !dev_init(vid))
                return 0;
 
+       if (vid->mmap_on) {
+               if (!mmap_init(vid))
+                       return 0;
+       }
+
+       if (vid->mode & M_SET_CTRL) {
+               if (!parse_ctrl(vid, &ctrl_id, &ctrl_val)) {
+                       return 0;
+               }
+               dev_set_ctrl_abs(vid, ctrl_id, ctrl_val);
+               return 1;
+       }
+
+       if (vid->mode & M_RESET) {
+               dev_reset_ctrls(vid);
+               return 1;
+       }
+
        if ((vid->mode & M_OUT_XV) && !xv_init(vid))
                return 0;
 
        if (vid->sz_str && !strcmp(vid->sz_str, "full"))
                resize_window(vid, 1);
 
-       if (vid->mmap_on) {
-               if (!mmap_init(vid))
-                       return 0;
-       }
-
        if (vid->mode & M_OUT_XV)
                net_wm_supported(vid);
 
@@ -1949,7 +2002,7 @@
        vid.mmap_on = 1; /* mmap method is default */
        wout = 1;
 
-       while ((ch = getopt(argc, argv, "gqRva:e:f:i:O:o:r:s:")) != -1) {
+       while ((ch = getopt(argc, argv, "gqRva:c:e:f:i:O:o:r:s:")) != -1) {
                switch (ch) {
                case 'a':
                        x->cur_adap = strtonum(optarg, 0, 4, &errstr);
@@ -1958,6 +2011,17 @@
                                errs++;
                        }
                        break;
+               case 'c':
+                       if ((vid.mode & M_RESET) || (vid.mode & M_SET_CTRL)) {
+                               warnx("Only one '-c' option allowed.");
+                               errs++;
+                       } else if (strcmp(optarg, "reset") == 0) {
+                               vid.mode |= M_RESET;
+                       } else {
+                               vid.mode |= M_SET_CTRL;
+                               vid.set_ctrl_str = strdup(optarg);
+                       }
+                       break;
                case 'e':
                        vid.enc = find_enc(optarg);
                        if (vid.enc >= ENC_LAST) {
@@ -2055,6 +2119,10 @@
 
        if (!setup(&vid))
                cleanup(&vid, 1);
+
+       if ((vid.mode & M_RESET) || (vid.mode & M_SET_CTRL)) {
+               cleanup(&vid, 0);
+       }
 
        if (vid.mode & M_IN_FILE) {
                if (pledge("stdio rpath", NULL) == -1)

Reply via email to