Nginx with m4a/aac/mp4 seek support on CentOS 5

I was working on Sikh Sangeet website which serves a lot of static audio media files. For the past couple of months, we’ve been paying overage (i.e. bandwidth charges for surpassing limits). I either had the option of paying much more (hundreds) for a better server or keep paying the overage charges (usually less than a hundred). So, I wanted to convert all the listening audio to a smaller format, such that I could provide full quality mp3s for downloading and provide smaller format audio for listening. I ended up choosing H264’s aac-HE, because it is supported in flash, android and iphone.

Previously on our dedicated Sikh Sangeet server, I ran nginx because the server was very limited with hardware, yet needed to serve the huge files that were mp3s. I had the latest nginx rpm (0.6.39-5.el5) from epel setup, but to get mp4 support, I had to install nginx from source with mp4 support.

I will reproduce the steps in the hopes that if I or anybody needs to do this in the future, they can get a quick idea:

Install nero encoders (best encoders for aac).
Convert mp3 to wav: mplayer -vc null -vo null "orig_file.mp3" -ao pcm:fast:file="/tmp/out.wav"
Convert wav to aac/m4a: neroAacEnc -br 56000 -if /tmp/out.wav -of "new_file.m4a"
Tag the m4a file with proper info: neroAacTag "new_file.m4a" -meta:title="title" -meta:artist="artist" -meta:track="track" -meta:album="album" -meta:genre="genre"

Now we have a m4a (aac) file, but this file is still not interleaved like an mp4 should be for nginx to stream parts of it. We must now convert the m4a (aac) file to mp4.

Install MP4Box (best way to convert regular audio into mp4 containers).
Convert m4a to mp4: MP4Box -add new_file.m4a:sbr final_file.mp4

Now we have our audio part ready. Now we just need to setup nginx:
Use the compile/make instructions from the original creators of the mp4 streaming module for nginx.

Notes:

  • If using the latest nginx server, the configure statement will not work. For two reasons:
    1. The nginx source requires pcre, even if you have pcre and pcre-dev(el) packages installed. For some reason nginx ./configure wasn't picking them up, so I downloaded pcre from pcre ftp. And without running make/configure or anything on it, used the following ./configure statement for nginx: ./configure --add-module=$HOME/nginx_mod_h264_streaming-2.2.7 --sbin-path=/usr/local/sbin --with-debug --with-pcre=$HOME/pcre-8.10
    2. The nginx_mod_h264_streaming-2.2.7 module has an incompatibility with the latest nginx (confirmed with 0.8.53):
      nginx_mod_h264_streaming-2.2.7/src/ngx_http_streaming_module.c:158: error: ângx_http_request_tâ has no member named âzero_in_uriâ.
      So, you must patch the ngx_http_streaming_module.c file using this patch.
  • For Red Hat/CentOS/Fedora users: If you want to use service nginx start/stop/reload/etc, download this Nginx Init Script.

Once you have nginx ready serving regular files from your document root (public_html, www, etc). Then simply put this directive inside the server context:

location ~ \.mp4$ {
root /your/document/root/full/path/here;
mp4;
}

The mp4 line will take care of the final_file.mp4?start=25 variable (i.e. start at 25 seconds) that flash players send to the server and cut off the mp4 at the right place.