Irrelevant backstory: As I started with Timescale as a Developer Advocate, I got a new Ubuntu laptop for work which I chose myself. Just when I was done installing most of the programs I use for work I realized that my webcam looks very flickery during calls. It is due to “an interaction between lights and the shutter speed of the webcam” as Google taught me. Now the thing is, I had this problem previously with an older Ubuntu laptop as well, but I didn’t quite remember how I had solved it before so I thought I’d document this process here now.

The process to make permanent changes to your webcam (or other video device) settings:

  1. Come up with the proper command (I’m using uvcdynctrl)
  2. Create a bash script with that command
  3. Create a service to run the bash script during start-up

Come up with the proper command Link to heading

To adjust webcam settings in the command line, you can use the uvcdynctrl package. This package should already be available in your Ubuntu but if not, this is how to install it:

sudo apt update
sudo apt install uvcdynctrl

After installing it you, you can set a lot of things with it.

In my case, I need to change the power line frequency:

uvcdynctrl -d video4 "--set=Power Line Frequency" 1

The -d parameter is --device which is the name of the device you want do adjust. In my case it is video4. If you don’t know the name of your device you can just guess the number (video1, video2, etc), or skip to the end of the article and I show you how to find it.

Unfortunately if you run the command above that will only apply the modification until you reboot. After reboot, all changes are lost. In order to make this change permanent you need to set up a service which runs this command everytime the computer starts.

Create bash script Link to heading

set_webcam.sh:

#!/bin/bash

uvcdynctrl -d video4 "--set=Power Line Frequency" 1

Nothing new here, just using the same command I used before.

Save it wherever you want (you’ll need to reference it later in your service file), I saved it to /usr/local/bin.

Create a service Link to heading

This is the general idea for a service file like this:

set_webcam.service: (save it to /etc/systemd/system)

[Unit]
Description=Set Logitech webcam frequency to 50Hz

[Service]
ExecStart=/usr/local/bin/set_webcam_freq.sh

[Install]
WantedBy=multi-user.target

This service will run everytime I boot up. But I found that in my case there’s a minor problem which you might encounter as well: the script appearently runs just before my webcam becomes availabe as a device, which means the service fails. If you encounter this problem you need to add a condition to only run the script after the device actually becomes available.

To achieve this, you need to edit one of udev rule files to add a symlink to your device which then you can use inside your service file. More on udev rules here.

So let’s edit, for example, /lib/udev/rules.d/99-systemd.rules, add this line to add a symlink to your device: (use the device name you have, in my case it’s video4)

KERNEL=="video4", SYMLINK="video4", TAG+="systemd"

After saving this file, add BindsTo and After parameters to the service file to reference your device:

set_webcam.service:

[Unit]
Description=Set Logitech webcam frequency to 50Hz
BindsTo=dev-video4.device
After=dev-video4.device

[Service]
ExecStart=/usr/local/bin/set_webcam_freq.sh

[Install]
WantedBy=multi-user.target

Make sure to enable the service so it runs during start-up:

systemctl enable set_webcam.service

That’s it. This service will run during each start-up after the video4 device (which is my Logitech webcam in my case) becomes available and modifies the webcam’s settings.

If you don’t know the device name of your webcam (video0, video1, etc), keep reading…

Find out your webcam’s device name Link to heading

Method 1 Link to heading

You can list all of your video devices with this command:

ls -ltrh /dev/video*

crw-rw----+ 1 root video 81, 0 máj   14 10:17 /dev/video0

If the output is something similar to this, and you only have one entry in the list, that’s awesome! You just found your webcam’s name is video0. But if you have multiple records showing up here - because you have multiple webcams connected or other reasons, keep reading.

Method 2 Link to heading

If you have multiple video devices connected like me, this method might be more useful.

If I type the command above, this is what I get:

crw-rw----+ 1 root video 81, 0 máj   14 10:17 /dev/video0
crw-rw----+ 1 root video 81, 2 máj   14 10:17 /dev/video2
crw-rw----+ 1 root video 81, 1 máj   14 10:17 /dev/video1
crw-rw----+ 1 root video 81, 3 máj   14 10:17 /dev/video3
crw-rw----+ 1 root video 81, 5 máj   14 10:17 /dev/video5
crw-rw----+ 1 root video 81, 4 máj   14 10:17 /dev/video4

Because I have an integrated laptop webcam and also my external Logitech webcam connected.

But then why is it not only 2 video device entries (nodes)? The thing is, Linux creates more device nodes for each device to store additional metadata in them. So basically I have 6 of these files but only have 2 “real” devices. How am I supposed to know which two are my “real” devices?

The simplest way might be to use a package that can list your video devices by name:

sudo apt-get install v4l-utils
v4l2-ctl --list-devices
Integrated Camera: Integrated C (usb-0000:00:14.0-8):
	/dev/video0
	/dev/video1
	/dev/video2
	/dev/video3

HD Pro Webcam C920 (usb-0000:09:00.0-1.3.1):
	/dev/video4
	/dev/video5

Now this should make things clear, regarding which device nodes belong to which webcam. And to find out which exact node is the “real one” that you can use to reference the device when using the uvcdynctrl command, you have two options:

  • in my experience the first entry that the command above shows for the device is the “real one” (others are metadata only) - but I don’t have evidence it’s always the case.
  • to 100% make sure you find the correct video device file, you can check more information about a device using this command:

udevadm info -n /dev/video0

P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/video4linux/video0
N: video0
L: 0
S: v4l/by-path/pci-0000:00:14.0-usb-0:8:1.0-video-index0
S: v4l/by-id/usb-Chicony_Electronics_Co._Ltd._Integrated_Camera_0001-video-index0
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/video4linux/video0
E: DEVNAME=/dev/video0
E: MAJOR=81
E: MINOR=0
E: SUBSYSTEM=video4linux
E: USEC_INITIALIZED=2754683
E: ID_V4L_VERSION=2
E: ID_V4L_PRODUCT=Integrated Camera: Integrated C
E: ID_V4L_CAPABILITIES=:capture:
E: ID_VENDOR=Chicony_Electronics_Co._Ltd.
E: ID_VENDOR_ENC=Chicony\x20Electronics\x20Co.\x2cLtd.
E: ID_VENDOR_ID=04f2
E: ID_MODEL=Integrated_Camera
E: ID_MODEL_ENC=Integrated\x20Camera
E: ID_MODEL_ID=b6cb
E: ID_REVISION=5818
E: ID_SERIAL=Chicony_Electronics_Co._Ltd._Integrated_Camera_0001
E: ID_SERIAL_SHORT=0001
E: ID_TYPE=video
E: ID_BUS=usb
E: ID_USB_INTERFACES=:0e0100:0e0200:0e0101:0e0201:fe0101:
E: ID_USB_INTERFACE_NUM=00
E: ID_USB_DRIVER=uvcvideo
E: ID_PATH=pci-0000:00:14.0-usb-0:8:1.0
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_8_1_0
E: ID_FOR_SEAT=video4linux-pci-0000_00_14_0-usb-0_8_1_0
E: COLORD_DEVICE=1
E: COLORD_KIND=camera
E: DEVLINKS=/dev/v4l/by-path/pci-0000:00:14.0-usb-0:8:1.0-video-index0 /dev/v4l/by-id/usb-Chicony_Electronics_Co._Ltd._Integrated_Camera_0001-video-index0
E: TAGS=:uaccess:snap_zoom-client_zoom-client:seat:

This will spit out a bunch of information about that device node. The keyword you’re looking for here is ID_V4L_CAPABILITIES=:capture:. If the ID_V4L_CAPABILITIES value is set to capture or anything similar, you can be sure this is a real device not just metadata. If you check the other metadata files, they don’t have anything set for the ID_V4L_CAPABILITIES value.

After finding your video device name, you can use the command shown above:

uvcdynctrl -d video4 "--set=Power Line Frequency" 1