In v1.0.2 of
nginx-rtmp-module I've added support for HLS variant playlists. Now it's easy to create multi-bitrate HLS streams.
The new directive is
hls_variant.
hls_variant SUFFIX [PARAM]*;
where
SUFFIX is used to match incoming stream name,
PARAMs are values added to each variant playlist entry
describing the entry. Examples are
BANDWIDTH=xxxx or
CODECS=yyyy.
http {
listen 80;
location /hls {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
alias /tmp;
}
}
rtmp {
server {
listen 1935;
application src {
live on;
exec ffmpeg -i rtmp://localhost/src/$name
-c:a libfdk_aac -b:a 32k -c:v libx264 -b:v 128K -f flv rtmp://localhost/hls/$name_low
-c:a libfdk_aac -b:a 64k -c:v libx264 -b:v 256k -f flv rtmp://localhost/hls/$name_mid
-c:a libfdk_aac -b:a 128k -c:v libx264 -b:v 512K -f flv rtmp://localhost/hls/$name_hi;
}
application hls {
live on;
hls on;
hls_path /tmp/hls;
hls_nested on;
hls_variant _low BANDWIDTH=160000;
hls_variant _mid BANDWIDTH=320000;
hls_variant _hi BANDWIDTH=640000;
}
}
}
If you stream incoming video with the following command
ffmpeg -i /var/videos/sintel.mp4 -c:a copy -c:v copy -f flv rtmp://localhost/src/sintel;
then the multi-bitrate HLS stream will be available at the following URL
ffplay http://localhost/hls/sintel.m3u8
This playlist references 3 playlist with low, medium and high qualities.
I am not sure why this isn't working...
ReplyDeleteI'm feeding it an h.264 stream from a raspberry pi camera module like so:
raspivid -t 999999999 -w 960 -h 540 -fps 10 -b 500000 -vf -o - | ffmpeg -i - -c:v copy -an -f flv rtmp://localhost/src/raspi
nginx-rtmp is accepting the stream (this is output from nginx-rtmp's stat.xsl):
src
live streams 1
raspi 1 8.54 MB 0 KB 165 Kb/s 0 Kb/s 960x540 25 H264 active 6m 54s
hls
live streams 0
Generated by NGINX RTMP module, NGINX , pid 24116, built Aug 25 2013 16:43:05 gcc 4.6.3 (Debian 4.6.3-14+rpi1)
From nginx.conf (this is basically copied from your post above, but I told ffmpeg to drop the audio, which doesn't exist anyway):
rtmp {
server {
listen 1935;
ping 30s;
notify_method get;
application src {
live on;
exec ffmpeg -i rtmp://localhost/src/$name
-an -c:v libx264 -b:v 128K -f flv rtmp://localhost/hls/$name_low
-an -c:v libx264 -b:v 256k -f flv rtmp://localhost/hls/$name_mid
-an -c:v libx264 -b:v 512K -f flv rtmp://localhost/hls/$name_hi;
}
application hls {
live on;
hls on;
hls_path /tmp/hls;
hls_nested on;
hls_variant _low BANDWIDTH=160000;
hls_variant _mid BANDWIDTH=320000;
hls_variant _hi BANDWIDTH=640000;
}
}
}
FFMPEG is streaming camera video nicely:
ffmpeg version N-55356-gb11b7ce Copyright (c) 2000-2013 the FFmpeg developers
built on Aug 8 2013 00:43:17 with gcc 4.6 (Debian 4.6.3-14+rpi1)
configuration:
libavutil 52. 41.100 / 52. 41.100
libavcodec 55. 23.100 / 55. 23.100
libavformat 55. 13.102 / 55. 13.102
libavdevice 55. 3.100 / 55. 3.100
libavfilter 3. 82.100 / 3. 82.100
libswscale 2. 4.100 / 2. 4.100
libswresample 0. 17.103 / 0. 17.103
Input #0, h264, from 'pipe:':
Duration: N/A, bitrate: N/A
Stream #0:0: Video: h264 (High), yuv420p, 960x540, 25 fps, 25 tbr, 1200k tbn, 50 tbc
Output #0, flv, to 'rtmp://localhost/src/raspi':
Metadata:
encoder : Lavf55.13.102
Stream #0:0: Video: h264 ([7][0][0][0] / 0x0007), yuv420p, 960x540, q=2-31, 25 fps, 1k tbn, 1200k tbc
Stream mapping:
Stream #0:0 -> #0:0 (copy)
frame= 8571 fps= 10 q=-1.0 size= 17645kB time=00:05:42.80 bitrate= 421.7kbits/s
So it looks like it's working, but...
http://localhost/hls/raspi.m3u8 -> HTTP error 404 Not Found
http://localhost/hls -> HTTP error 403 Forbidden
What am I doing wrong?
Change localhost in the following command to localhost:1935:
Deleteexec ffmpeg -i rtmp://localhost/src/$name
-c:a libfdk_aac -b:a 32k -c:v libx264 -b:v 128K -f flv rtmp://localhost/hls/$name_low
-c:a libfdk_aac -b:a 64k -c:v libx264 -b:v 256k -f flv rtmp://localhost/hls/$name_mid
-c:a libfdk_aac -b:a 128k -c:v libx264 -b:v 512K -f flv rtmp://localhost/hls/$name_hi;
Hi Arut, this feature works with vod files?
ReplyDeleteNo. HLS support in nginx-rtmp-module is only for live streams.
ReplyDeleteHi Arut, thanks for your response. One more question, please.
ReplyDeleteI'm trying to deploy this feature, but I believe that I did something wrong.
Basically, I'm ingest a stream as below:
Duration: 02:04:42.34, start: 0.000000, bitrate: 2127 kb/s
Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x808, 2030 kb/s, 23.98
Stream #0:1(eng): Audio: aac (mp4a / 0x6134706D), 48000 Hz, stereo, s16, 93 kb/s
But the logs of nginx showed me like below:
2013/10/22 17:28:11 [info] 652#0: *3 client connected '127.0.0.1'
2013/10/22 17:28:11 [info] 652#0: *3 connect: app='src' args='' flashver='FMLE/3.0 (compatible; Lavf54.29' swf_url='' tc_url='rtmp://localhost:1935/src' page_url='' acodecs=0 vcodecs=0 object_encoding=0, client: 127.0.0.1, server: 0.0.0.0:1935
2013/10/22 17:28:11 [info] 652#0: *3 createStream, client: 127.0.0.1, server: 0.0.0.0:1935
2013/10/22 17:28:11 [info] 652#0: *3 publish: name='sintel' args='' type=live silent=0, client: 127.0.0.1, server: 0.0.0.0:1935
2013/10/22 17:28:11 [notice] 652#0: signal 17 (SIGCHLD) received
2013/10/22 17:28:11 [notice] 652#0: unknown process 1973 exited with code 1
2013/10/22 17:28:16 [notice] 652#0: signal 17 (SIGCHLD) received
2013/10/22 17:28:16 [notice] 652#0: unknown process 1983 exited with code 1
2013/10/22 17:28:17 [info] 652#0: *3 deleteStream, client: 127.0.0.1, server: 0.0.0.0:1935
2013/10/22 17:28:17 [info] 652#0: *3 disconnect, client: 127.0.0.1, server: 0.0.0.0:1935
2013/10/22 17:28:17 [info] 652#0: *3 deleteStream, client: 127.0.0.1, server: 0.0.0.0:1935
My nginx.conf is below:
worker_processes 5;
error_log logs/error.log debug;
events {
worker_connections 1024;
}
rtmp {
server {
listen 1935;
ping 30s;
notify_method get;
application src {
live on;
exec ffmpeg -i rtmp://localhost/src/$name
-c:a libfdk_aac -b:a 32k -c:v libx264 -b:v 128K -f flv rtmp://localhost/hls/$name_low
-c:a libfdk_aac -b:a 64k -c:v libx264 -b:v 256k -f flv rtmp://localhost/hls/$name_mid
-c:a libfdk_aac -b:a 128k -c:v libx264 -b:v 512K -f flv rtmp://localhost/hls/$name_hi;
}
application hls {
live on;
hls on;
hls_path /mnt/hls;
hls_nested on;
hls_fragment 5s;
hls_variant _low BANDWIDTH=160000;
hls_variant _mid BANDWIDTH=320000;
hls_variant _hi BANDWIDTH=640000;
}
}
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
# rtmp stat
location /stat {
rtmp_stat all;
rtmp_stat_stylesheet stat.xsl;
}
location /stat.xsl {
# you can move stat.xsl to a different location
root ~/build/nginx-rtmp-module/;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location /hls {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
alias /mnt/hls;
}
}
}
What should be wrong?
Thanks again.
ffmpeg exits for some reason
Delete1. make sure ffmpeg is accessible from nginx worker account (unprivileged usually)
2. add "2>>/tmp/log" to the end of exec directive to see ffmpeg error
Hi Arut. What is your recommendation for #1?
DeleteShould I modify nginx config so worker_processes run as a user other than nobody? Or should I grant nobody access to exec ffmpeg (possible?)?
Thank you.
Install ffmpeg on Ubuntu:
Deletecd /usr/local/bin
sudo mkdir ffmpeg
cd ffmpeg
sudo wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-64bit-static.tar.xz
sudo tar -xf ffmpeg-release-64bit-static.tar.xz
rm ffmpeg-release-64bit-static.tar.xz
sudo ln -s /usr/local/bin/ffmpeg/ffmpeg-3.4.1-64bit-static/ffmpeg /usr/bin/ffmpeg
#Now ffmpeg is installed as root. Need to change it to nobody for nginx rtmp worker to pick it up:
sudo cp /usr/bin/ffmpeg /var/
sudo chown nobody:nobody ffmpeg
ls -l /var/ffmpeg
-rwxr-xr-x 1 nobody nobody 48373280 Apr 1 17:07 /var/ffmpeg
# edit nginx.conf and set the path to ffmpeg:
exec /var/ffmpeg -i rtmp://localhost/src/$name
-c:a aac -b:a 32k -c:v libx264 -b:v 128K -f flv rtmp://localhost/hls/$name_low
-c:a aac -b:a 64k -c:v libx264 -b:v 256k -f flv rtmp://localhost/hls/$name_mid
-c:a aac -b:a 128k -c:v libx264 -b:v 512K -f flv rtmp://localhost/hls/$name_hi 2>>/tmp/log;
#stop and start nginx. This should work now!
application myapp {
ReplyDeletelive on;
# sample recorder
recorder rec1 {
record all;
record_interval 30s;
record_path /tmp;
record_unique on;
}
# sample HLS
hls on;
hls_path /tmp/app;
hls_fragment 15s;
hls_nested on;
hls_cleanup off;
hls_variant _low BANDWIDTH=160000;
hls_variant _mid BANDWIDTH=320000;
hls_variant _hi BANDWIDTH=640000;
}
location /myapp {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
alias /tmp/app;
add_header Cache-Control no-cache;
}
I am able to play the m3u8 file but only audio without video. i tested in both android and iphone browsers .. while i am trying to play the ts files directly using media player it also play only audio.
Please check video codec. It should be h264.
DeleteCan we create more than 3variants?. I am getting an exception for 4 variants:
ReplyDeletex264 [error]: malloc of size 6955584 failed
Video encoding failed
There's no limit on the number of variants. Where do you have this exception? Libx264 is not related to the rtmp module.
DeleteThis comment has been removed by the author.
ReplyDeleteQuick question: Does the on_play or exec_play type of events work with HLS variants, I cant seem to get it to fire, and my players are not even showing up in the stats page
ReplyDelete*****
rtmp {
server {
listen 1935;
exec_play bash -c "echo $addr $name >> /tmp/clients";
exec_play_done bash -c "echo $addr $name done>> /tmp/clients";
exec_publish bash -c "echo $addr $name >> /tmp/publishers";
exec_publish_done bash -c "echo $addr $name done >> /tmp/publishers";
application src {
live on;
exec ffmpeg -i rtmp://stream.reachbig.com/src/$name
-acodec copy -b:a 64k -c:v libx264 -b:v 256k -f flv rtmp://stream.reachbig.com/live/$name_mid
-acodec copy -vcodec copy -f flv rtmp://stream.reachbig.com/live/$name_hi;
}
application live {
live on;
hls on;
hls_path /HLS/live;
hls_nested on;
hls_fragment 10;
hls_variant _mid BANDWIDTH=320000;
hls_variant _hi BANDWIDTH=2400000;
}
}
}
******
I see the publish and the client playing the src but only the publish in the live
I ultimately want to trigger a bash script on different events.
Jeremy
Hi Arut,
ReplyDeleteIs a multi-bitrate configuration possible with the DASH module of your streaming module? If so, is the syntax for configuring DASH bitrate variants similar to what you've described here for HLS?
Thank you,
Paul
Hi Arut,
ReplyDeleteSorry for my english, i'm French.
I try your configuration for make multi-bitrate HLS streams, but it's not working.
I'm pretty sure the probleme is what have you say : make sure ffmpeg is accessible from nginx worker account (unprivileged usually)
Have you some tips to check that ?
Thanks, and good job for your work man.
A debt of gratitude is in order for the blog entry amigo! Keep them coming... go
ReplyDeletei tried this tutorial exactly, does not work. I do not get multi bit rate hls variant.
ReplyDelete
ReplyDeleteHls Streaming Server
Get to us to find high- quality hls streaming server services and great deals. We are one of the largest service providers that help you with the best hls streaming server services. Visit us to see what we have to offer.
https://cdn.net/how-cdns-facilitate-faster-http-live-streaming/
Thanks for sharing the useful information. If you guys want to finish HLS streaming download task, you should make use of the downloading tools. You can check some of them in the link. Hope it helps.
ReplyDelete