This patch adds the ability to control the white balance temperature on
webcams in video(1). This is bound to keys W/w in steps of +/-10K (because
changing the temperature 1K at a time is tortuously slow given a typical
range of 2800-6500K, and +/-10 seems to roughly be the minimum difference
that my eyes can detect).

At least on my Logitech C920, one can only change the white balance
temperature once auto-white balance is turned off (if it's not off, the C920
refuses to change anything and the ioctl returns an error). This patch thus
turns auto-white balance on/off when you change/reset the white balance.
This is required by the USB video spec which doesn't seem too surprising
until you realise that the spec also says that the contrast value can't be
changed without auto-contrast being turned off. However, I can't see any
code anywhere which does this: perhaps auto-contrast is off on some, or all,
webcams by default?


Laurie


Index: video.c
===================================================================
RCS file: /cvs/xenocara/app/video/video.c,v
retrieving revision 1.30
diff -u -r1.30 video.c
--- video.c     1 Jul 2020 06:45:24 -0000       1.30
+++ video.c     13 Jul 2020 16:08:05 -0000
@@ -114,7 +114,10 @@
        { "gamma",      0, V4L2_CID_GAMMA,      0, 0, 0, 0, 0 },
 #define CTRL_SHARPNESS 6
        { "sharpness",  0, V4L2_CID_SHARPNESS,  0, 0, 0, 0, 0 },
-#define CTRL_LAST       7
+#define CTRL_WHITE_BALANCE_TEMPERATURE 7
+       { "white_balance_temperature",
+                       0, V4L2_CID_WHITE_BALANCE_TEMPERATURE,  0, 0, 0, 0, 0 },
+#define CTRL_LAST       8
        { NULL, 0, 0, 0, 0, 0, 0, 0 }
 };
 
@@ -730,6 +733,14 @@
                                if (vid->mode & M_IN_DEV)
                                        dev_set_ctrl(vid, CTRL_SATURATION, -1);
                                break;
+                       case 'W':
+                               if (vid->mode & M_IN_DEV)
+                                       dev_set_ctrl(vid, 
CTRL_WHITE_BALANCE_TEMPERATURE, 10);
+                               break;
+                       case 'w':
+                               if (vid->mode & M_IN_DEV)
+                                       dev_set_ctrl(vid, 
CTRL_WHITE_BALANCE_TEMPERATURE, -10);
+                               break;
                        default:
                                break;
                        }
@@ -1011,6 +1022,15 @@
                    ctrls[ctrl].name, d->path);
                return;
        }
+       /* The spec requires auto-white balance to be off before we can set the
+        * white balance temperature. */
+       if (ctrl == CTRL_WHITE_BALANCE_TEMPERATURE) {
+               control.id = V4L2_CID_AUTO_WHITE_BALANCE;
+               control.value = 0;
+               if (ioctl(d->fd, VIDIOC_S_CTRL, &control) != 0) {
+                       warn("VIDIOC_S_CTRL(auto_white_balance)");
+               }
+       }
        val = ctrls[ctrl].cur + ctrls[ctrl].step * change;
        if (val > ctrls[ctrl].max)
                val = ctrls[ctrl].max;
@@ -1054,6 +1074,15 @@
                if (vid->verbose > 0)
                        fprintf(stderr, "%s now %d\n", ctrls[i].name,
                            ctrls[i].cur);
+               /* After resetting the temperature, also turn auto-white
+                * balance back on. */
+               if (i == CTRL_WHITE_BALANCE_TEMPERATURE) {
+                       control.id = V4L2_CID_AUTO_WHITE_BALANCE;
+                       control.value = 1;
+                       if (ioctl(d->fd, VIDIOC_S_CTRL, &control) != 0) {
+                               warn("VIDIOC_S_CTRL(auto_white_balance)");
+                       }
+               }
        }
 }
 

Reply via email to