Live Streaming, updated

HTTP Live Streaming and Streaming Server

Apr. 2012.

I wan't to stream live events and support this selection of browsers:

  1. Safari on iPad, iPod and Mac OS
  2. Firefox and Chrome on Windows and Linux platforms

Safari is supported through HTTP Live Streaming, HLS. Firefox and Chrome are supported through WebM files served by the streaming server ffserver. In both cases the video is embedded in the browser using HTML5 video tags.

Video is recorded using a DV camera connected to a Linux computer. Video is stored temporarily in a fifo-file on the Linux computer in an mpegts container with x264 video and mp3 audio. Video is stored temporarily until video is moved to an Amazon EC2 Server. We server the video from Amazon to get the right outgoing bandwidth. We use an Amazon Machine Image called Amazon Linux AMI, ami-db65bab2.

A segmenter reads the fifo-file as it is written and sends 10 sec. video segment files and video segment index to an Amazon EC2 server running Apache. Next to the video segment index and the video segments on the Apache server we have an index.html file with HTML5 video tag pointing to the video segment index file. With this setup Safari users on iPad, iPod and Mac OS are able to view the live video event browsing to the index.html file.

The Amazon EC2 server also runs ffserver serving a single WebM video stream. The feed for ffserver comes from an instance of ffmpeg running on the same host. Input for ffmpeg comes from the HLS available on the same host. The index.html is expanded to include yet another HTML5 video tag that points to the WebM stream served by ffserver. With this setup Firefox and Chrome users on Windows and Linux platforms are able to view the live video event browsing to the index.html file.

Segmenter

See link below for details about the segmenter and how to compile the segmenter.

I had to modify hs_transfer.rb so video segment index is sent after video segment. Otherwise, video segment index might refer to not yet fully transferred video segment file and playback in browser suffers.

The segmenter reads from a fifo-file, /tmp/live.fifo. Start segmenter from the directory where the compiled segmenter is located.

The configuration file I use is based on the standard configuration file example-configs/config-recommended-ipad-16x9-multirate.yml where I only use the encoding profile 'cell_16x9_440k'. Furthermore, I changed the frame rate on the corresponding ffmpeg command from 30 to 25 to fit the frame rate of the DV camera.

The segmenter will use scp to copy video segment files to Amazon EC2 server so we have to copy the KEYPAIR (private key) file to ~/.ssh/id_rsa. Otherwise, the segmenter will fail to copy the files to Amazon EC2 server.

Commands

I run the following commands on a Lenovo T420 laptop and I use a JVC low budget DV camera. Becuase I copied the KEYPAIR (private key) file to ~/.ssh/id_rsa I can call ssh and scp without specifying identity file.

Open terminal window.

Start Amazon EC2 Server (remember that KEYPAIR is name of keypair and NOT the filename of the keypair!):

  • ec2-run-instances --key KEYPAIR ami-db65bab2

From here we assume the name of newly created Amazon EC2 Server is ec2.amazonaws.com.

Login to Amazon EC2 Server, create setupAmazonLinuxAMI.sh, execute setupAmazonLinuxAMI.sh, and logout

  • ssh ec2-user@ec2.amazonaws.com
  • nano ./setupAmazonLinuxAMI.sh
  • Get text for setupAmazonLinuxAMI.sh from listing below. Save file and exit nano.
  • bash ./setupAmazonLinuxAMI.sh
  • exit

Note how script setupAmazonLinuxAMI.sh created the file public_html/index.html on the Amazon EC2 server. If running on IBM SCE then correct the public server name in the file index.html. Furthermore, note how setupAmazonLinuxAMI.sh created the configuration file for ffserver that we will start later!

First make the fifo-file that the segmenter reads from and then start the segmenter. Remember to update the segmenters config file to reflect the newly created Amazon EC2 Server. In my case the segmenter copies files to Amazon EC2 server using scp so I have to update the remote_host variable of the scp_dev section in the segmenters config file config-recommended-ipad-16x9-multirate.tps01.yml.

  • mkfifo /tmp/live.fifo
  • ./http_streamer.rb config-recommended-ipad-16x9-multirate.tps01.yml

Open new terminal window:

Start video recording and send video to the fifo-file (note how the segmenter in the first terminal window starts ffmpeg coding and sends coded files to Amazon EC2 Server):

  • dvgrab -format dv1 - | ffmpeg -y -f dv -i - -f mpegts -vcodec libx264 -preset veryfast /tmp/live.fifo

Now, we can watch live video on iPad and iPhone by going to http://ec2.amazonaws.com/~ec2-user.

Open new terminal window:

Start ffserver on Amazon EC2 Server.

Open new terminal window:

Start ffmpeg on Amazon EC2 Server so we send video to the feed of the ffserver we started previously:

Now, we can watch live video in FireFox and Chrome on Windows and Linux platforms by going to http://ec2.amazonaws.com/~ec2-user.

We now have four terminal windows:

  1. segmenter reading from fifo-file and sending video index and video segments to Amazon EC2 Server
  2. dvgrab reading from DV camera, pipe to ffmpeg which reformats and writes to fifo-file
  3. ffserver running on Amazon EC2 Server serving WebM video
  4. ffmpeg running on Amazon EC2 Server sending video to ffserver feed

EC2 Instance Setup, setupAmazonLinuxAMI.sh

#!/bin/bash -ex

# Install Apache web server
sudo yum -y install httpd.i686

# User Apache module userdir_mod and put users Apache files in ~username
sudo sed -i 's/UserDir disable/#UserDir disable/g' /etc/httpd/conf/httpd.conf
sudo sed -i 's/#UserDir public_html/UserDir public_html/g' /etc/httpd/conf/httpd.conf

# Start web server
sudo /etc/init.d/httpd start

# Make directory for users Apache files and let Apache find files
mkdir ~/public_html
chmod 711 ~/

# Bulld ffmpeg on this CentOS - see http://ffmpeg.org/trac/ffmpeg/wiki/CentosCompilationGuide
sudo yum -y install gcc git make nasm
mkdir ~/ffmpeg-source
cd ~/ffmpeg-source
wget http://www.tortall.net/projects/yasm/releases/yasm-1.2.0.tar.gz
tar xzvf yasm-1.2.0.tar.gz
cd yasm-1.2.0
./configure
make
sudo make install

cd ~/ffmpeg-source
git clone git://git.videolan.org/x264
cd x264
./configure --enable-static --disable-opencl
make
sudo make install

cd ~/ffmpeg-source
wget http://downloads.sourceforge.net/project/lame/lame/3.99/lame-3.99.5.tar.gz
tar xzvf lame-3.99.5.tar.gz
cd lame-3.99.5
./configure --disable-shared --enable-nasm
make
sudo make install

cd ~/ffmpeg-source
git clone http://git.chromium.org/webm/libvpx.git
cd libvpx
./configure
make
sudo make install

cd ~/ffmpeg-source
wget http://downloads.xiph.org/releases/ogg/libogg-1.3.0.tar.gz
tar xzvf libogg-1.3.0.tar.gz
cd libogg-1.3.0
./configure --disable-shared
make
sudo make install

cd ~/ffmpeg-source
wget http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.3.tar.gz
tar xzvf libvorbis-1.3.3.tar.gz
cd libvorbis-1.3.3
./configure --disable-shared
make
sudo make install

cd ~/ffmpeg-source
git clone git://source.ffmpeg.org/ffmpeg
cd ffmpeg
./configure --enable-gpl --enable-libmp3lame --enable-libvpx --enable-libx264 --enable-version3 --enable-libvorbis
make
sudo make install

# Create index.html that serves video. Dynamically insert public hostname of newly created Amazon EC2 Server.
# If video is served out of IBM SCE then manually adjust public name of server.
cd ~/public_html
cat > index.html <<DELIM1
<video controls>
<source src="stream_multi.m3u8" type='video/mp4; codecs="avc.42E01E, mp4a.40.2"'/>
<source src="`curl http://169.254.169.254/latest/meta-data/public-hostname`:8090/live.webm" type='video/webm; codecs="vp8, vorbis"' />
Sorry, your browser does not support HTML5. You will not be able to view the video.
</video>
DELIM1

# Create ffserver configuration file.
cd ~
cat > ffserver.conf.webm <<DELIM2
Port 8090
BindAddress 0.0.0.0
MaxHTTPConnections 2000
MaxClients 1000
MaxBandwidth 1000000
CustomLog -
NoDaemon

<Feed feed1.ffm>
File /tmp/feed1.ffm
FileMaxSize 1G
ACL allow 127.0.0.1
</Feed>

<Stream live.webm>
Feed feed1.ffm
Format webm
AudioBitRate 64
AudioSampleRate 48000
AudioChannels 1
VideoCodec libvpx
VideoSize 320x160
VideoFrameRate 25
AVOptionVideo flags +global_header
AVOptionAudio flags +global_header
PreRoll 15
StartSendOnKey
VideoBitRate 400
</Stream>

<Stream stat.html>
Format status
# Only allow local people to get the status
ACL allow localhost
ACL allow 192.168.0.0 192.168.255.255
</Stream>
# Redirect index.html to the appropriate site
<Redirect index.html>
URL http://www.ffmpeg.org/
</Redirect>
DELIM2

Links

segmenter and compile information
http://www.ioncannon.net/projects/http-live-video-stream-segmenter-and-d...
https://github.com/carsonmcdonald/HTTP-Live-Video-Stream-Segmenter-and-D...

Amazon EC2 server, compile ffmpeg
http://aws.amazon.com/amazon-linux-ami/
http://docs.amazonwebservices.com/AWSEC2/2011-05-15/UserGuide/index.html...
http://ffmpeg.org/trac/ffmpeg/wiki/CentosCompilationGuide

Thanks

Thomas S

Comments

IBM SmartCloud Enterprise, SCE

With a few minor adjustments the procedure above works with IBM SCE:

  1. Use SME image Red Hat Enterprise Linux 5.8 (32-bit)
  2. The user account on the instance is now idcuser and not ec2-user
  3. Script setupAmazonLinuxAMI.sh has to be adjusted:
    - Apache web server package is httpd and not httpd.i686
    - Install git from another respository:
    - sudo rpm -ivh http://mirror.chpc.utah.edu/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm
    - sudo yum -y install git
  4. Open ports 80 and 8090 on the instance - http://www.ibm.com/developerworks/cloud/library/cl-cloudstart.html
  5. Disable SELINUX so Apache will serve files under /home/idcuser/public_html. Run this command on the instance: `sudo /usr/sbin/setenforce 0`

Thanks Thomas S

Setup Environment Up Again

I just reinstalled the pc on which I am running the live streaming and it took me a couple of hours to get the pc back to a working state. Here are some of the notes I made:

Update to Ubuntu 12.04
Download and compile my own version of ffmpeg on the Ubuntu host. Use this configuration: --enable-gpl --enable-libmp3lame --enable-libvpx --enable-libx264 --enable-version3 --enable-libvorbis
If configure fails due to missing library then get library from Ubuntu Software Center, ie. libx264-dev.
Before running the command ./http_streamer.rb config-recommended-ipad-16x9-multirate.tps01.yml I set these variables in config-recommended-ipad-16x9-multirate.tps01.yml:
- input_location: '/tmp/live.fifo'
- encoding_profile: [ 'wifi_16x9_640k' ]
- transfer_profile: 'scp_dev'
- ffmpeg_command: Use the ffmpeg I just compiled
- remote_host: '170.225.99.72'
- user_name: 'idcuser'
- directory: 'public_html'

Misc.

Grap from firewire using ffmpeg libiec61883 and not dvgrab:

ffmpeg -y -f iec61883 -i auto -f mp4 -vcodec libx264 -acodec aac -strict experimental test.mp4

Get format of what was recorded. Note, here you can also see the configuration that was used when compiling ffmpgeg:

ffmpeg -i test.mp4
ffmpeg version N-44959-ge97e0ef Copyright (c) 2000-2012 the FFmpeg developers
built on Oct 26 2012 14:39:12 with gcc 4.6 (Ubuntu/Linaro 4.6.3-1ubuntu5)
configuration: --enable-gpl --enable-libmp3lame --enable-libvpx --enable-libx264 --enable-version3 --enable-libvorbis --enable-libiec61883
libavutil 51. 73.101 / 51. 73.101
libavcodec 54. 62.100 / 54. 62.100
libavformat 54. 29.105 / 54. 29.105
libavdevice 54. 3.100 / 54. 3.100
libavfilter 3. 19.102 / 3. 19.102
libswscale 2. 1.101 / 2. 1.101
libswresample 0. 16.100 / 0. 16.100
libpostproc 52. 1.100 / 52. 1.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'test.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf54.29.105
Duration: 00:01:16.88, start: 0.032000, bitrate: 1561 kb/s
Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 720x576 [SAR 64:45 DAR 16:9], 1432 kb/s, 25 fps, 25 tbr, 25 tbn, 50 tbc
Metadata:
handler_name : VideoHandler
Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 32000 Hz, stereo, s16, 122 kb/s
Metadata:
handler_name : SoundHandler
At least one output file must be specified

Record from video camera and apply scoreboard video filter:

../ffmpeg/ffmpeg -y -f iec61883 -i auto -f mp4 -vcodec libx264 -acodec aac -strict experimental -filter:v scoreboard=bitmapdir=bitmaps:gameclockinput=nautronic.log:gameclockoutput=file2:gameclockvideo=file3 -b:v 1000k test.mp4