Skip to content

Instantly share code, notes, and snippets.

@justinschuldt
Last active June 14, 2024 06:04
Show Gist options
  • Save justinschuldt/36469e2a89d95ef158a8c4df091e9cb4 to your computer and use it in GitHub Desktop.
Save justinschuldt/36469e2a89d95ef158a8c4df091e9cb4 to your computer and use it in GitHub Desktop.
Directions for setting up a RaspberryPi to act as a generic USB webcam

hardware/software

Webcam parts:

  • Raspberry Pi Zero W Rev 1.1
  • Raspberry Pi Camera v2 (8-megapixel)
  • Raspberry Pi High Quality Camera (12.3-megapixel)
  • Raspbian Buster Lite 2020-02-13

Webcam works with:

  • Windows 10
  • Windows 10 "Camera" app
  • Google Hangouts via Chrome
  • Zoom

setup

  • start with a fresh install of Raspbian Buster Lite 2020-02-13.
  • enable ssh access & connect to network.
  • connect the camera to the Raspberry Pi.

run updates, install git

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git -y

enable the camera

sudo raspi-config

Interfacing Options > P1 Camera > Enable

set dwc2 as dtoverlay

Add

dtoverlay=dwc2

to the bottom of /boot/config.txt

(sudo vi /boot/config.txt then add dtoverlay=dwc2 to the end.)

load dwc2 and libcomposite at boot

Add

modules-load=dwc2,libcomposite

after the rootwait in /boot/cmdline.txt

(sudo vi /boot/cmdline.txt then add modules-load=dwc2,libcomposite at the end.)

create the ConfigFS uvc.sh script

vi uvc.sh

then add the following from g.letourneur on raspberrypi.org

#!/bin/bash
mkdir /sys/kernel/config/usb_gadget/pi4

echo 0x1d6b > /sys/kernel/config/usb_gadget/pi4/idVendor
echo 0x0104 > /sys/kernel/config/usb_gadget/pi4/idProduct
echo 0x0100 > /sys/kernel/config/usb_gadget/pi4/bcdDevice
echo 0x0200 > /sys/kernel/config/usb_gadget/pi4/bcdUSB

echo 0xEF > /sys/kernel/config/usb_gadget/pi4/bDeviceClass
echo 0x02 > /sys/kernel/config/usb_gadget/pi4/bDeviceSubClass
echo 0x01 > /sys/kernel/config/usb_gadget/pi4/bDeviceProtocol

mkdir /sys/kernel/config/usb_gadget/pi4/strings/0x409
echo 100000000d2386db > /sys/kernel/config/usb_gadget/pi4/strings/0x409/serialnumber
echo "Samsung" > /sys/kernel/config/usb_gadget/pi4/strings/0x409/manufacturer
echo "PI4 USB Device" > /sys/kernel/config/usb_gadget/pi4/strings/0x409/product
mkdir /sys/kernel/config/usb_gadget/pi4/configs/c.1
mkdir /sys/kernel/config/usb_gadget/pi4/configs/c.1/strings/0x409
echo 500 > /sys/kernel/config/usb_gadget/pi4/configs/c.1/MaxPower
echo "UVC" > /sys/kernel/config/usb_gadget/pi4/configs/c.1/strings/0x409/configuration

mkdir /sys/kernel/config/usb_gadget/pi4/functions/uvc.usb0
mkdir -p /sys/kernel/config/usb_gadget/pi4/functions/uvc.usb0/control/header/h
ln -s /sys/kernel/config/usb_gadget/pi4/functions/uvc.usb0/control/header/h /sys/kernel/config/usb_gadget/pi4/functions/uvc.usb0/control/class/fs
mkdir -p /sys/kernel/config/usb_gadget/pi4/functions/uvc.usb0/streaming/mjpeg/m/720p
cat <<EOF > /sys/kernel/config/usb_gadget/pi4/functions/uvc.usb0/streaming/mjpeg/m/720p/dwFrameInterval
5000000
EOF
cat <<EOF > /sys/kernel/config/usb_gadget/pi4/functions/uvc.usb0/streaming/mjpeg/m/720p/wWidth
1280
EOF
cat <<EOF > /sys/kernel/config/usb_gadget/pi4/functions/uvc.usb0/streaming/mjpeg/m/720p/wHeight
720
EOF
cat <<EOF > /sys/kernel/config/usb_gadget/pi4/functions/uvc.usb0/streaming/mjpeg/m/720p/dwMinBitRate
29491200
EOF
cat <<EOF > /sys/kernel/config/usb_gadget/pi4/functions/uvc.usb0/streaming/mjpeg/m/720p/dwMaxBitRate
29491200
EOF
cat <<EOF > /sys/kernel/config/usb_gadget/pi4/functions/uvc.usb0/streaming/mjpeg/m/720p/dwMaxVideoFrameBufferSize
1843200
EOF
mkdir /sys/kernel/config/usb_gadget/pi4/functions/uvc.usb0/streaming/header/h
cd /sys/kernel/config/usb_gadget/pi4/functions/uvc.usb0/streaming/header/h
ln -s ../../mjpeg/m
cd ../../class/fs
ln -s ../../header/h
cd ../../class/hs
ln -s ../../header/h
cd ../../../../..

ln -s /sys/kernel/config/usb_gadget/pi4/functions/uvc.usb0 /sys/kernel/config/usb_gadget/pi4/configs/c.1/uvc.usb0
udevadm settle -t 5 || :
ls /sys/class/udc > /sys/kernel/config/usb_gadget/pi4/UDC

make the new script executable

chmod +x uvc.sh

setup uvc-gadget

clone whle's uvc-gadget repo

git clone https://github.com/wlhe/uvc-gadget.git

build it

cd uvc-gadget && make

setup complete, reboot

sudo reboot 0

debugging

see video steams (cameras)

ls -ls /dev

should have video0 if your Raspberry Pi Camera is hooked up and enabled.

see if you have a device controler

ls -la /sys/class/udc

should have:

lrwxrwxrwx  1 root root 0 May 11 22:21 20980000.usb -> ../../devices/platform/soc/20980000.usb/udc/20980000.usb

pre-check usb_gadget

ls -la /sys/kernel/config/usb_gadget

should exist.

usage

Start with your Pi just hooked up to power, not connected to another computer.

check camera connections

note which is the physical camera connected

ls /dev/video*

will probably be video0

setup ConfigFS

sudo ./uvc.sh

if it returns with no errors, it worked.

check for new video output

note which one is new from running the uvc.sh script

ls /dev/video*

will probably be video1.

start the uvc-gadget webcam

if your camera is video0 and your UVC gadget is video1:

~/uvc-gadget/uvc-gadget -v /dev/video0 -u /dev/video1 -r 1 -f 1

note the options on the repo, this will output 1280x720 MJPEG

You should have output like this:

pi@campi:~ $ ~/uvc-gadget/uvc-gadget -v /dev/video0 -u /dev/video1 -r 1 -f 1
V4L2 device is mmal service 16.1 on bus platform:bcm2835-v4l2
V4L2: Getting current format: JPEG 1024x768
V4L2: Setting format to: MJPG 1280x720
V4L2: Getting current format: MJPG 1280x720
v4l2 open succeeded, file descriptor = 3
uvc device is 20980000.usb on bus gadget
uvc open succeeded, file descriptor = 4
V4L2: Buffer 0 mapped at address 0xb6cf4000.
V4L2: Buffer 1 mapped at address 0xb6c13000.
V4L2: 2 buffers allocated.

plug the RaspberryPi into a Windows10 computer, as a webcam

connect Raspberry Pi's Micro USB to a USB-A port of a Windows 10 host

you should see a bunch of logs on the rPi when you connect the cable, like:

control request (req 86 cs 04)
control request (req 81 cs 02)
control request (req 86 cs 09)
control request (req 81 cs 02)
control request (req 86 cs 02)

open the "Camera" app on Windows

on the RaspberryPi you should see logs like:

streaming request (req 81 cs 01)
streaming request (req 01 cs 01)
setting probe control, length = 26
streaming request (req 81 cs 01)
streaming request (req 83 cs 01)
streaming request (req 82 cs 01)
streaming request (req 01 cs 01)
setting probe control, length = 26
streaming request (req 81 cs 01)
streaming request (req 01 cs 02)
setting commit control, length = 26
UVC: 2 buffers allocated.
V4L2: Starting video stream.
UVC: Starting video stream.
control request (req 81 cs 02)
control request (req 81 cs 02)
control request (req 81 cs 02)
control request (req 01 cs 02)
setting unknown control, length = 2
V4L2: Brightness control changed to value = 0x7f
Control Request data phase (cs 02 entity 02)
control request (req 81 cs 02)
control request (req 81 cs 02)

stop streaming by pressing ctrl+c on the Pi

Rerunning the script should work fine. You can unplug the Pi and move it to a different computer, etc.

troubleshooting

all white or all black video output

try setting the brightness to something like 65, as it may default to 0 leaving you with an all-black image.

souces

Used these resouces to get this working

@jiribrejcha
Copy link

Great work, Justin 👍🏻 Have you had a chance to test this on macOS, please?

@alexmetcalfe
Copy link

Hey @jiribrejcha I managed to get this working on macOS, the only thing I had to do was change the default brightness to a lower level.

details on how to do this here -> https://www.raspberrypi.org/forums/viewtopic.php?t=148361&start=25#p1659365

also verified its working with Zoom

@mikeschnier
Copy link

Hey Alex, which version of macOS are you running? I've seen two reports of this not working correctly on macOS, at least one of the users was running Catalina.

@eightlines
Copy link

I can confirm, Catalina 10.15.3. White screen. I lowered the threshold to 55, recompiled and it works fine.

@savicbo
Copy link

savicbo commented Jun 9, 2020

Many thanks for putting to work in to document this process so cleanly Justin.

Hate to add to the "does it work on.." but does anyone have a Chromebook they could try this on? Might be just the perfect solution for a decent webcam for my Chromebox.. Thanks in advance all!

@edwardcoyne
Copy link

edwardcoyne commented Jun 11, 2020

I am using it on a chromebook. It doesn't work with the builtin "camera" app but it works great with Google meet through chrome, which is what I wanted it for anyway.

I added the script to startup and it is perfect, plug the device into the laptop, wait ~60s then fire up the video chat and it has worked every time.

@savicbo
Copy link

savicbo commented Jun 12, 2020

I am using it on a chromebook. It doesn't work with the builtin "camera" app but it works great with Google meet through chrome, which is what I wanted it for anyway.

I added the script to startup and it is perfect, plug the device into the laptop, wait ~60s then fire up the video chat and it has worked every time.

That's great to hear, very kind thanks for confirming this. I too would use it only for Google Meet, so that's perfect. Again, many thanks!

@leonardsaers
Copy link

I got this working on a raspberry pi 4 as well. Thanks for compiling the instructions.

@omnisonic
Copy link

Thanks for the directions!
I got it working on a Raspberry Zero V1.3 with Raspi cam 1.3 on a Mac 10.14 Mojave.
Tested with Zoom and Screenflow.
It took me a minute to figure out that I had to run 'sudo ./uvc.sh' again after changing default brightness in the uvc-gadget.c file as per -> https://www.raspberrypi.org/forums/viewtopic.php?t=148361&start=25#p1659365

I added a script file to rc.local to get it running upon startup as per -> https://www.raspberrypi.org/documentation/linux/usage/rc-local.md

I had to make sure file paths in the scripts were all absolute since rc.local runs as root. But now it starts up after plugin. Currently just unplugging to stop it since I can't ssh into it (not a pi w)

Nice to have this little lightweight usb camera now.

@mikeschnier
Copy link

mikeschnier commented Jun 24, 2020

My camera kit arrived and I managed to get the setup above working in Chrome in macOS 10.14.6 (including Skype via web.skype.com), but not in Photo Booth or Skype's native app. I'm not sure why it only works in Chrome, but I can live with it for now.

The latency and framerate were really bad first, maybe 1-2 FPS and a 1.5 second refresh rate. I took a few zeros out of the bitrate and framebuffer limits and am getting a decent framerate now with a split-second delay. With the included option for Super Speed, I suspect the settings provided were intended for a device that supported USB 3.0 and may need to be adjusted.

I can see there's a setting for brightness. Does anyone know how to adjust the hue, saturation and contrast?

@marcteys
Copy link

Really nice, thanks ! What is the average latency of this setup ?

@mikeschnier
Copy link

Reporting back with more information! Dave Hunt kindly pointed me to some of the v4l2-ctl commands he was using, and you can view all the available controls through "v4l2-ctl --list-ctrls". Handy if you need to fine-tune the white balance, brightness, hue and exposure or apply in-camera effects.

If you have a second terminal open, you can configure the settings while the camera's running.

@mikeschnier
Copy link

To improve this setup, I would really like to run the ./uvc.sh script, start the uvc-gadget webcam and apply a handful of v4l2-ctl commands at startup. I was trying to do this through Cron, but I haven't really used it before and haven't been having luck getting it to work.

I can see that Dave Hunt's setup uses systemd services, so I may try to figure out how that works...

@zainmehdi
Copy link

Hi, Thanks alot for the useful tutorial, I was just wondering if anyone has been able to get it working with a dummy video instead of a camera. I am trying to inject a video file into v4l2loopback device but I only get colored stripes at the host pc.

@pietrouk
Copy link

trying to run this on a Pi 4 1GB to use on macOS. Followed all the steps and changed #define PU_BRIGHTNESS_DEFAULT_VAL 127 to #define PU_BRIGHTNESS_DEFAULT_VAL 55 before compiling.

When I get to
sudo ./uvc.sh
it hangs, the pi becomes unresponsive and requires a reboot. Any suggestions?

@geerlingguy
Copy link

geerlingguy commented Sep 24, 2020

@pietrouk — I ran into the same issue. It works on the Pi Zero, but not on the Pi 4 (I tried a 1 GB and newer 8 GB model, neither worked). And we're not alone. User Nazarov in the Pi Forums is experiencing the same thing.

I'm also trying to add some structure to the project (so I can reformat and re-configure everything really quick) so I put everything I'm doing into a full repo: geerlingguy/pi-webcam. It basically does everything in this gist, but uses @climberhunt's fork of uvc-gadget, and configures the Pi to run the script at boot so you can just plug into a Mac or PC and a few seconds later use it as a webcam (headless).

@justinschuldt
Copy link
Author

@pietrouk, @geerlingguy - on a Pi 4 you must use the USB-C (power) port, as that is the only one that can act as usb-OTG.

I have done this with a Pi 4 hooked up to one of the official 7" displays. The display gets powered via it's micro-usb port, then connects to the Pi via GPIO, which provides consistent power to the Pi.

I used the display to keep a terminal open to start/watch/stop the UVC script, then cable the Pi 4's usb-c to the destination computer. I used this setup as my primary webcam for about a month, it was surprisingly usable/stable.

@geerlingguy
Copy link

geerlingguy commented Sep 24, 2020

@justinschuldt - That's exactly what I was doing (using a USB-C to USB-C cable—actually tested four different ones), and I had the Pi plugged into an external HDMI display.

The problem seems to occur with the latest version of the kernel, and it basically locks everything up immediately after running the last command in the uvc.sh script—if I have an open SSH session, it hangs, the UI hangs (even with keyboard and mouse plugged in), etc. It's very odd, and I couldn't find any helpful log info either. For now, I'm switching over to a Pi Zero (which is working just fine), but I'd like to go with the Pi 4 eventually as it's sooo much faster when booting and configuring :)

Note: It also does the same thing using @climberhunt's fork and the piwebcam script he includes.

Edit: tracking this also here.

@pietrouk
Copy link

thanks @justinschuldt, much appreciated and good to hear it can work on the Pi4.

I can confirm I'm getting the same as @geerlingguy as soon as I run uvc.sh everything freezes up and a reboot is required, irrespective of which USB port I'm using.

Possibly a kernel downgrade would work? What version are you using? Thanks again

@mkyl
Copy link

mkyl commented Oct 12, 2020

Works brilliantly on macOS Catalina 10.15.7! All I had to do was change the constant in uvc-gadget.c, as described above. Thank you a ton.

@Ghazanfar373
Copy link

I tried on raspberrypi zero with 8 gb sd card & IR camera emmiting frames of 1280x720 at 60 fps. its running fine but getting too much latency in video on my laptop. can we reduce frame rate on raspberrypi or any other way to reduce latency rate?

@mikeschnier
Copy link

mikeschnier commented Dec 15, 2020 via email

@mikeschnier
Copy link

If you want to try it yourself, you can use v4l2 commands to adjust frame rate.

To get 15 fps, I used:
v4l2-ctl -p 15

You can also adjust the video bitrate. The following is automatic:
v4l2-ctl -c video_bitrate_mode=0

You can also specify a bitrate using:
v4l2-ctl -c video_bitrate=

@PassiveProfit
Copy link

I got up to this point and I cant see the camera on Windows 10. Tested on laptop and Desktop. I am using pi 0 and connected through USB

image

@charles-cloud
Copy link

I tried using Raspberry pi4 + camera board and connected to PC using micro USB cable. but failed to detect it as UVC webcam on Windows 10.

Number of buffers requested = 3
V4L2 device is mmal service 16.1 on bus platform:bcm2835-v4l2
V4L2: Getting current format: JPEG 1024x768
V4L2: Setting format to: MJPG 1280x720
V4L2: Getting current format: MJPG 1280x720
v4l2 open succeeded, file descriptor = 3
uvc device is fe980000.usb on bus gadget
uvc open succeeded, file descriptor = 4
V4L2: Buffer 0 mapped at address 0xb6cbb000.
V4L2: Buffer 1 mapped at address 0xb6bda000.
V4L2: Buffer 2 mapped at address 0xb6af9000.
V4L2: 3 buffers allocated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment