Use Canon EOS 90D as a webcam for Google Meet / Skype / Zoom / etc on Linux Ubuntu 22.04 with nVidia hardware acceleration

Quick and dirty post that pulls together a couple of sources. I might improve the post at some point. I might not…

Initial set-up:


Additional code to specify which video device to create.

sudo apt update && sudo apt install gphoto2 v4l2loopback-utils ffmpeg

echo 'dslr-webcam' | sudo tee -a /etc/modules

echo <<EOT | sudo tee -a /etc/modprobe.d/dslr-webcam.conf
alias dslr-webcam v4l2loopback 
options v4l2loopback exclusive_caps=1 max_buffers=2 video_nr=69

Hardware acceleration set-up:


I’ll assume you have nvidia drives installed

sudo apt install nvidia-cuda-toolkit

mkdir ~/nvidia/ && cd ~/nvidia/
git clone

cd nv-codec-headers && sudo make install

cd ~/nvidia/
git clone ffmpeg/

sudo apt install build-essential yasm cmake libtool libc6 libc6-dev unzip wget libnuma1 libnuma-dev

cd ~/nvidia/ffmpeg/
./configure --enable-nonfree --enable-cuda-nvcc --enable-libnpp --extra-cflags=-I/usr/local/cuda/include --extra-ldflags=-L/usr/local/cuda/lib64

make -j $(nproc)

Combined to pull video from the camera to a video device:

echo 'alias start-gphoto2-webcam="gphoto2 --capture-image &&  gphoto2 --stdout --capture-movie | ~/nvidia/ffmpeg/ffmpeg -hwaccel cuda -i - -vcodec rawvideo 
-pix_fmt yuv420p -threads 0 -f v4l2 /dev/video69"' >> ~/.bashrc


  • Logout/in
  • Plug the camera into the computer
  • Turn the camera on
  • Run: start-gphoto2-webcam
  • Use in an application that uses a webcam

New hardware, who dis?

New laptop provided by work. Time to install everything that makes me productive as a PHP developer.

Using Kubuntu 21.10 as my base OS.

General utilities:

sudo apt install \
    openssh-server \
    net-tools \
    htop \
    curl \
    whois \
    ack \
    mysql-client \
    httpie \
    php-cli \
    freerdp2-x11 \
    meld \
    kcachegrind \
    vokoscreen-ng \
    autokey-qt \
    parlatype \
    thunderbird-locale-en-gb \
    libreoffice-calc \
    libreoffice-writer \
    libreoffice-draw \


sudo snap install \
    spotify \
    skype \
    postman \
    authy \

Snaps that need to be installed in “classic” mode:

sudo snap install --classic \
    slack \

Microsoft Edge:

echo 'deb [arch=amd64] stable main' | sudo tee /etc/apt/sources.list.d/microsoft-edge.list

sudo apt-key adv --keyserver hkp:// --recv EB3E94ADBE1229CF

sudo apt update && sudo apt install microsoft-edge-beta

VirtualBox: (recommend sticking with ubuntu version unless latest required)

echo "deb [arch=amd64] $(lsb_release -cs) contrib" | sudo tee /etc/apt/sources.list.d/oracle-virtualbox.list

wget -q -O- | sudo apt-key add -

wget -q -O- | sudo apt-key add -

sudo apt update && sudo apt install virtualbox-6.1


echo "deb [arch=amd64] $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/vagrant.list

curl -fsSL | sudo apt-key add -

sudo apt-get update && sudo apt-get install vagrant


echo "deb [arch=amd64] $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list

curl -fsSL | sudo apt-key add -

sudo apt update && sudo apt-get install docker-ce docker-ce-cli

sudo usermod -a -G docker $USER

Docker Compose (v1):

curl -L "$(uname -s)-$(uname -m)" -o /tmp/docker-compose

chmod +x /tmp/docker-compose

sudo mv /tmp/docker-compose /usr/local/bin/docker-compose


sudo apt-key adv --keyserver --recv-keys ACCAF35C

echo "deb$(lsb_release -is | tr '[:upper:]' '[:lower:]') $(lsb_release -cs) non-free contrib" | sudo tee /etc/apt/sources.list.d/insync.list

sudo apt update && sudo apt install insync


git clone ~/.bash-git-prompt --depth=1

tee -a ~/.bashrc <<EOF

if [ -f "$HOME/.bash-git-prompt/" ]; then
    source $HOME/.bash-git-prompt/

vagrant plugin “hostmanager” sudo without password

sudo tee /etc/sudoers.d/vagrant_hostmanager <<EOF
Cmnd_Alias VAGRANT_HOSTMANAGER_UPDATE = /bin/cp $HOME/.vagrant.d/tmp/hosts.local /etc/hosts


sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt install ansible

Additional monitor resolution

Help from:

sudo tee /etc/profile.d/ <<EOF
xrandr --newmode "2560x1440_60.00"  312.25  2560 2752 3024 3488  1440 1443 1448 1493 -hsync +vsync
xrandr --addmode DP-3-2 "2560x1440_60.00"

old and busted: mysqldump, new hotness: mydumper

I’m late to the mydumper party –

Multi-threaded, lightning quick, exports to files per table structure and data.

In the Ubuntu world (and likely Debian too) it’s available as a precompiled package: sudo apt update && sudo apt install mydumper

Backup everything in a database:

mydumper \
  --triggers \
  --routines \
  --events \
  --database name_of_source_database

It’ll create a date stamped directory with two files for each table. One for the schema, the other with the data.

If you want to import everything in one go, here’s a little bit of bash to help:

# 1st - import all of the schema files to create the
#   tables, triggers, routines, and events
for i in `ls *-schema.sql`; do
    echo -e "\nImporting schema file: ${i}"
    pv ${i} | mysql name_of_target_database

# 2nd - import all of the table data
for i in `ls *.sql | grep -v '\-schema.sql'`; do
    echo -e "\nImporting data file: ${i}"
    pv ${i} | mysql name_of_target_database

The above uses pv (pipe viewer – to send the content of the files into mysql. This means that we get to see the progress of importing files into MySQL.

If you haven’t got pv I suggest you get it: sudo apt update && sudo apt install pv.

How to call a static method in PHP when you have the class name in a variable

Wrap the variable (that holds the class name) in brackets:


class A
    public static function foo($arg)
        return 'Argument was "' . $arg . '"' . PHP_EOL;

$result = A::foo('triggered via named class');
echo $result;

$className = A::class;
$result = ($className)::foo('trigged via variable');
echo $result;

The output of the above code:

php a.php
Argument was "triggered via named class"
Argument was "trigged via variable"

I got locked out of a google compute instance due to ssh packets being dropped

Silly thing to happen really.

Some system on the instance detected too many connections in a short amount of time – likely due to some automated tasks driven by ansible.

That resulted in iptables dropping all connections to port 22 🙁

Thankfully, with google compute, one can access the serial console via the web UI.

Unfortunately, all of my users have no passwords – this is to ensure that ssh logins are via keypairs only.

The work around was eventually found on


  • Edit the instance
  • Tick “Enable connecting to serial ports”
  • Scroll down to “Custom metadata”
  • Add a new item with the key “startup-script”:
useradd --groups google-sudoers tempuser
echo "tempuser:password" | chpasswd
  • Save the instance and hit “Reset”
  • When the instance is back up, connect to it via the serial console and login as the “tempuser”
  • Fix things!
  • Remove the tempuser
  • Remove the startup-script from custom metadata

KDE Plasma likes, dislikes, and would be nice to haves

With each new release of Ubuntu, I’ve stuck with the default desktop environment. These have worked well for me over the years, but thought I should see what else there is.

The only way for me to do it justice is to run KDE Plasma as my only desktop environment for a minimum of 2 weeks. So both my work station and my personal laptop are use KDE Plasma installed alongside Gnome 3 Shell on Ubuntu 19.10.

If I’m unhappy after the 2 weeks, I can always go back to Gnome. Or maybe try something else, like lxde or xfce.

I started on Sunday evening, and it’s now Wednesday afternoon. The following are my findings.

This is likely to be updated as I find new things or ways to fix niggles.


  • When an application shows in the “Task Manager” bar, one can click it to minimise the active window.
  • All icons showing in the “Task Manager” bar (Autokey is a GTK application, but can’t show its icon in Gnome 3, but manages to in KDE Plasma?).
  • Simple music controls on lock screen.


  • Even at max mouse sensitivity, it feels slower than on Gnome 3 – not good for a 3 monitor set-up – this may be subjective and not be an issue in time.
  • No option to locate the mouse cursor by pressing [ctrl].
  • Some windows don’t respond to a mouse wheel scoll until the window is clicked – this may be an issue only with GTK applications running on KDE Plasma.
  • Being asked for my SSH key in the terminal for every action – is there a key manager like in Gnome that I need to enable? Manually resolved by running `ssh-add` against each key required. Gnome does handle this a lot better 😐
  • Scrolling in an application window does not respond while a OSN is displayed – example: Spotify changing tracks

Things I’d like to see ported from Gnome 3 Shell

  • The option to only switch the central monitor when changing between virtual desktops.
  • Change between virtual desktops using [ctrl]+[alt]+arrow keys.

Things I’d like to see in all desktop environments

  • Option to have the cursor colour to invert as it passes over other colours – Windows does this.
  • Automatic window scaling based upon the native resolution of the monitor in use. If a window is moved from one monitor to another, and the resolution changes, the scale should adapt to keep it readable – Windows does this.

Embiggen .desktop loaded applications on Ubuntu

I keep forgetting the steps required for this, so thought I should write them up in one easy to remember blog post for myself.

My desktop set-up consists of 2 x 1080 and 1 x 4k display. Making sure that applications are readable is a bit of a farce.

But as long as I ensure that certain applications only ever appear on the correct monitor, means that I can alter the launcher to set the correct DPI scaling.

Case in point is the “thunderbird.desktop” launcher. I only ever use it on the 4k display (central monitor), so I can alter the launcher to pre-set the scaling to two times normal. Making it readable without squinting (I’m nearly 40 you know).

Using “locate thunderbird.desktop” we find that it’s stored at “/usr/share/applications/thunderbird.desktop”. So raised privileges will be needed to edit it.

“sudo nano -w /usr/share/applications/thunderbird.desktop”

Using “ctrl+\” to replace text, search for “Exec=thunderbird” and replace it with “Exec=env GDK_SCALE=2 thunderbird”. Use “ctrl+x” to save and exit the editor.

Now when the Thunderbird launcher icon is clicked, the application will be rendered at twice the normal size. Making the working day a lot less squinty.

Most amusing spam received to date

Good morning...

Do not consider on my English, I am from Iran.I installed the virus on your system.After that I pilfered all confidential info from your OS. Furthermore I received some more compromising evidence.The most interesting evidence which I thieftend- its a record with your self-abusing.I adjusted malicious software on a porn web site and after you installed it. As soon as you picked the video and pressed play, my software immediately set up on your OS.

After loading, your web camera shoot the record with you self-abusing,  furthermore it saved precisely the video you watched. In next week my malicious software collected all your social and work contacts.

If you wish to delete  the videotape- transfer me 380 united state dollar in BTC(cryptocurrency).
I provide you my Bitcoin wallet address - [redacted]  

You have 22 hours from this moment. When I receive transfer I will destroy the evidence forever. Differently I will send the tape to all your contacts.

Sent 5 days ago to my work address, no less.

Guess I got away with it!

Upgrading Jenkins war file the quick and dirty way


set -e

if [ $# -eq 0 ]; then
    echo "New Jenkins version number missing"
    exit 1


set -x

cd /usr/share/jenkins/
wget${VERSION}/jenkins.war -O jenkins.war-${VERSION}
rm jenkins.war && ln -s jenkins.war-${VERSION} jenkins.war
service jenkins restart

The above bash script will download a given version of the jenkins.war file and symlink it into place before restarting the jenkins service.

Assumptions made:

  • The jenkins.war file is installed to /usr/share/jenkins
  • The server is using upstart for running services
  • User input is sane – there is no validation or sanitisation