Tuesday, July 11, 2017

Introducing nginx-ts-module for HLS and MPEG-DASH live streaming

Today I'm announcing the first release 0.1.0 of nginx-ts-module. The module provides HLS and MPEG-DASH live streaming capabilities for those who want a lightweight solution based on the HTTP protocol. The stream is published in the MPEG-TS format over HTTP. This makes it possible to use all the power and flexibility of nginx HTTP configurations including SSL, access control, logging, request limiting etc. MPEG-TS is a widely adopted, well known and well documented streaming format.

Currently, the module supports three directives: ts, ts_hls, ts_dash. The first directive enables receiving the MPEG-TS stream. The following two directives enable generating HLS and MPEG-DASH files.

Example:

http {
    server {
        listen 8000;

        location /publish/ {
            # This directive sets unlimited request body size
            client_max_body_size 0;

            ts;
            ts_hls path=/var/media/hls segment=10s;
            ts_dash path=/var/media/dash segment=10s;
        }

        location /play/ {
            types {
                application/x-mpegURL m3u8;
                application/dash+xml mpd;        
                video/MP2T ts;
                video/mp4 mp4;
            }
            alias /var/media/;
        }
    }
}

To publish a stream, invoke ffmpeg like this:

$ ffmpeg -re -i ~/Movies/sintel.mp4 -bsf:v h264_mp4toannexb
         -c copy -f mpegts http://127.0.0.1:8000/publish/sintel

HLS can be played primarily in Safari and mobile devices using the following HTML:

<body>
  <video width="640" height="480" controls autoplay
         src="http://127.0.0.1:8000/play/hls/sintel/index.m3u8">
  </video>
</body>

MPEG-DASH is now supported on most browsers including Chrome, Firefox, Safari. To play the stream, the dash.js player can be used like this:

<script src="http://cdn.dashjs.org/latest/dash.all.min.js"></script>

<body>
  <video data-dashjs-player
         width="640" height="480" controls autoplay
         src="http://127.0.0.1:8000/play/dash/sintel/index.mpd">
  </video>
</body>

For more details refer to the README.rst file in the project root.

Monday, July 10, 2017

MPEG-DASH improvements in nginx-rtmp-module 1.2.0

In the previous versions of the module there's been a number of issues concerning the MPEG-DASH implementation. In the latest release of the module I've made a number of important fixes:

  • the nginx-rtmp-module now works successfully with the mainline dash.js player
  • the DASH manifest now successfully passes the validity tests
  • the DASH manifest file generation has been improved for smooth playback
Please check out the version 1.2.0 of nginx-rtmp-module.

Tuesday, September 9, 2014

HLS encryption in the rtmp module v1.1.5

The nginx-rtmp-module version 1.1.5 supports HLS encryption using AES-128 method. HLS fragments are encrypted so that they could be opened only with someone having HLS key files. The key files are auto-generated by the module and stored in a location specified in nginx.conf. They are supposed to be served securely using the https protocol only to authorised clients. To make this simpler those files can be stored in a location different from the default HLS location. It's possible to set how many HLS fragments are encrypted with a single key file.
http {
    server {
        listen 443 ssl;
        server_name example.com;

        ssl_certificate /var/ssl/example.com.pem;
        ssl_certificate_key /var/ssl/example.com.private;

        # Serve HLS keys securely here
        location /keys {
            root /tmp;
        }
    }

    server {
        listen 80;
        server_name example.com;

        # Serve HLS playlist/fragments here
        location /hls {
            root /tmp;
        }
    }
}

rtmp {
    server {
        listen 1935;

        hls on;
        hls_path /tmp/hls;

        # Use HLS encryption
        hls_keys on;

        # Store auto-generated keys in this location rather than hls_path
        hls_key_path /tmp/keys;

        # Prepend key url with this value
        hls_key_url https://example.com/keys/;

        # Change HLS key every 2 fragments
        hls_fragments_per_key 2;
    }
}
The following directives are added:
  • hls_keys on|off - Toggles HLS encryption using the AES-128 method. Current fragment number is used as an AES initialization vector.
  • hls_key_path - Directory where key files are stored. The default HLS directory (hls_path) is used by default.
  • hls_key_url - URL prefix to serve key files from a different location.
  • hls_fragments_per_key - The number of fragments encrypted with a single key. Zero (default) means a single auto-generated key file is used from the publish command till the stream end.
Here's an example m3u8 playlist generated by the above mentioned configuration.
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:16
#EXT-X-TARGETDURATION:10
#EXT-X-KEY:METHOD=AES-128,URI="https://example.com/keys/mystream-15.key",IV=0x0000000000000000000000000000000F
#EXTINF:10.010,
mystream-16.ts
#EXT-X-KEY:METHOD=AES-128,URI="https://example.com/keys/mystream-17.key",IV=0x00000000000000000000000000000011
#EXTINF:10.010,
mystream-17.ts
#EXTINF:10.010,
mystream-18.ts
#EXT-X-KEY:METHOD=AES-128,URI="https://example.com/keys/mystream-19.key",IV=0x00000000000000000000000000000013
#EXTINF:10.010,
mystream-19.ts
#EXTINF:9.759,
mystream-20.ts
#EXT-X-KEY:METHOD=AES-128,URI="https://example.com/keys/mystream-21.key",IV=0x00000000000000000000000000000015
#EXTINF:10.010,
mystream-21.ts

Thursday, April 3, 2014

Proxy Protocol support in nginx-rtmp-module 1.1.4

The new version of nginx-rtmp-module has proxy protocol support added. Proxy protocol lets you put nginx behind a TCP-proxy and still have real client address. Here's an example of nginx.conf setting a listener with proxy protocol enabled.
rtmp {
    server {
        listen 1935; # usual listener
        listen 1936 proxy_protocol; # handles proxy protocol
        
        application myapp {
            live on;
        }
    }
}
If proxy_protocol option is specified in listen directive, such listener expects proxy protocol header from its client before RTMP data and will not handle plain RTMP requests. The client address received via proxy protocol is used everywhere instead of the proxy address including logs and on_XXX callbacks.

Notable software having client-side proxy protocol support allowing you to proxy RTMP requests to nginx-rtmp-module:

Monday, January 13, 2014

RTMP play2 support in version 1.1.2

In nginx-rtmp-module version 1.1.2 play2() support is added. Some players use this call to switch to a different stream or bitrate.

Sunday, January 12, 2014

New exec_record_done variables

New variables are added to exec_record_done directive to make setting files and directories easier.
  • filename - file name portion of the path, directory omitted
  • dirname - directory path
  • basename - file name with file extension omitted

Assume path is /tmp/rec/mystream-1389499351.flv. Then filename is mystream-1389499351.flv, dirname is /tmp/rec, basename is mystream-1389499351.

Example of recording mp4 with proper file names.
application myapp {
  live on;
  record all;
  record_path /tmp/rec;
  record_unique on;
  record_interval 30s;
  exec_record_done ffmpeg -i $path -c copy /var/videos/$basename.mp4;
}
Wiki is updated as well.

Friday, January 10, 2014

Redirecting streams in version 1.1.1

In version 1.1.1 of nginx-rtmp-module stream redirect feature is added. Now you can change currently played or published stream in realtime through control request. The following call changes subscriber stream name to newname. The subscriber is found in myapp application by the IP address 127.0.0.1.
http://server.com/control/redirect/subscriber?app=myapp&addr=127.0.0.1
&newname=newname
The above example changes stream for a single client. To change it for all clients use pull and change its source end. You can pull certain streams from VOD applications as well.
application myapp {
  live on;
  hls on;
  hls_path /var/hls;
  pull rtmp://localhost/src/default name=myapp static;
}

application src {
  live on; 
  pull rtmp://localhost/vod/title.mp4 name=default;
  pull rtmp://localhost/vod/ad.mp4 name=ad;
}

application vod {
  play /var/videos;
}
The myapp stream starts with title.mp4. Now switch to cam1 (which should be published to src application)
http://server.com/control/redirect/subscriber?app=src&addr=127.0.0.1
&newname=cam1
Now show ad.mp4
http://server.com/control/redirect/subscriber?app=src&addr=127.0.0.1
&newname=ad
Back to cam1
http://server.com/control/redirect/subscriber?app=src&addr=127.0.0.1
&newname=cam1
Now show cam2
http://server.com/control/redirect/subscriber?app=src&addr=127.0.0.1
&newname=cam2
The new stream starts immediately in RTMP. In HLS the stream is usually slightly delayed due to the nature of HLS.

Limitations:
  • The feature only works in single-worker mode. You can easily create a streaming backend with a single worker to pull from.
  • MPEG-DASH engine cannot handle stream discontinuities so the feature will not work properly with DASH