Real-Time Video Stream with Raspberry Pi
Over the years I’ve accumulated a few Raspberry Pis of different versions, each of which I’ve used for certain things, some of them I’ve retired or upgraded to newer versions. Consequently, I have a few Raspberry Pi 1 and 1B still around, and they’re not doing much aside from collecting dust. I also have an old Raspberry Pi NoIR camera that I haven’t been using much.
Over the years I’ve tried different things, including PIR-triggered recording of the camera feed, sort of to build a device that records what’s happening when the infrared sensor is triggered. While that actually worked just fine, I also wanted to be able to get a steady video stream from the camera that can be observed over the internet, if necessary.
Here’s how I ended up doing that. My setup is
- Raspberry Pi 1
- Pi NoIR Camera Rev 1.3
- Raspbian 11 (bullseye) with Linux kernel 6.1 (it’s a while since I’ve re-imaged the SD card ;-))
Set up the camera
My Pi NoIR camera has certain defaults that I don’t quite like. I use the
following setup.sh
script to change these defaults to use my preferred values.
First I print the current values. In a next step, I update the video bitrate
mode, set the video bitrate to 800 kbps and reset the color effects to the
default. Here’s where you could turn on things like black-and-white, negative,
and so on. Finally, I let v4l2-ctl
print the updated settings for
confirmation.
The updates are applied to the device, so even if you restart the stream afterwards, these settings will stay in effect until overwritten, or until you reboot.
$ cat ~/setup.sh
#!/bin/bash
echo 'Current settings:'
v4l2-ctl --list-ctrls
echo
echo 'Updating bit rate ...'
v4l2-ctl -d /dev/video0 --set-ctrl=video_bitrate_mode=1 \
--set-ctrl=video_bitrate=800000 --set-ctrl=color_effects=0
echo
echo 'Updated settings:'
v4l2-ctl --list-ctrls
Start the video stream
The stream.sh
script is used to start the stream with the help of VLC. I use
the command-line tool cvlc
as you can see below. The script has VLC capture
the feed from /dev/video0
, which is my Pi NoIR camera. It’s instructed to
capture a Full HD feed at 30 frames per second, and use the H.264 video coding.
Because I mounted the camera in a way that does not need the ribbon cable to be
twisted, I also need to flip the captured image both horizontally and vertically
to match what a humand would see.
And last but not least, the --sout '...'
argument tells VLC that I’d like the feed to be made available over RTP with
RTSP as the session description protocol, using port 8554. The default port
for RTSP is 554, so binding to that TCP port typically requires more permissions
which I didn’t want to fiddle with for this toy.
$ cat ~/stream.sh
#!/bin/bash
echo 'Open RTSP streaming server on port 8554 ...'
cvlc v4l2:///dev/video0 --v4l2-width 1920 --v4l2-height 1080 --v4l2-fps 30 \
--v4l2-chroma h264 --v4l2-vflip 1 --v4l2-hflip 1 \
--sout '#rtp{sdp=rtsp://:8554}' :no-sout-all :sout-keep :demux=264
Start the stream automatically on reboot
To start the stream automatically after the Rasberry Pi has booted, I rely on
cron
. Here’s what my crontab
looks like:
$ crontab -l
# [... irrelevant stuff ...]
@reboot /home/pi/start-stream.sh
And here’s what that start-stream.sh
script looks like:
$ cat ~/start-stream.sh
#!/bin/bash
sleep 15
/home/pi/setup.sh
nohup /home/pi/stream.sh &
The sleep
with 15 seconds is, as you would probably expect, a work-around for
delays in other dependencies on the system. Perhaps there’s a way to use signals
instead, but I didn’t bother to invest a lot of time here, so for now this does
the trick.
Watch the stream
Supposedly any software that can show an RTP stream initiated over RTSP can be
used to watch the stream. For instance, on Linux I use ffplay
as follows:
$ ffplay rtsp://host-address:8554/
If you’re streaming over the internet, do not forget to address the following:
- Security: With the above instructions, you’ll get a feed that anybody knowing the address (and port) can watch too.
- Port-forwarding: You’ll probably not have the Raspberry Pi connected to the internet directly, so port-forwarding may be needed. That goes for the RTSP port (tcp/8554 in my setup) as well as the UDP port used for the actual RTP stream. I haven’t found a way to fix the UDP port (I also didn’t care much, TBH) with VLC, so typically it selects a random port. Keep that in mind when setting up port forwarding for UDP.
Conclusion
It’s really quite easy to turn your Raspberry Pi with camera into a video streaming device. The quality is quite decent, and CPU consumption is below 10% for the first streaming client, but grows with additional clients. With my 800 kbps for a 30 fps Full HD stream I get a pretty decent quality: I can easily see the branches and leaves of trees 50 meters away, and I can see fluent motions of people and cars. I think the hardware for this cost less than 100 $ total (many years ago). The benefit is what you make of it ;-)