Streaming the Raspberry Pi Camera

While Recording 1080p at 30 FPS

Can it be done? It can! I am doing it!?

I have a Raspberry Pi recording 1080p, 30 frames per second, high bit-rate. It records beautiful! Exactly what I want. I simply want to be able to view my camera Live whenever I want, without effecting the recording. Sounds simple. Right? Well, you may have looked for a solution and found that it is not so simple.

Every solution I found had unacceptable side effects. Like:

I did not want to run a 100 foot HDMI cable out to my camera. I can find them on Amazon for about $47.00, but I don't think I could get it to go inside the camera housing without cutting the cable, or drilling a hole for it into the camera housing. UGH! Running yet another wire to the camera would be a pain, I already have a 100 ft Ethernet cable I had to run, plus power for the RPI and power power to the housing heater/fan. Another concern I had was I have never seen an HDMI cable over 10 feet or so...I am not sure it would even work at 100 feet. Okay, too many problems, expensive, and not sure it would even work. The 100 foot cable is not an option. I am glad...it just seemed too Rube Goldbergesque.

There had to be a solution to the problem. I am recording exactly the way I want. I don't want the fact that I am viewing, or not viewing to effect my recording at all!

I finally found a streaming solution called NETCAT in combination with MPlayer. But the instructions I found for setting it up left me with many of the same issues I described above. I played with it a bit and came up with a solution that works perfectly (for me anyway).

Eureka! I have a full screen HD view of my camera. I can start watching, or stop watching whenever I want. My viewing or not viewing does not affect my recording which is 1080p/30.

The lag of the live view is less than 2 seconds. I say this, but when you first start the view, your lag will most likely be minutes...YIKES!! Easy to fix. Hit the up arrow once. The picture will freeze and after a few seconds you will see a [.........] overlay the picture for a few seconds and action will resume. You just jumped ahead 1 minute. Hit the up arrow again. repeat till you really are live. The LAG is actually self correcting. Once the segment of recording changes, the video will jump to live. So if you just wait a bit, you don't need to hit the arrow at all.

This solution has two drawbacks that I can see. First is the initial, self correcting LAG I described above. Second, only 1 PC may view the camera, and this PC must have a static IP on the local LAN. If these issues are unacceptable to you, you can use the same solution for MANY other programs. You don't have to use NetCat and Mplayer. Modify the concept for the programs you want to use. I can imagine modifying this to setup a stream for websites or mobile apps. The point is it gives you a way to hook into the camera the same time you are recording.

Okay, what you need to do to get this to work.

First, you need to install NetCat and (optionally) Mplayer on the Raspberry Pi. How? Well it is simple...

$ sudo apt-get install mplayer netcat

Now, you probably have already written a routine to record your camera that runs in background. For example purposes, here is a very simplified DVR script. This is for example purposes only, lets not complain about this POS script will cause problems. Also I write in the Korn shell. I began programming in the 1980's when all we had was the bourn shell (sh). Years later I relearned everything to use the C Shell (csh), then again to use the Korn shell (ksh). I refuse to become bourn again (bash). Figure it out.

#!/bin/ksh # # dvr.sh # # An example simple DVR routine by Gerard W. Callahan # Nobody in their right mind would dump huge h264 into the tmp directory. THIS IS AN EXAMPLE # LOOP=1 while test "$LOOP" -ne "0" do FILENAME="/tmp/video-`date '+%H'`-`date '+%M'`.h264" raspivid -f -drc high -ev auto -sh 10 -w 1920 -h 1080 -fps 30 -i record -o $FILENAME -fps 30 -b 25000000 -pf high -ih -t 300000 done

Does this script work...IDK, It is an example...I would never output my video file to /tmp on the local SD card. I just put it up, I did not test it. Just imagine this script running in background, throwing 5 minute HD videos into your tmp directory on your SD card. YIKES!

Okay, lets modify this script to give a hook in for the streaming script we need to write. We are going to put the fully qualified path of the current video being recorded into a file called /tmp/current.tab. The streaming script we are going to write needs to know the path/name of the video being created. However you decide to get that name to the script is up to you. This is just an example of one way to do it.

#!/bin/ksh # # dvr.sh # # A Modified example simple DVR routine by Gerard W. Callahan # Nobody in their right mind would dump huge h264 into the tmp directory. THIS IS AN EXAMPLE # LOOP=1 while test "$LOOP" -ne "0" do FILENAME="/tmp/video-`date '+%H'`-`date '+%M'`.h264" # Save file name for steaming script echo "$FILENAME" > /tmp/current.tab raspivid -f -drc high -ev auto -sh 10 -w 1920 -h 1080 -fps 30 -i record -o $FILENAME -fps 30 -b 25000000 -pf high -ih -t 300000 done

This is the only modification you need to make to your DVR routine. You don't need to do it this way, it is an example.

Okay, we have a DVR running in background creating H264 videos in any definition you want. dvr.sh is creating a hook that allows us to know the path and name of the current video being recorded. Let's stream that file!!...

Write some code that interrogates /tmp/current.tab when it changes, make a fifo buffer IE: mkfifo /tmp/dvrfifo then use code like this to tail the current video into the fifo buffer tail -n +0 -f "$CURRENTVIDEO" > $FIFO & Save the PID of the tail, you will need to kill it when the video name changes then start the stream of the buffer you are creating: cat /tmp/dvrfifo | nc $STREAMIP $STREAMPORT & save this PID too...you need to kill it when the video name changes STREAMIP is the IP of the PC receiving the stream STREAMPORT is a unique port. I use 65001 for my first camera, 65002 for my second camera, etc when the file changes, kill the tail...kill the cat...delete /tmp/dvrfifo...then do the above again

NOTE: your script needs to interrogate the PID for the cat ---> nc is still running if the file name has not changed. nc will terminate if the viewing pc starts viewing, then stops. You need to restart the cat ---> nc if it is no longer running.

mkfifo /tmp/dvrfifo tail -n +0 -f "$CURRENTVIDEO" > $FIFO & delete /tmp/dvrfifo when the CURRENTVIDEO name changes and kill the PID of the tail # # Put the static IP of the PC that is going to get the video stream # STREAMIP=192.168.0.45 # # A unique port. I use multiple RPi's as cameras. The first camera I assign 65001, the second I assign 65002 etc # STREAMPORT=65001 # Remove old FIFO buffer if it exists if test -r "$FIFO" then echo "removing FIFO Buffer" rm -f "$FIFO" fi # Loop forever while test "$LOOP" -ne "0" do if test -r "$FNAME" then # Get the name of the H264 file currently being created (remember? We created this in that POS dvr script.) NAME=`cat $FNAME` # See if the current file is the same one we are buffering if test "$NAME" != "$CURRENT" then echo "Buffer is changing!" # Wait for new video to have a size while test ! -s "$NAME" do echo "Waiting for $NAME to get data" sleep 1 # Make sure file did not change while we were waiting NAME=`cat $FNAME` done # If we were filling the buffer, stop the old video feed to the buffer if test "$PPID" -ne 0 then kill -9 $PPID fi # Clear the buffer and initialize it if test ! -r $FIFO then echo "Creating the buffer" rm -f $FIFO 2>/dev/null mkfifo $FIFO fi # Put the current video in the buffer CURRENT="$NAME" echo "Filling new pipe with $NAME" tail -n +0 -f "$CURRENT" > $FIFO & PPID=$! echo "Starting Stream to $STREAMIP on port $STREAMPORT" cat $FIFO | nc $STREAMIP $STREAMPORT & PPID2=$! sleep 5 else COUNT=`ps auxww | grep -v grep | grep -c " nc "` # If NC is not running (Most likely Viewer connected, then disconnected), restart it. if test "$COUNT" -eq "0" then # Force restart on next loop echo "nc died...restarting..." CURRENT="" fi fi else echo "No current video...waiting..." sleep 5 fi done

I would not run this script in background until you are sure everything is working correctly. Run this script on the RPi and then go over to your PC. Drop to a DOS prompt and cd c:\netcat, then type:

c:\NetCat> c:\netcat\nc64.exe -L -p 65001 | "c:\program files (x86)\mplayer for windows\mplayer.exe" -fps 31 -cache 1024 -

Wait for it...poof! If everything is working, you should get a full screen view of your camera!