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)"); + } + } } }