Wednesday, February 04, 2009

Apache FLV streaming done right!

After 2 days of researching, I've just found how to do FLV streaming the right way!
Let's wrap up current (I.2009) situation:

Why?
  • FLV is still very common container format for videos. h264 is more efficient but is supported by Flash since version 9.115
  • FLV streaming means you can seek to any position during video, and browser (flash player) will buffer only from this position to the end.
  • Streaming allows people to skip boring parts or see video ending without loading the whole file (saves bandwidth).
  • Lighttpd has FLV streaming built in.
  • Apache doesn't.
  • There is number of PHP and Perl scripts that allow to implement streaming. These work by loading the given flv file, and pushing it's content from given position to the end.
  • It's bloated! PHP uses memory, Apache PHP module uses memory, every single streaming connection is a running php script (try empty php file with just <?=memory_get_usage(true)?> )

Behind the scenes
  1. Flash player requests the file, starts loading i.e.: http://host/video.flv
  2. When user clicks any position on the "scrubber" (seek bar) player stops buffering and starts buffering from url: http://host/video.flv?start=1503320
  3. The parameter is byte count from where buffering should start.
  4. Server fetches the file, truncates it and rewrites FLV header.

Solution: flv streaming in apache:
  1. Download apache mod_flv module by Paul Querna or my tuned version.
  2. Install apxs tool (also avaliable in RPMs for most systems as httpd-devel)
  3. Compile and install your module with the following command:

    apxs -c -i ./mod_flvx.c

  4. Add the following 2 lines to your httpd.conf or create a dedicated /etc/httpd/conf.d/mod_flvx.conf (path depends on your distribution):

    LoadModule flvx_module modules/mod_flvx.so
    AddHandler flv-stream .flv

  5. Restart Apache (i.e. with service httpd restart)

Tuning:

  1. I've modified the module to fix content-length and add last-modified headers. I've also added a fix when offset is set to wrong position (i.e. past video length).
  2. You can download the tuned module here.

Things to remember:
  • To use flv streaming on the web, you need to use a pseudo-streaming compliant Flash player. Flowplayer does the job quite well.
  • Streaming requires that your FLV has embedded keyframe markers (meta-data). You can inject any FLV with this data using flvtool2:

    flvtool2 -U video.flv

  • Generated streams will work briliantly in Flash player, but you won't be able to play them back in standalone player (VLC, WMP etc.). So don't be suprised when you "wget" a video with ?start=1000 and the file doesn't play. That is because they don't have starting meta-data and players will have hard time deciding which codec to use.

Have fuN!