Sunday, February 10, 2013

HTML5 video live streaming with ffmpeg and mediaelement.js, Round 1

In the era of HD home-videos on YouTube, our current delivery method for online classes in low quality Flash videos is getting kinda unacceptable, especially for maths-type subjects, where it would be nice to actually all those numbers and figures on the whiteboard.
So, enter HTML5 video, H.264, mpeg4 and possibly a new encoding server... Our main problem is that we want to print some custom stuff on the videos, so we need to encode them in realtime.

The player of choice is mediaelement.js, because it comes with the promise on the tin that it just works. Just how we like it.
So, after checking out the samples, the player code looks like this:

<video controls="controls" height="360" id="player2" width="480">
  <source src="relay_video.php?quality=0&id=1469&format=mp4" title="mp4" type="video/mp4"></source>
  <source src="relay_video.php?quality=0&id=1469&format=ogg" title="ogg" type="video/ogg"></source>
  <source src="relay_video.php?quality=0&id=1469&format=wmv" title="wmv" type="video/wmv"></source>
    <object data="flashmediaelement.swf" height="360" type="application/x-shockwave-flash" width="480">
        <param name="movie" value="flashmediaelement.swf" />
        <param name="flashvars" value="controls=true&file=relay_video.php?quality=0&id=1469&format=flv" />
        <!-- Image as a last resort -->
        <img src="noflash.jpg" width="480" height="360" title="No video playback capabilities" />

So far so good, let's give it some video files. Transcoding happens on-the-fly either with mencoder or ffmpeg. As we prefer ffmpeg, let's try to do everything with that.
Large parts are from John's ffmpeg post here:

Problem 1: we don't have libvpx support compiled in; for the time we'll try to live without it.
Problem 2: old IE versions. They should at least have native support for WMV, either with Silverstripe or otherwise. FFmpeg supports WMV, so this might actually work.
Problem 3: This is a hard one: ffmpeg can't mux into mp4 on a non-seekable output (ie. socket). Wikipedia tells me that WebM is actually based on Matroska. FFmpeg loves Matroska, we can do this.

So, our current format - container - vcodec - acodec groups are as follows:
mp4 - matroska - libx264 - libfaac
ogg - ogg - libtheora - libvorbis
wmv - asf - wmv2 - wmav2
flv - flv - flv - libmp3lame

And: it works so far! The Mozilla guys are open source believers, so Firefox automatically selects ogg. Chromium uses mp4, or in absence of that, falls back to ogg. A few things to try: iPhones might possibly not like the Matroska container, but supposedly they can do mpegts. Problem with that is that Chromium does not work with that, but doesn't fall back to ogg either.
So for that, I'll try:
mp4 - mpegts - libx264 - libfaac
webm - matroska - libx264 - libfaac

Other problems might arise while finding ancient IE version to test with, and maybe on OS X. If I find more out, there'll be a round 2 of this post.

1 comment:

  1. Thank you for this great post.

    I' trying to do exactly the same thing, especialy the on-the-fly transcode part. So I am wondering how do you manage to make it work trough php. Could you show us the content of your relay_video.php file ?

    Thanks a lot !