Update: I've tested this on Debian 10 and Debian 11, and on a Surface Pro 6, a SurfaceBook 2, and a Surface Go.
Linux support for the Surface Pro 6 is quite superb, thanks to the people working on the linux-surface project.
One of the last hold-outs was support for the cameras.
The Surface Pro 6 seems to have been luckier than the other devices in the Surface line, in that now there is support for both cameras, albeit the quality is not great.
There is no single set of instructions to help make the cameras work, and make them usable in applications (e.g. firefox, for use in jitsi), so I wrote up what I learned for the github issues list, and I'm repeating it here.
You can get the firmware you need for the cameras from
firmware-linux, but you might need to change the name of a file. Here's a workaround:
cd /tmp wget -4 http://archive.ubuntu.com/ubuntu/pool/main/l/linux-firmware/linux-firmware_1.187.tar.gz tar -xvf linux-firmware_1.187.tar.gz sudo cp /tmp/linux-firmware/intel/irci_irci_ecr-master_20161208_0213_20170112_1500.bin /lib/firmware/intel/ipu3-fw.bin rm -r /tmp/linux-firmware rm -r /tmp/linux-firmware_1.187.tar.gz
Remove any existing
Camera support relies on
libcamera, and I had previously built this, and got cameras working on
qcam, but not available in applications. For this, one needs
It might be possible to re-do the initial configuration step to make this work, but I failed, so I just removed the
libcamera repository as my starting step:
cd ~ sudo rm -r libcamera
libcamera from GitHub
git clone https://git.libcamera.org/libcamera/libcamera.git
sudo apt install build-essential meson ninja-build pkg-config libgnutls28-dev openssl python3-pip python3-yaml python3-ply python3-jinja2 qtbase5-dev libqt5core5a libqt5gui5 libqt5widgets5 qttools5-dev-tools libtiff-dev libevent-dev clang libc++-dev libc++abi-dev -y
sudo apt install gstreamer1.0-tools libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev -y
cd libcamera GST_PLUGIN_PATH=$(pwd)/build/src/gstreamer CC=clang CXX=clang++ meson build -Dpipelines=uvcvideo,ipu3 -Dprefix=/usr ninja -C build sudo ninja -C build install
At the end of this, you should be able to see both cameras if you run
qcam. Yes, they have odd names.
Get a camera working over a video loopback, to expose it to other applications
sudo apt install v4l2loopback-dkms -y sudo modprobe v4l2loopback video_nr=42 card_label="virtualcam" exclusive_caps=1
(The "card_label" switch is the name the device will show up as in firefox and other applications. "virtualcam" was fine by me, but change it if you want something else. It's not a physical device though, so calling it "frontcam" or "backcam" would be confusing. You select the actual camera you want to use later.)
Yes, at the moment, each time you want to use the camera, you need to run this command.
gst-launch-1.0 libcamerasrc camera-name='\\_SB_.PCI0.I2C2.CAMF' ! video/x-raw,width=1280,height=720,framerate=30/1,format=NV12 ! videoconvert ! video/x-raw,format=YUY2 ! videoconvert ! v4l2sink device=/dev/video42
This will use the front camera on a Surface Pro 6 and a SurfaceBook 2. If you want the rear camera, you'd need to change the
camera-name switch to
On a Surface Go, the
camera-name for the front camera is
_SB_.PCI0.LNK1. The rear camera is
Using an alias to make it a bit easier
Rather than using the full command each time, using a bash alias can make it a bit easier.
I created a shell script, and aliased that.
The shell script (called
#!/bin/bash gst-launch-1.0 libcamerasrc camera-name='\\_SB_.PCI0.I2C2.CAMF' ! video/x-raw,width=1280,height=720,framerate=30/1,format=NV12 ! videoconvert ! video/x-raw,format=YUY2 ! videoconvert ! v4l2sink device=/dev/video42
I later tweaked this, so that I could use the same script and the same alias on multiple machines, with different camera names:
#!/bin/bash HOSTNAME=$(cat /etc/hostname) echo "This machine is $HOSTNAME" if [ $HOSTNAME == "surfacego" ]; then CAMERANAME='\\_SB_.PCI0.LNK1' else CAMERANAME='\\_SB_.PCI0.I2C2.CAMF' fi echo "Camera is $CAMERANAME" gst-launch-1.0 libcamerasrc camera-name=$CAMERANAME ! video/x-raw,width=1280,height=720,framerate=30/1,format=NV12 ! videoconvert ! video/x-raw,format=YUY2 ! videoconvert ! v4l2sink device=/dev/video42
Update: there's a bug in the blog engine, which means I've had to escape the backslashes in this post, to make them appear correctly in the rendered output. The camera name needs two backslashes before
_SB, in case the blog system has removed them again.
~/.bashrc, I added:
alias startcam="/bin/bash /path/to/camera.sh"
Then, reload your
So now, by typing
startcam, the camera starts.
Loading the kernel modules automatically
Note that loading a kernel module via
modprobe lasts only for the current session - after a reboot, you'll need to do it again. You could make it part of the bash script, but that would be a pain, as it requires superuser permission.
If you are going to use this regularly, it would make more sense to load the kernel modules automatically:
echo "v4l2loopback" | sudo tee -a /etc/modules-load.d/v4l2loopback.conf echo "options v4l2loopback video_nr=42 card_label="virtualcam" exclusive_caps=1" | sudo tee -a /etc/modprobe.d/v4l2loopback.conf update-initramfs -c -k $(uname -r)
Thank you to the
Thank you to everyone working on
libcamera for making this possible.