Difference between revisions of "Streaming Video With RaspberryPi"
(→C. Use rsync to infinitely synchronise chunks on server) |
|||
Line 96: | Line 96: | ||
'''Some important points to mention here ''' | '''Some important points to mention here ''' | ||
− | * The | + | * The RaspberryPi MUST have access to a <server> using an SSH KEY for an <user>. Password access won't work for infinite rsync. |
* This <server> CAN be your laptop. If so it MUST be on the same LAN as the RaspberryPi | * This <server> CAN be your laptop. If so it MUST be on the same LAN as the RaspberryPi | ||
* This <server> CAN be a datacenter machie. If so it MUST be accessible on Internet by the RaspberryPi. | * This <server> CAN be a datacenter machie. If so it MUST be accessible on Internet by the RaspberryPi. | ||
Line 102: | Line 102: | ||
* It is advised to run this one liner in a <code>screen</code> command on the RaspberryPi | * It is advised to run this one liner in a <code>screen</code> command on the RaspberryPi | ||
− | <code> ssh user@server:/tmp/ "[ -d /tmp/capture ] || mkdir /tmp/capture" && while true; do rsync -a --files-from=/tmp/capture/out.list /tmp/capture user@server:/tmp/capture; sleep 1; done</code> | + | <code> ssh <user>@<server>:/tmp/ "[ -d /tmp/capture ] || mkdir /tmp/capture" && \ |
+ | while true; do rsync -a --files-from=/tmp/capture/out.list /tmp/capture <user>@<server>:/tmp/capture; sleep 1; done</code> | ||
Line 108: | Line 109: | ||
#<code> ssh </code> Use SSH ... | #<code> ssh </code> Use SSH ... | ||
− | ##<code> | + | ##<code> <user>@<server>:/tmp/ </code> ... to connect to server "server" as user "user" |
##<code> "[ -d /tmp/capture ] || mkdir /tmp/capture" </code> ... and create if not exists a folder "/tmp/capture" | ##<code> "[ -d /tmp/capture ] || mkdir /tmp/capture" </code> ... and create if not exists a folder "/tmp/capture" | ||
#<code> while true; do </code> Run an infinite loop | #<code> while true; do </code> Run an infinite loop | ||
Line 115: | Line 116: | ||
###<code> --files-from=/tmp/capture/out.list </code> Use the out.list as a list of file to transfer, which avoids scanning the whole folder | ###<code> --files-from=/tmp/capture/out.list </code> Use the out.list as a list of file to transfer, which avoids scanning the whole folder | ||
###<code> /tmp/capture </code> (source) Transfer local folder content... | ###<code> /tmp/capture </code> (source) Transfer local folder content... | ||
− | ###<code> user@server:/tmp/capture; </code> (destination) To the server "server" | + | ###<code> <user>@<server>:/tmp/capture; </code> (destination) To the server "server" |
##<code> sleep 1; </code> Sleep one second | ##<code> sleep 1; </code> Sleep one second | ||
− | #<code> done </code> | + | #<code> done </code> Loop end |
− | + | ==== D. Broadcast from server to icecast ==== | |
− | |||
− | |||
− | |||
− | <code> php /usr/local/bin/stream.php | ffmpeg -i - -f ogg - | oggfwd -p -n " | + | # You MUST install some script on <server> to assemble / concatenate the MPEGTS chunks for you. This PHP streamer is used as an example <code>http://pastebin.com/3f5t9vDS</code> |
+ | # You MUST install ffmpeg on <server> with ogg support (see below) | ||
+ | # You MUST install the oggfwd command line tool with <code>aptitude install oggfwd</code> | ||
+ | # You MUST have access to an icecast server. If you use a datacenter server, everything can run locally | ||
+ | |||
+ | <code> php /usr/local/bin/stream.php | ffmpeg -i - -f ogg -o - | oggfwd -p -n "My RaspberryPi Stream" <stream.server.com> 8000 mySecretIceCastStreamingPassword /test </code> | ||
+ | |||
+ | '''What's happening here''' | ||
+ | |||
+ | #<code> php /usr/local/bin/stream.php </code> Start an infinite stream of assembled chunks received via rsync | ||
+ | #<code> | ffmpeg </code> Pipe into FFMPEG | ||
+ | ##<code> -i - </code> (input) Use Standard In as input | ||
+ | ##<code> -f ogg </code> (format) Use ogg as output format | ||
+ | ##<code> -o - </code> (output) Output to Standard Out | ||
+ | #<code> | oggfwd </code> Pipe into oggfwd | ||
+ | ##<code> -p </code> (public) Makes the stream public. | ||
+ | ##<code> -n "My RaspberryPi Stream" </code> (name) Your stream name. '''Tweak''' | ||
+ | ##<code> <stream.server.com> </code> (address) Your icecast server name. '''Tweak''' | ||
+ | ##<code> 8000 </code> (port) 8000 is default for icecast | ||
+ | ##<code> <mySecretIceCastStreamingPassword> (password) The icecast input password '''Tweak''' | ||
+ | ##<code> /rpi01 </code> (mountpoint) The icecast "mountpoint" ie. the path for your stream | ||
+ | |||
+ | |||
+ | ==== E. Get the m3u from icecast ==== | ||
+ | |||
+ | With the default parameters provided the stream would be accessed on | ||
+ | |||
+ | <code>http://<stream.server.com>:8000/rpi01.m3u</code> | ||
'''Sources''' | '''Sources''' |
Revision as of 19:39, 16 January 2015
Contents
General
Caution: this is a Work in progress, things are being tested. The objective is to provide in the end one or more working solutions for everyone.
Video streaming is a problem
The RaspberryPi camera offers an interesting solution to this problem. It is a very well integrated module of the Pi with one huge advantage: h264 encoding can be performed directly by the CPU as the camera uses the Serial Camera Interface protocol.
So theorically, solving the video problem with the Pi is easy but there are many subtle problems.
Problems
Audio As we use video webstreaming mostly for conferences broadcasting, good audio quality is necessary.
Slides It would be interesting to include slides of conferences while filming.
File It is important to have a file at the end of the filming.
Web It is important to have a large viewer base, therefore a well supported format.
Raspicam basics
http://elinux.org/Rpi_Camera_Module
raspivid is the basic command line used to capture video in h264.
raspivid -t 3 -fps 25 -b 1000k -w 1920 -h 1080 -o /tmp/video.h264
A very simple tutorial : http://www.raspberrypi-spy.co.uk/2013/05/capturing-hd-video-with-the-pi-camera-module/
Solution
Solution 1 : OGG/VORBIS + Icecast
Basic idea
- Use the PI to capture video as h264, merge audio from usb and use ffmpeg to produce MPEGTS "chunks"
- Rsync the chunks to a laptop or a server (note : the audio mix can be done on the laptop)
- Assemble the chunks and pipe them in ffmpeg
- Ask ffmpeg to convert this into ogg
- Use oggfwd to push the ogg to your icecast server
- Serve m3u from the server
CON ogg does not work for everyone. It is supposed to be HTML5 compatible but icecast doesn't offer that by default.
PRO Icecast is simple, open, and handles authentification. Rsync using SSH is crypto friendly. The file is saved on the server.
How to stream in OGG to Icecast
A. Compile FFMPEG on pi & server (see below)
B. Start capture in a screen
It is advised to run this one liner in a screen
command on the RaspberryPi
[ -d /tmp/capture ] || mkdir /tmp/capture; rm -f /tmp/capture/* && cd /tmp/capture/ && \
raspivid -ih -t 0 -w 1280 -h 720 -b 1000000 -pf baseline -o - | /usr/local/bin/ffmpeg -f alsa -itsoffset 6.5 -ac 1 -i hw:1 -acodec aac -strict -2 \
-i - -vcodec copy -f segment -segment_list out.list -segment_list_flags +live -segment_list_size 5 -segment_time 4 -segment_time_delta 3 %10d.ts
What's happening here
- We create a /tmp/capture folder and make sure it's empty when starting capture
- Raspivid starts capturing with following parameters
-ih
(inline headers) DONT CHANGE Necessary for technical reasons, as otherwise the "chunking" doesn't work-t 0
(timeout) DONT CHANGE Necessary for technical reasons, as otherwise capture stops after 5s-w 1080 -h 720
(height) and (width) Tweak according to your needs-b 1000000
(bitrate) Tweak according to your needs (only integer numbers in bits are accepted, here <=> 1Mb)-pf baseline
(h264 profile) Tweak according to your needs ( only baseline, main, or high accepted)-o -
(output) DONT CHANGE Necessary in order to use the flux as Standard Output
- We pipe the content into ffmpeg
- ALSA Input
-f alsa
(format) We usealsa
for usb audio capture-itsoffset 6.5
(time offset) This one is a trick We noticed our RPi B+ had a 6.5 seconds delay to start the audio, so this is used to resync audio. Tweak.-ac 1
(number of audio channels) We used a mono input, so1
was the right choice. Tweak-i hw:1
(input) Tweak as your audio card adress may vary. Find more witharecord -l
-acodec aac
(audio codec) AAC works well for TS live.-strict -2
Argument mandatory for AAC format
- Video Input
-i -
(input) DONT CHANGE Use the Standard input-vcodec copy
(video codec) DONT CHANGE Use the video codec from the RPi. Not enough CPU to do anything else.-f segment
(output format) DONT CHANGE Use a "chunked" output-segment_list out.list
(segment file) Defines a file containing the produced files names-segment_list_flags +live
(segment file flags) Defines the way the output file caches files names.-segment_list_size 5
(segment file size)-segment_time 4
(segment time) Defines the capture base duration in seconds. Tweak.-segment_time_delta 3
(segment time delta) Defines a window to modulate chunks duration in seconds to include mandatory inline headers. Tweak.%10d.ts
The format for chunks files names. %10d will start at 0000000000.ts and ffmpeg understand we want MPEGTS format for chunks
- ALSA Input
- ffmpeg saves the files 0000.ts, 0001.ts, etc. and out.list in /tmp/capture
C. Use rsync to infinitely synchronise chunks on server
Some important points to mention here
- The RaspberryPi MUST have access to a <server> using an SSH KEY for an <user>. Password access won't work for infinite rsync.
- This <server> CAN be your laptop. If so it MUST be on the same LAN as the RaspberryPi
- This <server> CAN be a datacenter machie. If so it MUST be accessible on Internet by the RaspberryPi.
- This <server> MUST have FFMPEG installed (see point D below)
- It is advised to run this one liner in a
screen
command on the RaspberryPi
ssh <user>@<server>:/tmp/ "[ -d /tmp/capture ] || mkdir /tmp/capture" && \
while true; do rsync -a --files-from=/tmp/capture/out.list /tmp/capture <user>@<server>:/tmp/capture; sleep 1; done
What's happening here
ssh
Use SSH ...<user>@<server>:/tmp/
... to connect to server "server" as user "user""[ -d /tmp/capture ] || mkdir /tmp/capture"
... and create if not exists a folder "/tmp/capture"
while true; do
Run an infinite looprsync
Start rsync file synchronisation-a
(archive mode) Set the right parameters for transfer--files-from=/tmp/capture/out.list
Use the out.list as a list of file to transfer, which avoids scanning the whole folder/tmp/capture
(source) Transfer local folder content...<user>@<server>:/tmp/capture;
(destination) To the server "server"
sleep 1;
Sleep one second
done
Loop end
D. Broadcast from server to icecast
- You MUST install some script on <server> to assemble / concatenate the MPEGTS chunks for you. This PHP streamer is used as an example
http://pastebin.com/3f5t9vDS
- You MUST install ffmpeg on <server> with ogg support (see below)
- You MUST install the oggfwd command line tool with
aptitude install oggfwd
- You MUST have access to an icecast server. If you use a datacenter server, everything can run locally
php /usr/local/bin/stream.php | ffmpeg -i - -f ogg -o - | oggfwd -p -n "My RaspberryPi Stream" <stream.server.com> 8000 mySecretIceCastStreamingPassword /test
What's happening here
php /usr/local/bin/stream.php
Start an infinite stream of assembled chunks received via rsync| ffmpeg
Pipe into FFMPEG-i -
(input) Use Standard In as input-f ogg
(format) Use ogg as output format-o -
(output) Output to Standard Out
| oggfwd
Pipe into oggfwd-p
(public) Makes the stream public.-n "My RaspberryPi Stream"
(name) Your stream name. Tweak<stream.server.com>
(address) Your icecast server name. Tweak8000
(port) 8000 is default for icecast<mySecretIceCastStreamingPassword> (password) The icecast input password Tweak
- <code> /rpi01 (mountpoint) The icecast "mountpoint" ie. the path for your stream
E. Get the m3u from icecast
With the default parameters provided the stream would be accessed on
http://<stream.server.com>:8000/rpi01.m3u
Sources
http://sirlagz.net/2013/01/07/how-to-stream-a-webcam-from-the-raspberry-pi-part-3/
Solution 2 : FLVSTR + PHP Streamer
Basic idea the Octopuce company has a solution to convert live MP4 to F4V. With an USB audio card, we could mux the MP4 and AAC audio and have a standalone solution.
CON authentification is hard, F4V means Flash, requires an USB disk for local backup
PRO the pi can be autonomous
First, authentification. This problem is adressed by solving encryption as well: we use an SSL socket to communicate with the server.
Solution 3 : RTSP
Basic idea Use an RTSP stream with VLC and the V4L driver
CON Non commercial RTSP server are not the norm, requires VLC or Flash player, Quality with v4l is low
PRO Easy to work out
Sources
http://www.ics.com/blog/raspberry-pi-camera-module#.VJFhbyvF-b8
http://ffmpeg.gusari.org/viewtopic.php?f=16&t=1130
Solution 4 : HLS + RSYNC
Basic idea Use HLS segmentation and rsync
CON Not all web players can do HLS
PRO Almost out of the box, robust
Howto
1. Compile fresh ffmpeg on the pi
2. Run a capture : raspivid -t 0 -b 1000000 -w 1080 -h 720 -v -o - | ffmpeg -i - -f alsa -ac 1 -itsoffset 6.5 -i hw:1 -acodec aac -strict -2 -vcodec copy out.m3u8
3. Run a cron rsync to server (todo)
4. Connect a client (todo)
Sources
http://www.ffmpeg.org/ffmpeg-formats.html#hls
FFMPEG compilation
This installation is debian based. Some packages are included by default :
- ffmpeg : Provides a large number of the dependencies required at compilation tim
- yasm : modular assembler (good for compilation)
- pkg-config : info about installed libraries (good for compilation)
- screen : helpful for running compilation in background
For Raspberry
For the Raspberry, we only need the support of x264 and ALSA
sudo -s aptitude install screen yasl libx264-dev libasound2-dev ffmpeg cd /usr/src git clone --depth 1 git://source.ffmpeg.org/ffmpeg.git cd ffmpeg ./configure --enable-gpl --enable-libx264 make make install
For laptop or server
Your default debian might come with sufficent support but if you want total control, compiling is a good idea.
Remove packages and ffmpeg support if you don't need everything.
Ex: to produce ogg format, you only need
- aptitude packages libtheora-dev and libvorbis-dev
- configure options --enable-libtheora --enable-libvorbis
sudo aptitude update && aptitude install screen pkg-config yasm ffmpeg libass-dev libavcodec-extra libfdk-aac-dev libmp3lame-dev libopus-dev libtheora-dev libvorbis-dev libvpx-dev libx264-dev cd /usr/src git clone --depth 1 git://source.ffmpeg.org/ffmpeg.git cd ffmpeg ./configure --enable-gpl --enable-libass --enable-libfdk-aac --enable-libfreetype --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvorbis --enable-libvpx --enable-libx264 --enable-nonfree --enable-x11grab make make install
References
Here are a number of unsorted links
http://techzany.com/2013/09/live-streaming-video-using-avconv-and-a-raspberry-pi/
https://trac.ffmpeg.org/wiki/StreamingGuide
Node
http://phoboslab.org/log/2013/09/html5-live-video-streaming-via-websockets https://github.com/fluent-ffmpeg/node-fluent-ffmpeg
http://ffmpeg.org/ffmpeg-all.html#segment_002c-stream_005fsegment_002c-ssegment