Photo from PxHere
guglhupf
is an extensible, distributed camera feed processing platform powered by Raspberry Pis and a comprehensive stack of open source tools, libraries, and frameworks. It has been developed targetting the use case of dashcams but can also be customized to serve other camera-based scenarios such as home security.
The platform consists of one controller acting as a central hub and multiple agents, each serving a camera video feed.
The controller hosts the main components of the platform:
- the
guglhupf
Python backend based onFastApi
- the
zuckerguss
frontend based onReact
- the
nginx
reverse proxy to serve as entry point - the
nfs
-managed storage for video recordings and gps location sharing - the
gps-sync
command and cronjob to continously update location data fromgpsd
- the
guglhupf-sync
command and cronjob to upload recordings to Google Drive usingdrive
-
Install
nginx
usingdietpi-software
. -
Create a
guglhupf.conf
nginx config file.sudo nano /etc/nginx/conf.d/guglhupf.conf`
The content of
guglhupf.conf
can be found in theresources
folder. -
Disable the default
nginx
config.sudo unlink /etc/nginx/sites-enabled/default
-
Restart the nginx service.
sudo systemctl restart nginx.service
The Camera Agents use the Video4Linux V4L2 API to process the video feed from the Raspberry Pi Camera Module.
These steps have been verified using a Raspberry Pi 3 Model B+ but should be the same on newer models like the Raspberry Pi 4 Model B. This tutorial is based on DietPi, but the steps should be similar on Raspberry Pi OS and other Raspberry Pi OS-based systems. Your Raspberry Pi should have the Camera Module connected.
-
Follow the DietPi instructions to download the latest DietPi release and flash it to an SD card with balenaEtcher.
Stop after step "2. Flash the DietPi image" since we will prepare a headless install and need to change some files before the first boot.
-
Reinsert/mount the SD card (typically called
boot
) once more after balenaEtcher is finished. -
Open
boot/dietpi.txt
in your favorite editor/IDE and update the settings for a headless boot.An example
dietpi.txt
can be found in theresources
folder.
Some of your settings might differ (e.g., regional settings)Overview of changed values:
-AUTO_SETUP_ACCEPT_LICENSE=0 +AUTO_SETUP_ACCEPT_LICENSE=1 -AUTO_SETUP_LOCALE=C.UTF-8 +AUTO_SETUP_LOCALE=en_US.UTF-8 -AUTO_SETUP_KEYBOARD_LAYOUT=gb +AUTO_SETUP_KEYBOARD_LAYOUT=us -AUTO_SETUP_TIMEZONE=Europe/London +AUTO_SETUP_TIMEZONE=America/Los_Angeles -AUTO_SETUP_NET_WIFI_ENABLED=0 +AUTO_SETUP_NET_WIFI_ENABLED=1 -AUTO_SETUP_NET_WIFI_COUNTRY_CODE=GB +AUTO_SETUP_NET_WIFI_COUNTRY_CODE=US -AUTO_SETUP_NET_HOSTNAME=DietPi +AUTO_SETUP_NET_HOSTNAME=<custom hostname> -AUTO_SETUP_HEADLESS=0 +AUTO_SETUP_HEADLESS=1 -AUTO_SETUP_AUTOSTART_TARGET_INDEX=0 +AUTO_SETUP_AUTOSTART_TARGET_INDEX=7 -AUTO_SETUP_AUTOMATED=0 +AUTO_SETUP_AUTOMATED=1 -AUTO_SETUP_GLOBAL_PASSWORD=dietpi +AUTO_SETUP_GLOBAL_PASSWORD=<custom password> -#AUTO_SETUP_INSTALL_SOFTWARE_ID=23 +AUTO_SETUP_INSTALL_SOFTWARE_ID=0 #OpenSSH Client +AUTO_SETUP_INSTALL_SOFTWARE_ID=7 #FFmpeg +AUTO_SETUP_INSTALL_SOFTWARE_ID=16 #Build-Essentials +AUTO_SETUP_INSTALL_SOFTWARE_ID=17 #Git +AUTO_SETUP_INSTALL_SOFTWARE_ID=103 #DietPi-RAMlog +AUTO_SETUP_INSTALL_SOFTWARE_ID=104 #Dropbear +AUTO_SETUP_INSTALL_SOFTWARE_ID=110 #NFS Client -SURVEY_OPTED_IN=-1 +SURVEY_OPTED_IN=0 -CONFIG_BOOT_WAIT_FOR_NETWORK=1 +CONFIG_BOOT_WAIT_FOR_NETWORK=2
Next, update
boot/dietpi-wifi.txt
by settingaWIFI_SSID[0]
to your WiFi SSID andaWIFI_KEY[0]
to your WiFi password. -
Unmount the SD card, insert it into the Raspberry Pi, and power it on.
It might take a moment to fully boot up and allow an SSH session since it will install all listed software on the first boot.
-
Check your WiFi router for connected devices to retrieve the IP of the Raspberry Pi.
-
Open an SSH session to the Raspberry Pi:
ssh root@<rpi-ip>
All upcoming steps are executed on the Raspberry Pi.
You can also usessh-copy-id
to install your public SSH key as an authorized key on the Raspberry Pi to avoid typing your password for new SSH sessions.ssh-copy-id root@<rpi-ip> ssh-copy-id dietpi@<rpi-ip>
-
Run
dietpi-config
to enable the camera and adjust the GPU memory.Under
1 : Display Options
, turn on8 : RPi Camera
and adjust the2 : GPU/RAM Memory Split
, e.g. to256 : General Gaming
. -
Mount the NFS directory of the guglhupf controller to using
dietpi-drive_manager
.Select
Add network drive
, thenNFS
, enter the guglhupf controller IP, and give it a unique folder name (e.g.,recordings
). -
Follow the other steps below to set up...
- the open-source
bcm2835-v4l2
camera driver - the camera utils
v4l-utils
for controlling rotation and resolution - a loopback device using
v4l2loopback
to mirrordev/video0
for multi-client access - a mirror from
dev/video0
todev/video1
using FFmpeg - a live video stream with
webrtc-streamer
- a recording service with FFmpeg
- the open-source
-
Add
bcm2835-v4l2
to/etc/modules-load.d/
(kernel modules to load at boot time).sudo nano /etc/modules-load.d/bcm2835-v4l2.conf
:bcm2835-v4l2
-
Reboot and check that
/dev/video0
exists.
-
Install
v4l-utils
for debugging & control commands.sudo apt install -y v4l-utils
Example command "rotatation of camera":
v4l2-ctl --set-ctrl=rotate=90
Example command "list video devices":
v4l2-ctl --list-devices
Example command "list video device details":
v4l2-ctl --device=/dev/video0 --all
-
Add
v4l2-ctl
command to system boot viaudev
subsystem.sudo nano /etc/udev/rules.d/99-local-webcam.rules
:SUBSYSTEM=="video4linux", PROGRAM="/usr/bin/v4l2-ctl --set-fmt-video=width=640,height=480 --set-ctrl=rotate=90"
Adjust the settings according to your needs (e.g., camera mounting rotation).
-
Reboot and check updated settings with
v4l2-ctl --device=/dev/video0 --all
.
-
Install
v4l2loopback
.sudo apt install -y linux-headers v4l2loopback-dkms v4l2loopback-utils
-
Add
v4l2loopback
to/etc/modules-load.d/
(kernel modules to load at boot time).sudo nano /etc/modules-load.d/v4l2loopback.conf
:v4l2loopback
-
Set parameters for
v4l2loopback
by creating a config file:sudo nano /etc/modprobe.d/v4l2loopback.conf
:options v4l2loopback devices=1 options v4l2loopback card_label="front"
Adjust the label to your preference. For guglhupf, there are two Raspberry Pis acting as Camera Agents with the camera labels
front
andback
. -
Reboot and check that
/dev/video1
exists.
Based on this StackOverflow answer.
-
Add video devices to
systemd
viaudev
subsystem.sudo nano /lib/udev/rules.d/99-systemd.rules
, beforeLABEL="systemd_end"
:# Systemd events for video devices KERNEL=="video0", SYMLINK="video0", TAG+="systemd" KERNEL=="video1", SYMLINK="video1", TAG+="systemd"
-
Reboot to activate new
udev
rules. -
Register
video-mirror
service withsystemd
.sudo nano /lib/systemd/system/video-mirror.service
:[Unit] Description=Mirror /dev/video0 to /dev/video1 with FFmpeg BindsTo=dev-video0.device dev-video1.device After=dev-video0.device dev-video1.device [Service] Type=simple ExecStart=ffmpeg -f v4l2 -i /dev/video0 -codec copy -f v4l2 /dev/video1 Restart=always RestartSec=1 StartLimitInterval=0 [Install] WantedBy=multi-user.target
-
Enable and start
video-mirror
service insystemd
.sudo systemctl daemon-reload sudo systemctl enable video-mirror.service sudo systemctl start video-mirror.service
-
Retrieve the latest
armv7l-Release
.cd /tmp wget https://github.com/mpromonet/webrtc-streamer/releases/download/v0.6.3/webrtc-streamer-v0.6.3-Linux-armv7l-Release.tar.gz tar -zxf webrtc-streamer-v0.6.3-Linux-armv7l-Release.tar.gz
-
Move
webrtc-streamer
binary.cd /tmp/webrtc-streamer-v0.6.3-Linux-armv7l-Release sudo mv ./webrtc-streamer /usr/local/bin/webrtc-streamer
-
Verify availability of
webrtc-streamer
command.webrtc-streamer --help
-
Register
webrtc-streamer
service withsystemd
.sudo nano /lib/systemd/system/webrtc-streamer.service
:[Unit] Description=WebRTC-streamer After=video-mirror.service [Service] Type=simple ExecStart=webrtc-streamer Restart=always RestartSec=1 StartLimitInterval=0 [Install] WantedBy=multi-user.target
-
Enable and start
webrtc-streamer
service insystemd
.sudo systemctl daemon-reload sudo systemctl enable webrtc-streamer.service sudo systemctl start webrtc-streamer.service
-
Validate WebRTC stream using a simple HTML page
-
Add monospaced
SourceCodePro
font.cd /tmp wget https://fonts.google.com/download?family=Source%20Code%20Pro -O SourceCodePro.zip unzip SourceCodePro.zip -d /tmp/SourceCodePro sudo mv /tmp/SourceCodePro /usr/share/fonts/truetype/
-
Add new
video-recording
command (bash script wrappingffmpeg
with parameters).sudo nano /usr/local/bin/video-recording
:#!/bin/bash ffmpeg \ -f v4l2 \ -video_size 640x480 \ -i /dev/video1 \ -map 0 \ -segment_time 300 \ -g 30 \ -sc_threshold 0 \ -force_key_frames "expr:gte(t,n_forced*300)" \ -f segment \ -reset_timestamps 1 \ -strftime 1 \ -vf "[in]\ drawtext=\ fontfile=/usr/share/fonts/truetype/SourceCodePro/SourceCodePro-Regular.ttf: \ textfile=/mnt/recordings/gps.txt: \ reload=1: \ x=10: \ y=h-text_h-10: \ fontsize=15: \ fontcolor=black: \ box=1: \ boxcolor=white@0.5: \ boxborderw=5,\ drawtext=\ fontfile=/usr/share/fonts/truetype/SourceCodePro/SourceCodePro-Regular.ttf: \ text='%{localtime}': \ x=w-text_w-10: \ y=h-text_h-10: \ fontsize=15: \ fontcolor=black: \ box=1: \ boxcolor=white@0.5: \ boxborderw=5 [out]" \ -c:v h264_omx \ -pix_fmt yuv420p \ /mnt/recordings/guglhupf/video_front_%Y-%m-%d_%H-%M-%S.mp4
A lot is going on here, and you might have to adjust a couple of settings (e.g., the filename template string).
FFmpeg reads from/dev/video1
in a fixed resolution of 640x480. It writes segments of the video feed to disk. Each segment is 5min (300sec), with keyframes enforced at the same time mark to allow a smooth cutover. It uses twodrawtext
filters: one to add GPS coordinates from a file (gps.txt
) to the lower-left corner and one to add timestamps to the lower-right corner of every frame. It uses the hardware-acceleratedh264_omx
codec and writes the output files to the configured NFS folder/mnt/recordings
with timestamps in the file name. -
Give execution rights to the new
video-recording
command:sudo chmod +x /usr/local/bin/video-recording
-
Test
video-recording
command:video-recording
-
Register
video-recording
service withsystemd
.sudo nano /lib/systemd/system/video-recording.service
:[Unit] Description=Video Recording with FFmpeg After=video-mirror.service [Service] Type=simple ExecStart=video-recording Restart=always RestartSec=1 StartLimitInterval=0 [Install] WantedBy=multi-user.target
-
Enable and start
video-recording
service insystemd
.sudo systemctl daemon-reload sudo systemctl enable video-recording.service sudo systemctl start video-recording.service
-
Use
htop
to verify thatvideo-recording
is running. You can also check the configured output folder, which should contain.mp4
files now.