First off, thank you for your continued contribution to the nginx-rtmp-module repo! You should consider putting together an official nginx-rtmp-module-redux
or something!
I am in the process of building out an implementation of your fork of the module to flow like so:
Consume RTMP via broadcasting clients ->
Handle stream coming into RTMP live app and direct it to ffmpeg ->
Output to hls app with three HLS variants, produced by ffmpeg ->
ngx_pagespeed module using memcached handles Amazon CloudFront CDN integration ->
.ts files are caching for 5 seconds, while m3u8 files are set to no-cache (3s segment length, 9s playlist length) ->
User/client consumes the HLS "live" stream via the AWS CloudFront CDN endpoint.
The problem I am encountering is that whether or not I am hitting the nginx server origin directly OR the CloudFront CDN, the hls stream has intermittent playback. The stream will either stop and start attempting to buffer and ultimately fail (the segment files and playlist files still seem to be generated appropriately on the local nginx server) or they will jitter after a pause in playback.
Does anyone have any suggestions for resolving this?
Nginx version: 1.7.11
Nginx RTMP module version: This fork's master, currently at: 1.1.7.10
ffmpeg
version info:
ffmpeg version N-78299-gf021030 Copyright (c) 2000-2016 the FFmpeg developers built with gcc 4.8 (Ubuntu 4.8.4-2ubuntu1~14.04) configuration: --prefix=/home/ubuntu/ffmpeg_build --pkg-config-flags=--static --extra-cflags=-I/home/ubuntu/ffmpeg_build/include --extra-ldflags=-L/home/ubuntu/ffmpeg_build/lib --bindir=/home/ubuntu/bin --enable-gpl --enable-libass --enable-libfdk-aac --enable-libfreetype --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-nonfree --enable-opengl --enable-openssl --enable-libxvid --enable-librtmp --enable-version3 libavutil 55. 17.100 / 55. 17.100 libavcodec 57. 24.101 / 57. 24.101 libavformat 57. 24.100 / 57. 24.100 libavdevice 57. 0.101 / 57. 0.101 libavfilter 6. 28.100 / 6. 28.100 libswscale 4. 0.100 / 4. 0.100 libswresample 2. 0.101 / 2. 0.101 libpostproc 54. 0.100 / 54. 0.100
Here is a refined copy of my nginx.conf:
worker_processes 1;
events {
worker_connections 1024;
}
# RTMP configuration
rtmp {
server {
listen 1935;
chunk_size 4096;
# LIVE / Records all streamers to FLV and MP4 / Notify Method: GET
application live {
live on;
record all;
record_path /tmp/vod/;
# Added this to output mp4 vod
exec_record_done /home/ubuntu/bin/ffmpeg -y -i $path -c copy -copyts /tmp/vod/$basename.mp4;
allow publish all;
allow play all;
meta copy;
sync 100ms;
interleave on;
wait_key on;
wait_video on;
drop_idle_publisher 15s;
notify_method get;
publish_notify on;
idle_streams on;
# FFMPEG execution call for splitting RTMP single stream to three HLS output streams
# enclosed in a single HLS playlist with three bitrates.
# Scale: 480, 720, 960
# Video Codec: libx264 - Video Bitrates: 256k, 768k, 1024k
# Audio Codec: libfdk_aac - Audio Bitrates: 32k, 96k, 128k
# Outputs .ts and .m3u8 files actively.
# Outputs .png video stream snapshot first second and every 60 seconds following
exec /home/ubuntu/bin/ffmpeg -i rtmp://localhost:1935/live/$name
-c:v libx264 -c:a libfdk_aac -b:v 256k -b:a 32k -vf "scale=480:trunc(ow/a/2)*2" -tune zerolatency -preset ultrafast -crf 23 -g 60 -maxrate 3000k -bufsize 4000k -keyint_min 60 -sc_threshold 0 -f flv rtmp://localhost/show/$name_low
-c:v libx264 -c:a libfdk_aac -b:v 768k -b:a 96k -vf "scale=720:trunc(ow/a/2)*2" -tune zerolatency -preset ultrafast -crf 23 -g 60 -maxrate 3000k -bufsize 4000k -keyint_min 60 -sc_threshold 0 -f flv rtmp://localhost/show/$name_mid
-c:v libx264 -c:a libfdk_aac -b:v 1024k -b:a 128k -vf "scale=960:trunc(ow/a/2)*2" -tune zerolatency -preset ultrafast -crf 23 -g 60 -maxrate 3000k -bufsize 4000k -keyint_min 60 -sc_threshold 0 -f flv rtmp://localhost/show/$name_hi
-vf fps=1/30 -vcodec png /tmp/thumbnails/$name.png;
}
# SHOW / Outputs all HLS streams originating from LIVE
application show {
# Turn LIVE on for this app
live on;
# Turn HLS on for this app
hls on;
# Allow everyone to publish (if they pass our stream validation)
allow publish all;
# Allow everyone to playback (really only for the server, specification to come)
allow play all;
# HLS segment and playlist generation location on local server
hls_path /tmp/hls;
# HLS fragment slicing method
hls_fragment_slicing aligned;
# HLS .ts fragment length
hls_fragment 3s;
# HLS .m3u8 playlist length
hls_playlist_length 9s;
# HLS sync
hls_sync 100ms;
# Will HLS use nested directories: on | off
hls_nested off;
# Stream META method: copy | on | off
meta copy;
# HLS pickup of stream where it left off
# hls_continuous on;
# HLS stream type: live | event
hls_type live;
# HLS base url used to reference all .ts and .m3u8 files in the playlists
hls_base_url https://<CLOUDFRONT_CDN>/show/hls/;
# HLS Variants, dictating master m3u8 playlist file
hls_variant _low BANDWIDTH=160000;
hls_variant _mid BANDWIDTH=320000;
hls_variant _hi BANDWIDTH=640000;
}
}
}
http {
include mime.types;
default_type application/octet-stream;
access_log off;
sendfile on;
sendfile_max_chunk 512k;
aio threads;
# Turn Google's ngx_pagespeed on
pagespeed on;
# Use the Native NGINX fetcher
pagespeed UseNativeFetcher on;
# Use Google DNS resolver
resolver 8.8.8.8;
# PageSpeed's file cache path on the local server
pagespeed FileCachePath /var/cache/pagespeed/;
# PageSpeed will report a message in the error log at level "error" for every URL fetch in
# flight when the HTTP stack encounters a system error
pagespeed ListOutstandingUrlsOnError on;
# Enable ForceCaching
pagespeed ForceCaching on;
# Set pagespeed's global admin and stat endpoints
pagespeed GlobalAdminPath /pagespeed_global_admin;
pagespeed GlobalStatisticsPath /ngx_pagespeed_global_statistics;
# Setup acme.com SSL certificate
ssl_certificate /usr/local/nginx/ssl/acme.com.crt;
ssl_certificate_key /usr/local/nginx/ssl/acme.com.key;
# SSL session cache
ssl_session_cache shared:SSL:10m;
# SSL session timeout
ssl_session_timeout 10m;
# SSL usable protocols and versions
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
# SSL usable ciphers
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:RSA+3DES:AES128-SHA:!ADH:!AECDH:!MD5;
# Prefer server ciphers for SSL
ssl_prefer_server_ciphers on;
# Redirect any request on port 80 to 443
server {
listen 80 default_server;
server_name acme.com streams-dev.acme.com;
rewrite ^ https://$host$request_uri permanent;
add_header Strict-Transport-Security max-age=604800;
}
# HTTP server required to serve the player and HLS fragments
server {
listen 443 default_server ssl;
server_name acme.com streams-dev.acme.com;
# PageSpeed
pagespeed Domain "http://acme.com";
pagespeed Domain "https://acme.com";
pagespeed Domain "http://streams-dev.acme.com";
pagespeed Domain "https://streams-dev.acme.com";
pagespeed Domain "http://<CLOUDFRONT_CDN>";
pagespeed Domain "https://<CLOUDFRONT_CDN>";
pagespeed MapOriginDomain "https://streams-dev.acme.com" "https://<CLOUDFRONT_CDN>";
pagespeed MapRewriteDomain "https://<CLOUDFRONT_CDN>" "https://streams-dev.acme.com";
pagespeed CacheFragment "hls-dev_";
pagespeed RewriteLevel CoreFilters;
pagespeed EnableFilters rewrite_domains,remove_comments,collapse_whitespace;
# Speed up PageSpeed by storing it in memcached
pagespeed MemcachedThreads 1;
pagespeed MemcachedServers "localhost:11211";
pagespeed SslCertDirectory /usr/local/nginx/ssl/;
pagespeed EnableCachePurge on;
location /ngx_pagespeed_statistics { allow 127.0.0.1; deny all; }
location /ngx_pagespeed_global_statistics { allow 127.0.0.1; deny all; }
location /ngx_pagespeed_message { allow 127.0.0.1; deny all; }
location /pagespeed_console { allow 127.0.0.1; deny all; }
location ~ ^/pagespeed_admin { allow 127.0.0.1; deny all; }
location ~ ^/pagespeed_global_admin { allow 127.0.0.1; deny all; }
pagespeed StatisticsPath /ngx_pagespeed_statistics;
pagespeed MessagesPath /ngx_pagespeed_message;
pagespeed ConsolePath /pagespeed_console;
pagespeed AdminPath /pagespeed_admin;
# Ensure requests for pagespeed optimized resources go to the pagespeed handler
# and no extraneous headers get set.
location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" {
add_header "" "";
}
location ~ "^/pagespeed_static/" { }
location ~ "^/ngx_pagespeed_beacon$" { }
# Lower-casing HTML element
pagespeed LowercaseHtmlNames on;
# Optimize RewriteLevel for bandwidth
# pagespeed RewriteLevel OptimizeForBandwidth;
# Preserve URL Relativity - PageSpeed will keep URLs the way they were found
pagespeed PreserveUrlRelativity on;
more_set_headers "Access-Control-Allow-Origin: *";
more_set_headers "Access-Control-Allow-Credentials: true";
more_set_headers -t application/vnd.apple.mpegurl 'Cache-Control: public, no-cache';
more_set_headers -t application/x-mpegURL 'Cache-Control: public, no-cache';
more_set_headers -t video/mp2t 'Cache-Control: public, min-age:0, max-age=5';
more_set_headers -t text/html 'Cache-Control: public, min-age:0, max-age=300';
more_set_headers -t image/jpeg 'Cache-Control: public, min-age:10 max-age=300';
more_set_headers -t image/png 'Cache-Control: public, min-age:55 max-age=65';
more_set_headers -t text/css 'Cache-Control: public, min-age:10, max-age=3600';
more_set_headers -t application/x-shockwave-flash 'Cache-Control: public, min-age:10, max-age=3600';
location / {
root html;
add_header X-Cache-Status $upstream_cache_status;
}
location /show {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
text/x-cross-domain-policy xml;
image/png png;
video/mp4 mp4;
}
alias /tmp;
add_header X-Cache-Status $upstream_cache_status;
}
location /stat {
rtmp_stat all;
rtmp_stat_stylesheet stat.xsl;
}
location /stat.xsl {
root html;
}
location /rtmp/control {
rtmp_control all;
}
location = /favicon.ico {
access_log off;
error_log off;
add_header Cache-Control public;
add_header expires max;
}
}
}
Also, I should note that I just recently added threading in an attempt to speed things up:
access_log off;
sendfile on;
sendfile_max_chunk 512k;
aio threads;
NGINX Compile config:
./configure --with-http_ssl_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_secure_link_module \
--with-http_auth_request_module \
--with-file-aio \
--with-http_spdy_module \
--with-pcre-jit \
--with-http_stub_status_module \
--with-ipv6 \
--with-threads \
--add-module=../sergey-rtmp-nginx \
--add-module=../headers-more-nginx-module-0.28 \
--add-module=../ngx_pagespeed
Does anyone have any recommendations on this?
Thank you for your time!