Motivations

I've been thinking about webcams for a while after I read about numerous pieces about how terrible laptop built-in webcams are in the day and age of zooming-from-home. People seem to have problems with laptop built-in webcams on the following aspects:

There are a couple of remedies people came up with for the built-in webcam quality:

Many "professional" streamers choose the last solution, and I have tried to do it myself too. It took me two months to wait for my $50 capture card from China to arrive. Then when it finally came, I realized this is a very cumbersome setup. First, my camera (a Sony NEX-5R) cannot output a "clean" HDMI output (i.e. without the GUI elements). The only way to get rid of that stupid overlay is to buy another newer camera (say, a Sony A7 is $500+ used). Second, the camera does not charge or stay charged on USB, so I have to buy another dummy battery that feeds from a DC source. Third, this setup is not portable.

Moreover, none of the above solutions allow us to trust, control, and improve on them (At least, physically disconnecting them solves the privacy concern, which isn’t something you can do with a laptop built-in camera).

Raspberry Pi as a webcam?

So I set out to build a webcam of my own. Recently, I noticed that the Raspberry Pi Foundation released a high-quality camera, which is a fantastic candidate. It's a professional camera with a very big sensor and an assortment of interchangeable lenses. Being in the right hands, this can be a very powerful tool to achieve many things. Can it be a webcam to use with my ordinary computer though?

I know it is possible to stream the webcam over the network, and then use a computer to turn the network stream back to a virtual webcam. However, because this setup depends on the operating system, the setup is not portable. It also introduces lags which makes the voice trails behind the images.

So in short, I want the Pi Camera to appear as just an ordinary USB webcam to my laptop.

Challenges

With a bit of googling, I learned that it is possible to make the Pi appear as a USB webcam! There is a mode on the Pi 0 USB port called USB gadget mode, which makes that port a guest port for the system it's plugged in to. I got a good start with Dave Hunt's post. However, there are things to be desired with his software solution. First, it uses Raspbian as a base, which means you have a writable root, and an abrupt disconnection of power (we will do that with a webcam) will cause filesystem corruption. Second, the camera takes a long time to start. Those are the two main barriers to this approach: It works as a hack, but it works less well as a solution you'd depend on. And what you need your webcam to do? To work every time when you need it, right?

Making the webcam boot quickly is a challenge: You'd have to build a dedicated linux system that can boot as quickly as possible. This makes using just Raspberry Pi OS a unviable choice. It needs to, also, makes unclean shutdowns not corrupt the filesystem. That means the filesystem needs to be read-only.

So, I set out to build a more robust firmware for the project. The following is the documentation of what I did to get the firmware working, and I think what I went through can be helpful if you want to roll your firmware to do things you'd like a dedicated embedded firmware for your Pi 0, too.

This project is not hardware focused, it uses all the off-the-shelf components, rather it is a firmware project to enable the use of the Pi 0 as a webcam.

Solution

One of the tools that I grew fond of recently is Buildroot. Buildroot is a framework/tool to allow you to roll out your own Linux OS/distribution for embedded devices. It powers a couple of big projects. So I set out to build my firmware with Buildroot.

I plan to do the following:

For step 1, I followed the tutorial on ARM fever to have to build a baseline image. Except having to tweak some wireless issues so I could remotely debug the Pi 0 via SSH, the tutorial was spot-on. I knew if the Pi 0 only USB OTG port was in peripheral (gadget) mode, it would have been impossible to connect a USB ethernet dongle to it, so SSH-over-wireless was essential. The package for enabling the SSH access to the Pi is dropbear. Getting a buildroot Pi working with dropbear took me a night.

Buildroot menuconfig

The very helpful menuconfig system that comes with buildroot

Next, it looked to me that a simple sysv-init system was going to be a growing pain. I don't know how to exactly deal with an udev system that the UVC-webcam project assumes, so I switched the init system to systemd which gives me udev automatically. But this change to systemd changes a lot of how networking is done, so getting back a console was quite frustrating. There are a couple of ways you can get a root shell to the Pi: Via ttyACM0 (the 40 pin serial headers, which I don't have soldered), via the HDMI console (tty1), or the USB port in gadget mode (ttyGS1), or via SSH (the issue was that get wireless and wired networking was not functional). The issue was that I wasn't sure of what parameters could be used to set them up when none of the venues were working. Without a way to see what wasn't working by looking at the logs or a way to fix issues on the fly, the job became significantly harder. I learned that my chroot-to-pi script helped debug boot issues. After seeing the Pi failing to give me the console, I could still chroot to the SD card and call journalctl to see what went wrong in the last boot with the script. After a while I learned of the names of the device and what went wrong, I was able to get a login prompt via the HDMI console. Once I got in the barebone Pi working with systemd, it became quite a bit easier to set up the serial console on the rest of the interfaces.

Then, I did quite a bit of reading on how to set up an external buildroot tree. This step is to avoid having to mangle between the buildroot tree and my system. I added the UVC-webcam package to my tree, that was very simple.

Then the rest was just fixing things and adding boot params in the right places until the whole system worked. The last part was to make the filesystem read-only. That task was done automatically with the rootfs being squashfs. This broke a couple of services at startup that assumed a writable rootfs, but that was not hard to fix – mounting /var as a tmpfs solved the issue.

Finally, it was time to remove all the networking support that I added for debugging purposes and just set up the serial access on the USB gadget interface.

The camera boots very quickly in 13 seconds. We can even get root on the webcam by logging in the serial interface presented on the Pi at 115200 baud as root:root.

Root

Now you can have root on your webcam too!

Licenses and Credits