Difference between revisions of "Streaming Video With RaspberryPi"

From Tmplab
(For laptop or server)
(Solution 1 : OGG/VORBIS + Icecast)
Line 37: Line 37:
  
  
'''Basic idea''' use the PI to capture MP4, stream it locally to a laptop. Merge audio in the laptop with ffmpeg and push the resulting ogg/vorbis stream to an icecast server.
+
'''Basic idea'''  
  
'''CON''' Mandatory local network between pi and laptop for socket,
+
# 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
  
'''PRO''' Icecast is simple, open, and handles authentification. The file is saved on the server. Vorbis is HTML5 compatible.  
+
'''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.  
  
 
'''Sources'''
 
'''Sources'''
Line 49: Line 56:
  
 
'''POC'''
 
'''POC'''
 
+
'''A.''' Compile FFMPEG on pi & server
+
'''A.''' Compile FFMPEG on pi & server (see below)
  
 
'''B.''' Start capture in a screen
 
'''B.''' Start capture in a screen
  
 
     <code># [ -d /tmp/capture ] || mkdir /tmp/capture; rm -f /tmp/capture/* && cd /tmp/capture/ && \
 
     <code># [ -d /tmp/capture ] || mkdir /tmp/capture; rm -f /tmp/capture/* && cd /tmp/capture/ && \
     raspivid -ih -h 320 -w 480 -t 0 -o - | /usr/local/bin/ffmpeg  -f alsa -ac 1 -itsoffset 6.5 -i hw:1 -acodec aac -strict -2 -i -\
+
     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 \
    -vcodec copy -f segment -segment_list out.list -segment_list_flags +live -segment_time 3 -segment_time_delta 2 %4d.ts</code>
+
    -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</code>
 +
 
 +
''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
 +
##<code> -ih </code>(inline headers) '''DONT CHANGE''' Necessary for technical reasons, as otherwise the "chunking" doesn't work
 +
##<code> -t 0 </code> (timeout) '''DONT CHANGE''' Necessary for technical reasons, as otherwise capture stops after 5s
 +
##<code> -w 1080 -h 720 </code> (height) and (width) Tweak according to your needs
 +
##<code> -b 1000000 </code> (bitrate) Tweak according to your needs (only integer numbers in bits are accepted, here <=> 1Mb)
 +
##<code> -pf baseline </code> (h264 profile) Tweak according to your needs ( only baseline, main, or high accepted)
 +
##<code> -o - </code> (output) '''DONT CHANGE''' Necessary in order to use the flux as Standard Output
 +
# We pipe the content into ffmpeg
 +
## ALSA Input
 +
###<code> -f alsa </code> (format) We use <code>alsa</code> for usb audio capture
 +
###<code> -itsoffset 6.5 </code> (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.
 +
###<code> -ac 1 </code> (number of audio channels) We used a mono input, so <code>1</code> was the right choice. Tweak
 +
###<code> -i hw:1 </code> (input)  '''Tweak''' as your audio card adress may vary. Find more with <code>arecord -l</code>
 +
###<code> -acodec aac </code> (audio codec) AAC works well for TS live.
 +
###<code> -strict -2 </code> Argument mandatory for AAC format
 +
## Video Input
 +
###<code> -i - </code> (input) '''DONT CHANGE''' Use the Standard input
 +
###<code> -vcodec copy</code> (video codec) '''DONT CHANGE''' Use the video codec from the RPi. Not enough CPU to do anything else.
 +
###<code> -f segment </code> (output format) '''DONT CHANGE''' Use a "chunked" output
 +
###<code> -segment_list out.list </code> (segment file) Defines a file containing the produced files names
 +
###<code> -segment_list_flags +live </code> (segment file flags) Defines the way the output file caches files names.
 +
###<code> -segment_list_size 5 </code> (segment file size)
 +
###<code> -segment_time 4 </code> (segment time) Defines the capture base duration in seconds. Tweak.
 +
###<code> -segment_time_delta 3 </code> (segment time delta) Defines a window to modulate chunks duration in seconds to include mandatory inline headers. Tweak.
 +
###<code> %10d.ts </code> The format for chunks files names. %10d will start at 0000000000.ts and ffmpeg understand we want MPEGTS format for chunks
 +
# ffmpeg saves the files 0000.ts, 0001.ts, etc. and out.list in /tmp/capture
  
 
'''C.''' Run rsync to server in a screen
 
'''C.''' Run rsync to server in a screen
Line 65: Line 102:
  
 
This requires  
 
This requires  
# a PHP streamer for your incoming files : http://pastebin.com/3f5t9vDS
+
# a PHP streamer for your incoming files : <code>http://pastebin.com/3f5t9vDS</code>
# the oggfwd command line tool
+
# the oggfwd command line tool: <code>aptitude install oggfwd</code>
  
     <code > php /usr/local/bin/stream.php | ffmpeg -i - -f ogg - | oggfwd -p -n "Test" stream.server.com 8000 mySecretIceCastStreamingPassword /test </code>
+
     <code> php /usr/local/bin/stream.php | ffmpeg -i - -f ogg - | oggfwd -p -n "Test" stream.server.com 8000 mySecretIceCastStreamingPassword /test </code>
  
 
== Solution 2 : FLVSTR + PHP Streamer ==
 
== Solution 2 : FLVSTR + PHP Streamer ==

Revision as of 18:19, 16 January 2015

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

  1.  Use the PI to capture video as h264, merge audio from usb and use ffmpeg to produce MPEGTS "chunks"
  2. Rsync the chunks to a laptop or a server (note : the audio mix can be done on the laptop)
  3. Assemble the chunks and pipe them in ffmpeg
  4. Ask ffmpeg to convert this into ogg
  5. Use oggfwd to push the ogg to your icecast server
  6. 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.

Sources

http://sirlagz.net/2013/01/07/how-to-stream-a-webcam-from-the-raspberry-pi-part-3/


POC

A. Compile FFMPEG on pi & server (see below)

B. Start capture in a screen

   # [ -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

  1. We create a /tmp/capture folder and make sure it's empty when starting capture
  2. Raspivid starts capturing with following parameters
    1.  -ih (inline headers) DONT CHANGE Necessary for technical reasons, as otherwise the "chunking" doesn't work
    2.  -t 0 (timeout) DONT CHANGE Necessary for technical reasons, as otherwise capture stops after 5s
    3.  -w 1080 -h 720 (height) and (width) Tweak according to your needs
    4.  -b 1000000 (bitrate) Tweak according to your needs (only integer numbers in bits are accepted, here <=> 1Mb)
    5.  -pf baseline (h264 profile) Tweak according to your needs ( only baseline, main, or high accepted)
    6.  -o - (output) DONT CHANGE Necessary in order to use the flux as Standard Output
  3. We pipe the content into ffmpeg
    1. ALSA Input
      1.  -f alsa  (format) We use alsa for usb audio capture
      2.  -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.
      3.  -ac 1  (number of audio channels) We used a mono input, so 1 was the right choice. Tweak
      4. -i hw:1  (input) Tweak as your audio card adress may vary. Find more with arecord -l
      5. -acodec aac (audio codec) AAC works well for TS live.
      6.  -strict -2  Argument mandatory for AAC format
    2.  Video Input
      1.  -i -  (input) DONT CHANGE Use the Standard input
      2. -vcodec copy (video codec) DONT CHANGE Use the video codec from the RPi. Not enough CPU to do anything else.
      3. -f segment (output format) DONT CHANGE Use a "chunked" output
      4. -segment_list out.list (segment file) Defines a file containing the produced files names
      5. -segment_list_flags +live (segment file flags) Defines the way the output file caches files names.
      6. -segment_list_size 5 (segment file size)
      7. -segment_time 4 (segment time) Defines the capture base duration in seconds. Tweak.
      8. -segment_time_delta 3 (segment time delta) Defines a window to modulate chunks duration in seconds to include mandatory inline headers. Tweak.
      9.  %10d.ts The format for chunks files names. %10d will start at 0000000000.ts and ffmpeg understand we want MPEGTS format for chunks
  4.  ffmpeg saves the files 0000.ts, 0001.ts, etc. and out.list in /tmp/capture

C. Run rsync to server in a screen

    while true; do rsync -a /tmp/capture user@server:/tmp/; sleep 1; done

D. Broadcast from server to icecast

This requires

  1.  a PHP streamer for your incoming files : http://pastebin.com/3f5t9vDS
  2.  the oggfwd command line tool: aptitude install oggfwd
    php /usr/local/bin/stream.php | ffmpeg -i - -f ogg - | oggfwd -p -n "Test" stream.server.com 8000 mySecretIceCastStreamingPassword /test 

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://raspberrypi.stackexchange.com/questions/23182/how-to-stream-video-from-raspberry-pi-camera-and-watch-it-live

http://ffmpeg.gusari.org/viewtopic.php?f=16&t=1130

http://blog.tkjelectronics.dk/2013/06/how-to-stream-video-and-audio-from-a-raspberry-pi-with-no-latency/

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