James Bos

Using a Raspberry PI for RTSP streaming

At our office, we have just replaced the aging existing CCTV system with a 32 channel Hikvision NVR and nearly just as many IP Cameras. This NVR (and the cameras separately) include 2 RTSP streams (main and a lower bitrate sub stream)

This allows me to be able to stream multiple cameras to the Raspberry Pi using omxplayer. The great thing is, omxplayer will quite happily display more than one stream on screen at the same time (for my case, I am streaming 9 cameras to a 1920x1080 display)

I won't go into the whole setup of the pi itself since there is already a metric shit ton of said rundowns on Google.

omxplayer

Firstly, we need to understand how omxplayer handles multiple video streams. For the purpose of this example, I am using 9 camera streams. omxplayer can wrap each stream in a window within the framebuffer using the --win command line switch (yep, we don't need to run this in X!)

The following would position our stream in the top right corner with Y ending at 640 px and the X ending at 360px

omxplayer --win "0 0 640 360" rtsp://ipaddress/stream/channel/1

Now, for example, we want all 9 cameras to display in a 3x3 grid on our 1920x1080 display

# first row (left, middle, right)
omxplayer --win "0 0 640 360" rtsp://user:pass@10.0.10.100/stream/channel/1
omxplayer --win "640 0 1280 360" rtsp://user:pass@10.0.10.101/stream/channel/1
omxplayer --win "1280 0 1920 360" rtsp://user:pass@10.0.10.102/stream/channel/1

# second row (left, middle, right)
omxplayer --win "0 360 640 720" rtsp://user:pass@10.0.10.103/stream/channel/1
omxplayer --win "640 360 1280 720" rtsp://user:pass@10.0.10.104/stream/channel/1
omxplayer --win "1280 360 1920 720" rtsp://user:pass@10.0.10.105/stream/channel/1

# third row (left, middle, right)
omxplayer --win "0 720 640 1080" rtsp://user:pass@10.0.10.106/stream/channel/1
omxplayer --win "640 720 1280 1080" rtsp://user:pass@10.0.10.107/stream/channel/1
omxplayer --win "1280 720 1920 1080" rtsp://user:pass@10.0.10.108/stream/channel/1

So as you can see, it's not all that confusing. You can have as many streams as you like, but you will most likely have to allocate more video memory by adding/changing the gpu_mem parameter in /boot/config.txt. I have gpu_mem=256 set in mine and it works perfectly fine.

Dealing with connection drop outs

By default, omxplayer will shit the bed and spit out the infamous "Have a nice day :)" to stdout when the connection drops out. We can mitigate this with some simple bash scriptage. For the sake of example, we'll call this file cctvhandler.sh

#!/bin/bash
USER=$1
PASS=$2
IPADDR=$3
LEFT=$4
TOP=$5
RIGHT=$6
BOTTOM=$7

while true; do
    if [[ $(ps ax | grep omxplayer.bi[n] | grep $IPADDR | cut -d ' ' -f 3) ]];then
            :
    else
            omxplayer --no-keys --win "$LEFT $TOP $RIGHT $BOTTOM" \
            rtsp://$USER:$PASS@$IPADDR/Streaming/Channels/102
    fi
    sleep 15
done

This will check if the PID exists for omxplayer.bin, if it doesn't, it'll go ahead and run omxplayer again with our desired command line parameters. Using the command line arguments means we don't need a separate file for each camera. We can simply run it by running:

./cctvhandler.sh yourusername yourpassword 10.0.10.100 0 0 640 360

Now, I didn't want to have to manually type that in every time, so we'll just call multiple instances of our script from one file. Let's call it start.sh

#!/bin/bash
./cctvhandler.sh yourusername yourpassword 10.0.10.100 0 0 640 360 &
./cctvhandler.sh yourusername yourpassword 10.0.10.101 640 0 1280 360 &
./cctvhandler.sh yourusername yourpassword 10.0.10.102 1280 0 1920 360 &
./cctvhandler.sh yourusername yourpassword 10.0.10.103 0 360 640 720 &
./cctvhandler.sh yourusername yourpassword 10.0.10.104 640 360 1280 720 &
./cctvhandler.sh yourusername yourpassword 10.0.10.105 1280 360 1920 720 &
./cctvhandler.sh yourusername yourpassword 10.0.10.106 0 720 640 1080 &
./cctvhandler.sh yourusername yourpassword 10.0.10.107 640 720 1280 1080 &
./cctvhandler.sh yourusername yourpassword 10.0.10.108 1280 720 1920 1080 &

And that's it! I call the start.sh from my bashrc for all non SSH logins

if [ "x${SSH_TTY}" = "x" ]; then
    /home/pi/start.sh
fi

You'll probably want to enable auto login, but again, that's what google is for!