0 comments

WARNING: This post is long and pretty technical and probably quite boring if streaming video isn’t your thing. It’s mostly meant as a reminder to myself as to how I got this working :-)

I’ve always been kind of keen on streaming video, webcams and so on and have for some time tried to work out the best way of delivering a live/almost live video feed to my iPhone (for free that is).

Last night I finally got a breakthrough while searching the web for possibilities. I had for some time had a pure HTML5 stream running using Theora/OGG encoded with VLC, but this was only viewable with Google Chrome.

HTTP Live Streaming is basically a trick used by Apple and a few others to deliver video content over anything from 3G to WI-FI connections. It works by splitting a video into small chunks and then downloading them one by one to the client which then puts them back together. To know which bits to download, the protocol makes use of an index file which is really just a list of URLs. All this is pretty easy with static content – just transcode your video into the correct format (H264 in an MPEG2 container) and chop it up. Then provide an index file (.m3u8) and point your device at it. There is software out there that can do this for you.

But for live video there’s a challenge. First of all, there is no set length of the video – it just goes on and on. So what most of the HTTP Live Streaming software out there does is that it stores the video feed in chunks, just like with a static video, and then dynamically updates the index file to point to the last say 5 chunks. The client continuously downloads the index file, so it always knows the name of the chunk to download and play next. The main drawback of this method is that the content the client sees is not really live, but instead has a latency of <chunk size * number of chunks> – usually about 60 seconds.

However, if you can live with this (and I think most people can if it’s just for fun) here’s how to set it up using the latest VLC Nightly Build which contains the httplive module. To get this to work, you must be running a web server on the same machine as your webcam.

  • First of all, download and install the latest VLC Nightly
  • Next, create a directory somewhere in your web root, where you want the video to reside. I chose c:\inetpub\wwwroot\live
  • Next up is to figure out the right options with which to launch VLC. It turns out that quite a few are needed; my commandline looks like this:

    "C:\Program Files (x86)\VideoLAN\VLC\vlc.exe" dshow:// --sout=#transcode{vcodec=h264,vb=512,scale=1,acodec=none,sfilter=marq{marquee="[%%d-%%m-%%Y %%H:%%M:%%S]",position=8,size=18},venc=x264{aud,profile=baseline,level=30,keyint=15,
    bframes=0,ref=1,nocabac}}:duplicate{dst=std{access=livehttp{seglen=10,delsegs=true,numsegs=5,
    index=c:/inetpub/wwwroot/live/mystream.m3u8,index-url=http://homeserver.local/live/mystream-########.ts},mux=ts{use-key-frames},dst=c:/inetpub/wwwroot/live/mystream-########.ts},dst=std{access=http,mux=ts,dst=:8090/video.mp4}}

    Take note of the paths and URLs in there – they have to be correct. Here’s a description of what’s going on:
    • The first part is just the path to the VLC executable.
    • dshow:// tells VLC to take the first available DirectShow device (my webcam).
    • --sout=sets up the default output chain. What follows is a chain of setup options that describe the output.
      • #transcode{ we want to transcode the input (from the webcam) to one or more different formats
      • vcodec=h264use the h.264 codec for output
      • vb=512 use a video bitrate of 512kb/s
      • scale=1 don’t scale the video – output the same size as the input
      • acodec=none I don’t want audio in this video so I explicitly unset the Audio Codec.
      • sfilter=marq{marquee="[%%d-%%m-%%Y %%H:%%M:%%S]",position=8,size=18}filter that adds the current time and date to the video stream.
      • venc=x264{aud,profile=baseline,level=30,keyint=15,
        bframes=0,ref=1,nocabac}
        Sets up the video encoding profile for the h.264 stream. This is to ensure that the iPhone can display the stream.
      • } ends the transcode section.
    • :duplicate{ Tell VLC that we want to chain multiple outputs. In this case I want 2 – one for HTTP Live Streaming and also a regular HTTP MP4/h.264 stream for viewing with VLC.
    • dst=std{access=livehttp{seglen=10,delsegs=true,numsegs=5,
      index=c:/inetpub/wwwroot/live/mystream.m3u8,index-url=http://homeserver.local/live/mystream-########.ts},mux=ts{use-key-frames},dst=c:/inetpub/wwwroot/live/mystream-########.ts

      This is quite a mouthful. I’ll split this one up by itself:
      • access=livehttp Set up the livehttp stream
      • seglen=10The length of each segment, in seconds
      • delsegs=true Delete segments that have rolled out of scope
      • numsegs=5 The number of segments to have queued up
      • index=c:/inetpub/wwwroot/live/mystream.m3u8 This is the path to where the index file will be located. It has to be in the web-accessible directory we set up earlier.
      • index-url=http://homeserver.local/live/mystream-########.ts This is the URL to the file fragments that will be embedded in the index file. The hash-characters have to be there – they are placeholders for the always-incrementing index file numbers.
      • mux=ts{use-key-frames} Set up the multiplexer and tell it to embed the key frames we set up in the video encoding profile earlier
      • dst=c:/inetpub/wwwroot/live/mystream-########.ts Finally, this is the file name template for the stream segments.
    • The last dst= part in the command line is just to set up the alternative H.264/MPEG4 stream that can be viewed using VLC from a PC.
  • Now that we have the command line set up, there is one more thing to be aware of. When running under Windows, the livehttp module won’t be able to automatically overwrite the index file every time a new segment is written to disk. To overcome this, it instead writes the new index file to a temporary file in the same directory. What I then did was to create a small PowerShell script that could copy the temp file over the index file at an interval shorter than the segment length.
    This is done in 4 lines of code. I placed the file in the output directory and named it rename.ps1:
    while ($true) {
        Copy-Item mystream.m3u8.tmp mystream.m3u8
        Start-Sleep -s 2
    }
  • Next up we have to configure the web server to spit out the correct MIME type when serving the .m3u8 and the .ts files, so that the client device knows what’s coming. I added the following two MIME mappings in my IIS:
    .m3u8  application/x-mpegURL
    .ts    video/MP2T
  • Now you’re just about ready to start serving video. All you have to do is set up an HTML5 page on a web server that you can access from your iPhone: 
    <!DOCTYPE html>
    <html>
    <head>
        <title>Live Cam</title>
    </head>
    <body>
        <div id="player">
            <video autoplay="true" controls="controls" width="640" height="480">
                <source src="http://homeserver.local/live/mystream.m3u8" />
                Your browser does not support HTML5 streaming!
            </video>
        </div>
    </body>
    </html>
  • What I did locally on my server was to set up a small .cmd file that could start the stream and file copier all at once. 
    @echo off
    start "" "c:\program files (x86\VideoLan\VLC\vlc.exe” [use the command line from above]
    
    echo Running rename script... do NOT close this window!
    powershell c:\inetpub\wwwroot\live\rename.ps1

That should be all there is to it! If you get any interesting streams up and running, paste a link to them in the comment section below :-)

comments powered by Disqus