Working front and rear cameras on Debian 11 on a Surface Pro 6, SurfaceBook 2, and Surface Go
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.
Install the ipu3-fw.bin
firmware
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 libcamera
files/config
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 gstreamer
support.
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
Clone libcamera
from GitHub
git clone https://git.libcamera.org/libcamera/libcamera.git
Install components
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
Install gstreamer
bits
sudo apt install gstreamer1.0-tools libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev -y
Build libcamera
with gstreamer
support
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.)
Run it
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 _SB_.PCI0.I2C2.CAMR
.
On a Surface Go, the camera-name
for the front camera is _SB_.PCI0.LNK1
. The rear camera is _SB_.PCI0.LNK0
.
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 camera.sh
) is:
#!/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.
In ~/.bashrc
, I added:
alias startcam="/bin/bash /path/to/camera.sh"
Then, reload your ~/.bashrc
config:
source ~/.bashrc
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 libcamera
team
Thank you to everyone working on libcamera
for making this possible.
You may also like:
- This one simple hack solved my Debian 11 Bluetooth audio problems
- Handwriting, and annotating PDFs: a stylus on Debian 10 on Surface Pro 6 compared with an iPad
- Installing Debian 10 Linux on a Microsoft Surface Pro 6
- Ubuntu on a OnePlus 6T: a good start, but too many compromises
- Aztine 15.6 Portable Monitor with Debian 11 on a Surface Pro 6
- Auto-unlocking a LUKS volume on an SD card on boot with Debian 11 Bullseye
- Making a Mac Mini power up when power is restored: Debian 11 version
- Removing the default games in GNOME 3 on Debian 10
- Raspberry Pi 4 with the PoE+ HAT: LUKS and a working fan
- Installing vanilla Debian 11 on a Raspberry Pi 4
- Fixing a font which shows in macOS Font Book but not in macOS LibreOffice
- Unlocking a LUKS-encrypted partition via ssh on Debian 10 and Debian 11
- Internet access via iPhone's personal hotspot on Lubuntu 21.04
- Lubuntu 21.04: forcing natural scrolling on a mouse
- Gemini PDA running Debian: a properly portable computer