This article will show you we use the Nginx mp4 streaming module and the Ranger module to help you deliver on-demand video files faster.
Nginx MP4 Streaming Module
Nginx provides pseudo streaming (HTTP Streaming) with the mp4 streaming module. The module itself is designed to provide crucial functions so that video content can be properly streamed out to the end-user. The scope of the files usually satisfies any mp4 format and/or FLV, meaning that mp4, m4v, m4a, and FLV files can be streamed out.
When performing the streaming, the supported player sends a request for metadata of the file to be streamed to the end-user. This is usually done by sending a query string of ?start=0 and thus fetching headers from the streaming server. Emphasis should be put on the fact that this is performance-effective because the player will ask for the first byte of data and get all metadata needed for playback. However, some encoding apps will put metadata at the end of the file which will affect the performance of playback. This is because the player has to download the entire file before playback starts.
After sending a request for metadata, the next step is to send a request for the file to the server with query string noting the start and end positions. This gives the range of video content for the server to prepare for streaming. Both start and end are not needed but the range itself will dictate to the Nginx mp4 streaming module what time range the end-user requested, and thus, UX improves significantly. If there is no end, Nginx will simply deliver the file as static content. Some players are starting to support range requests in the form of request header (Range: bytes=x-y).
Range Requests & the Ranger Module
The scenario above assumes Nginx has the requested file in its cache so it can easily partition it for streaming. But what happens if the file is not in the Nginx cache? The correct answer is that “Nginx will fetch the file from the backend server (origin) and then perform the streaming.” This is true but very user-affecting because if the file is too large (few dozens MBs up to few GBs), the player will have to wait for Nginx to download this file (which in this size is too much) and then wait for the stream to start.
We have remedied this issue by introducing the Ranger module that is performing range requests from the backend server (origin) and pulling the file in chunks of 5MBs so that streaming can start immediately. Ranger is pulling ranges from the origin through the Nginx cache so that when Ranger is in this scenario, the end-user actually communicates with Ranger which then fetches ranges from the origin through our cache or serves the range from the Nginx cache.
Important: Even if the range request comes in from the player but the file is not cached, we will perform range requests from the origin and fetch only the 5MB chunk of the file to prepare it for streaming. If the range overlays through two 5MB chunks, we will fetch both chunks at the same time (10MB) so that streaming can start on demand. This functionality is enabled by default when you turn on the pseudo streaming option in Zone Settings under Edge Settings in the MaxCDN Control Panel.
Example Nginx Configuration Block
location ~ /maxcdnrange(/.*) {
internal;
keepalive_timeout 4;
set $zone_id 123456;
set $company_id 0000;
set $zone_name myzone;
set $company_alias mycompany;
set $origin domain.com;
set $originscheme $scheme;
# PASSING HOST HEADER FOR EDGE RULE
set $block_size 10485760;
set $fcttl 86400;
set $ignore_querystring 0;
lua_code_cache on;
lua_check_client_abort on;
set $ranger_cache_status $upstream_cache_status;
lua_http10_buffering off;
content_by_lua_file 'lua/ranger/content.lua';
}
location ~ /maxcdnrangeproxy(/.*) {
internal;
if ($http_range) {
set $var_arg_range $http_range;
}
if ($arg_range) {
set $var_arg_range "bytes=$arg_range";
}
postpone_output 0;
proxy_pass http://127.0.0.1:8079$1?$args;
proxy_set_header If-Range "";
proxy_set_header Host myzone.mycompany.netdna-cdn.com;
proxy_set_header Range $var_arg_range;
proxy_set_header Accept-Encoding "";
proxy_buffer_size 20m;
proxy_buffers 24 20m;
}
location ~* \.flv$ {
rewrite ^(.*)$ /maxcdnrange$1 last;
}
location ~* \.(mp4|m4a|m4v|mov)$ {
keepalive_timeout 0;
set $pseudo 0;
if ($args ~* "start=") {
set $pseudo 1;
}
if ($args ~* "end=") {
set $pseudo 1;
}
if ($pseudo = 0) {
rewrite ^(.*)$ /maxcdnrange$1 last;
}
mp4 subrequest;
mp4_buffer_size 5m;
mp4_max_buffer_size 20m;
mp4_subrequest_path maxcdnrangeproxy;
}
Pseudo Streaming Scheme
- Player requests range from Nginx
- Ranger allocates blocks of 5MB under which the requested range resides
- Ranger requests it from Nginx cache
- The cache is MISS and Nginx passes range request to the origin
- Origin returns requested range
- MaxCDN retrieves the range and passes it to mp4 streaming module
Notes
- For custom use in your own environment, you should know that the mp4 module is not built-in by default. You should compile Nginx with --with-http_mp4_module.
- For ranger to take effect when contacting the origin with a range request, it’s mandatory that the origin supports range requests as well. You can test this by running the following command towards the origin file. If the origin supports range requests you’ll see a 206 status code. Here is the command:
curl -I http://origin.com/file.ext -H ‘Range: bytes=0-10’
If you want to learn more about pseudo streaming or Ranger, check out this blog post on caching range requests using Nginx at MaxCDN, this MaxCDN pseudo streaming example, and this MaxCDN pseudo streaming announcement.
If you have any questions or experience any issues, please reach out to the Support Team, live chat and ticket support are available 24/7.