In this post, I want to share an important update to my home surveillance system based on the Raspberry Pi Zero 2W. I’ve spent a considerable amount of time refining a stable FullHD RTMP stream
In this post, I want to share an important update to my home surveillance system based on the Raspberry Pi Zero 2W. I’ve spent a considerable amount of time refining a stable FullHD RTMP stream from the Raspberry Pi to a local NGINX-RTMP server, with motion-based local recording—without relying on any cloud services.
The system is designed to run fully offline and on-premises, providing high-resolution live streaming and recording for home or small-office surveillance setups. This update includes several critical optimizations for audio-video synchronization, power stability, and streaming performance.
🛠️ Hardware Used
- Raspberry Pi Zero 2W (rev. 1.0)
- USB microphone (standard ALSA compatible)
- Raspberry Pi camera module (v2, v3 or compatible)
- Local NGINX server with RTMP module
- 5V 3A reliable power supply
🔧 Optimizing Raspberry Pi for Stable Streaming
The Raspberry Pi Zero 2W is surprisingly capable, but to get a stable FullHD stream, you need to tweak the system configuration carefully, especially due to limited power margins and CPU/GPU capabilities.
Edit /boot/config.txt
with the following key parameters:
# ARM and GPU settings
arm_boost=1
arm_freq=1000
over_voltage=2
sdram_freq=450
temp_limit=80
Why over_voltage=2
is Crucial
When using ALSA with a USB microphone, I experienced frequent ALSA buffer underruns (xruns) that would corrupt the RTMP stream, making it unusable for ffmpeg decoders or motion-based analysis.
After much trial and error, I discovered that increasing over_voltage
stabilized the power supply enough to prevent audio glitches. This change had a direct and measurable impact on stream stability, especially over longer periods (3+ hours continuous streaming).
📹 RTMP Streaming Script
Here’s the complete streaming script I now use. It runs as a systemd service (stream.service
) and captures FullHD video with audio, using the hardware encoder and libav for streaming:
#!/bin/bash
nice -n -19 rpicam-vid -t 0 --width 1920 --height 1080 --nopreview 1 --low-latency 1 --hdr off --buffer-count 4 --flush 1 \
--exposure normal --sharpness 1.2 --contrast 1.2 --brightness 0.0 --saturation 1.0 --ev +1.1 --awb auto \
--profile high --level 4.2 --codec libav --libav-audio --audio-source alsa --audio-device plughw:0,0 --audio-channels 2 --audio-codec aac \
--audio-samplerate 48000 --audio-bitrate 128000 --libav-format flv -n --framerate 30 -b 5000000 \
--autofocus-mode manual --lens-position 0.8 --denoise auto \
--autofocus-window 0.25,0.25,0.5,0.5 --inline 1 -o "rtmp://192.168.178.25/zero/test"
This setup streams to the local RTMP server at rtmp://192.168.178.25/zero/test
.
Key Parameters Explained:
--codec libav
+--libav-audio
: Enables hardware-accelerated H.264 encoding with ALSA audio input--audio-device plughw:0,0
: Ensures ALSA uses the USB mic directly--bitrate 5000000
: FullHD stream at 5 Mbit/s--framerate 30
: Smooth video for both live view and recording--over_voltage=2
: Prevents buffer underruns due to low power issues


✅ Systemd Stream Output (Clean Example)
This is how a clean, stable streaming session looks when monitoring the stream process with:
journalctl -u stream.service -f
Example output:
csharpKopierenBearbeiten[h264_v4l2m2m @ 0x557306fa60] <<< v4l2_encode_init: fmt=179/0
[h264_v4l2m2m @ 0x557306fa60] Using device /dev/video11
[h264_v4l2m2m @ 0x557306fa60] driver 'bcm2835-codec' on card 'bcm2835-codec-encode' in mplane mode
[h264_v4l2m2m @ 0x557306fa60] requesting formats: output=YU12 capture=H264
Input #0, alsa, from 'plughw:0,0':
Duration: N/A, start: 1749990066.803250, bitrate: 1536 kb/s
Stream #0:0: Audio: pcm_s16le, 48000 Hz, 2 channels, s16, 1536 kb/s
Output #0, flv, to 'rtmp://192.168.178.25/zero/test':
Stream #0:0: Video: h264 (High), drm_prime(tv, bt709), 1920x1080, q=2-31, 5000 kb/s, 30 fps, 30 tbr, 1000k tbn
Stream #0:1: Audio: aac (LC), 48000 Hz, stereo, fltp, 128 kb/s
🧠 Lessons Learned
Getting a stable and synchronized FullHD stream with audio on the Raspberry Pi Zero 2W was not plug-and-play. Here are some key insights:
- Power stability is critical: Use a high-quality power supply. Even slight undervoltage causes audio xrun issues.
- over_voltage=2 made a big difference in ALSA and USB device reliability.
- The built-in H.264 hardware encoder on
/dev/video11
is efficient, but needs proper buffering to avoid dropped frames. - Audio sync only works reliably with ALSA plughw, not default devices.
📦 Recording with Motion
Once the stream is running, it’s picked up by motion (motionEye or native motion) on a separate server. Motion connects to the RTMP stream as an input source and saves recordings based on movement detection. These recordings are stored locally, without cloud dependency.
This gives me:
- Live viewing via RTMP-compatible clients (VLC, OBS, web dashboards)
- Local recordings on disk whenever motion is detected
- Zero reliance on cloud platforms
✅ Final Thoughts
With this setup, the Raspberry Pi Zero 2W becomes a powerful low-cost FullHD camera for DIY home surveillance—fully offline, fully open-source, and fully under your control.
The combination of rpicam-vid
, NGINX RTMP, ALSA audio, and motion-based recording results in a smooth and stable system that runs for days without issues.
If you’ve struggled with audio sync or stream instability on the Pi Zero 2W, these exact configuration tweaks may save you many hours of frustration.