Friday, August 18, 2017

Implement Nginx Reverse Proxy with SSL for Live Streaming

After struggling implement NGINX reverse proxy setup, I have decided to share my running config currently and hope this could be of any help to someone.

Here is the scenario of the implementation


First, we need to configure NGINX to enable http_v2_module
sudo ./configure  --with-http_ssl_module --with-http_v2_module  --add-module=../nginx-rtmp-module
make
sudo make install

After configure and compile NGINX, then in server 10.10.16.32 as reverse proxy, the configuration as following as below and don't forget to copy your SSL key and crt to your correct folder, in my case is in /home/livetv/live.

user livetv;
worker_processes  8;

error_log    /var/log/nginx/error.log debug;
worker_rlimit_nofile 65536;  #worker_rlimit_nofile = worker_connections * worker_processes

events {
    worker_connections  8192;
    multi_accept on;
    use epoll;
}

rtmp {
    server {
        listen 1935;
        chunk_size 8192;
        ping 30s;
        notify_method get;
        allow play all;

        application live {
            live on;

            exec_pull ffmpeg -re -i http://10.10.17.50/$app/$name
                 -vcodec copy -f flv -ar 44100 -ab 64 -ac 1 -acodec mp3 rtmp://localhost:1935/show/${name}
                 -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 1024k -b:a 128k -vf "scale=854:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/show/${name}_480
                 -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 776k -b:a 96k -vf "scale=640:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/show/${name}_360
                 -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 128k -b:a 96k -vf "scale=256:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/show/${name}_144;
        }

        application show {
            live on;
            hls on;
            hls_path /home/livetv/live/hls/;
            hls_nested on;
            record off;

            ### Instruct clients to adjust resolution according to bandwidth
            hls_variant _720 BANDWIDTH=2048000 RESOLUTION=1280x720; # High bitrate, HD 720p resolution
            hls_variant _480 BANDWIDTH=1024000 RESOLUTION=852x480;     # High bitrate, higher-than-SD resolution
            hls_variant _360 BANDWIDTH=512000 RESOLUTION=640x360;     # Medium bitrate, SD resolution
            hls_variant _240 BANDWIDTH=307200 RESOLUTION=426x240;     # Low bitrate, sub-SD resolution
            hls_variant _144 BANDWIDTH=131000 RESOLUTION=256x144;     # Low bitrate, 140p resolution
        }
       
        exec_pull /home/livetv/live/chmodTV.sh;
    }
}

http {
    include /etc/nginx/mime.types;
    default_type  application/octet-stream;
    sendfile on;
    keepalive_timeout   65;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;

    server {
        listen      8080;

        location /hls {
            # Disable cache
            add_header 'Cache-Control' 'no-cache';

            # CORS setup
            add_header 'Access-Control-Allow-Origin' '*' always;
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
            add_header 'Access-Control-Allow-Headers' 'Range';

            # allow CORS preflight requests
            if ($request_method = 'OPTIONS') {
                    add_header 'Access-Control-Allow-Origin' '*';
                    add_header 'Access-Control-Allow-Headers' 'Range';
                    add_header 'Access-Control-Max-Age' 1728000;
                    add_header 'Content-Type' 'text/plain charset=UTF-8';
                    add_header 'Content-Length' 0;
                    return 204;
            }

            #serve HLS fragments
            types {
                    application/dash+xml mpd;
                    application/vnd.apple.mpegurl m3u8;
                    video/mp2t ts;
            }

            root /home/livetv/live/;
            add_header Cache-Control no-cache;
        }

        #include /usr/local/nginx/conf/sites-enabled/*.conf;
    }

    server {
        listen 443 ssl http2;
        server_name cdn-livetv.metube.id;
        root /home/livetv/live/;

        ssl on;
        ssl_certificate /home/livetv/live/ssl/STAR_metube_id.crt;
        ssl_certificate_key /home/livetv/live/ssl/metube.key;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;

        ssl_buffer_size 16k;

        location / {
            index index.html;
        }

        location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|pdf|txt|xml|js)$ {
            expires 21d;
            add_header Pragma public;
            add_header Cache-Control "public, must-revalidate, proxy-revalidate";
            access_log off;
            log_not_found off;
            fastcgi_hide_header Set-Cookie;
            tcp_nodelay off;
            sendfile off;
            break;
        }

        location /hls {
            proxy_set_header x-real-IP $remote_addr;
            proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
            proxy_set_header x-forwarded-proto https;
            proxy_set_header host $host;
            proxy_pass http://172.31.16.26;
           
            #this is will handle problem in mobile when rise protocol exception
            proxy_buffering on;
            proxy_buffer_size 8k;
            proxy_buffers 2048 8k;
        }
    }
}




In server 172.31.16.26 as backend, the configuration as following as below and don't forget to copy your SSL key and crt to your correct folder, in my case is in /home/livetv/live.


user livetv livetv;
worker_processes  20;

error_log  logs/error.log debug;
worker_rlimit_nofile 409600; #worker_rlimit_nofile = worker_connections * worker_processes

events {
    worker_connections  20480;
    multi_accept on;
    use epoll;
}

rtmp {
    server {
        listen 1935;
        chunk_size 8192;
        ping 30s;
        notify_method get;
        allow play all;

        application live {
            live on;

            exec_pull ffmpeg -re -i http://172.31.16.27/$app/$name
                 -vcodec copy -f flv -ar 44100 -ab 64 -ac 1 -acodec mp3 rtmp://localhost:1935/show/${name}
                 -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 1024k -b:a 128k -vf "scale=854:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/show/${name}_480
                 -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 776k -b:a 96k -vf "scale=640:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/show/${name}_360
                 -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 128k -b:a 96k -vf "scale=256:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/show/${name}_144;
        }

        application show {
            live on;
            hls on;
            hls_path /home/livetv/live/hls/;
            hls_nested on;
            record off;

            ### Instruct clients to adjust resolution according to bandwidth
            hls_variant _720 BANDWIDTH=2048000 RESOLUTION=1280x720; # High bitrate, HD 720p resolution
            hls_variant _480 BANDWIDTH=1024000 RESOLUTION=852x480;     # High bitrate, higher-than-SD resolution
            hls_variant _360 BANDWIDTH=512000 RESOLUTION=640x360;     # Medium bitrate, SD resolution
            hls_variant _240 BANDWIDTH=307200 RESOLUTION=426x240;     # Low bitrate, sub-SD resolution
            hls_variant _144 BANDWIDTH=131000 RESOLUTION=256x144;     # Low bitrate, 140p resolution

        }
    }
}


http {

    include mime.types;
    default_type  application/octet-stream;
    sendfile on;
    keepalive_timeout   65;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;

    server {
        listen      80;

        location /hls {
            # Disable cache
            add_header 'Cache-Control' 'no-cache';

            # CORS setup
            add_header 'Access-Control-Allow-Origin' '*' always;
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
            add_header 'Access-Control-Allow-Headers' 'Range';

            # allow CORS preflight requests
            if ($request_method = 'OPTIONS') {
                    add_header 'Access-Control-Allow-Origin' '*';
                    add_header 'Access-Control-Allow-Headers' 'Range';
                    add_header 'Access-Control-Max-Age' 1728000;
                    add_header 'Content-Type' 'text/plain charset=UTF-8';
                    add_header 'Content-Length' 0;
                    return 204;
            }

            #serve HLS fragments
            types {
                    application/dash+xml mpd;
                    application/vnd.apple.mpegurl m3u8;
                    video/mp2t ts;
            }

            root /home/livetv/live/;
            add_header Cache-Control no-cache;
        }

        include /usr/local/nginx/conf/sites-enabled/*.conf;

    }

    server {
        listen 443 ssl http2;
        server_name cdn-livetv.metube.id;
        #rewrite ^(.*)  cdn-livetv.metube.id$1 permanent;
        root /home/livetv/live/;

        ssl on;
        ssl_certificate /home/livetv/live/ssl/STAR_metube_id.crt;
        ssl_certificate_key /home/livetv/live/ssl/metube.key;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;

        ssl_buffer_size 16k;
        location / {
            index index.html;
        }

        location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|pdf|txt|xml|js)$ {
            expires 21d;
            add_header Pragma public;
            add_header Cache-Control "public, must-revalidate, proxy-revalidate";
            access_log off;
            log_not_found off;
            fastcgi_hide_header Set-Cookie;
            tcp_nodelay off;
            sendfile off;
            break;
        }

        location /hls {
            proxy_set_header x-real-IP $remote_addr;
            proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
            proxy_set_header x-forwarded-proto https;
            proxy_set_header host $host;
            proxy_pass http://127.0.0.1;
           
            #this is will handle problem in mobile when rise protocol exception
            proxy_buffering on;
            proxy_buffer_size 8k;
            proxy_buffers 2048 8k;
        }
    }
}

                  
                               
               
               

Other Topics:
               
               
               
               
               
               
               
               

Friday, August 11, 2017

IP Forwarding and Enable UDP Multicast

During few days, I am confused on steaming of live TV that I created on our product. I couldn't forward the streaming of live tv on UDP multicast from eth0 to eth1. Our server has 2 network interface card and let say eth0 with IP 10.10.10.5 and eth1 with IP 172.31.16.26. In my opinion, it should be easy to be done but unfortunately, it is not simple as i thought. In order to make this happen then i created some simple experiment to forward traffic from eth0 to eth1. Here is my step to implement the things on how to forward IP and Port.

Step 1. Make sure the ip_forward is enable. Check on /etc/sysctl.conf and change the value to net.ipv4.ip_forward=1  If the flag is commented then just uncomment the line by removing # or you can do by typing on terminal sudo sysctl -w net.ipv4.ip_forward=1

Step 2. Change net.ipv4.conf.default.rp_filter=1. Check on /proc/sys/net/ipv4/conf/eth0/rp_filter and change the value to net.ipv4.conf.default.rp_filter=2


Step 3. Type this command on terminal 

sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
This command can be explained in the following way:
iptables: the command line utility for configuring the kernel
-t nat: select table "nat" for configuration of NAT rules.
-A POSTROUTING:  Append a rule to the POSTROUTING chain (-A stands for "append").
-o eth0: this rule is valid for packets that leave on the second network interface (-o stands for "output")
-j MASQUERADE: the action that should take place is to 'masquerade' packets, i.e. replacing the sender's address by the router's address.
Then forward packet from eth0 to eth1 
sudo iptables -A FORWARD -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT

Step 4. Add route to enable UDP multicast address from 224.0.0.0 to 239.255.255.255
route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0

Step 5. Make sure your firewall is inactive or if firewall enable then you must change DEFAULT_INPUT_POLICY="ACCEPT" on /etc/default/ufw 

Step 6. To check if the things is working properly then send data over UDP  by typing command on terminal 
echo "This is my data" > /dev/udp/239.255.0.1/3000
This will send text "This is my data" to UDP with IP 239.255.0.1 and Port 3000 and 
from the other terminal, just dump by typing command 
tcpdump -i eth1 udp port 3000 -vv -X


If you are successfully, then you will receive the text



Other Topics:




Tuesday, April 11, 2017

Creating Overlay Image and Running Text in Multiple Output Streaming with NGINX RTMP


Creating Multiple Output with No Filter

Creating multiple output without implement filtering can be done by using command

syntax:
           ffmpeg -i input1 -i input2 \
               -acodec … -vcodec … output1 \
               -acodec … -vcodec … output2 \
               -acodec … -vcodec … output3



Pic 1.  Multiple Outputs


Here is an example to create several different outputs out HD, VGA and QVGA resolution at the same time with one command

syntax:
           ffmpeg -i input \
               -s 1280x720 -acodec … -vcodec … output1 \
               -s 640x480  -acodec … -vcodec … output2 \
               -s 320x240  -acodec … -vcodec … output3


Creating Multiple Output with Same Filter to All Output

To implement same filter in multiple output can be done by using -filter_complex with split filter.
Command below to split=3 means split to three streams

syntax:
         ffmpeg -i input -filter_complex '[0:v]yadif,split=3[out1][out2][out3]' \
                           -map '[out1]' -s 1280x720 -acodec … -vcodec … output1 \
                           -map '[out2]' -s 640x480  -acodec … -vcodec … output2 \
                           -map '[out3]' -s 320x240  -acodec … -vcodec … output3


Creating Multiple Output with Specific Filter per each Output

To create multiple output with specific filter per each output can be done by using  -filter_complex with split filter, but split goes to input directly.

Below syntax to encode video to three different output at the same time, but boxblur will impact to output1, negate will impact to output2 and yadif will impact to output3.
syntax:
      ffmpeg -i input -filter_complex \
         '[0:v]split=3[in1][in2][in3];[in1]boxblur[out1];\
          [in2]negate[out2];[in3]yadif[out3]' \
        -map '[out1]' -acodec … -vcodec … output1 \
        -map '[out2]' -acodec … -vcodec … output2 \
        -map '[out3]' -acodec … -vcodec … output3


Creating Overlay Image and Running Text with Multiple Output

Here is my own experiment to implement Overlay Image and Running Text in Streaming with multiple resolution and multiple output. The main concern when implement this filter is the Overlay Image and Running Text will only display in output1 and dissappear in other output due to wrong placement of filtering. This is become my concern and do some experiment to find solution on how to put carefully of filtering placement.

Syntax:
ffmpeg -i storm_spirit.mp4 -i addies.jpg -filter_complex \
"[1:v]scale=iw/2:ih/2[logo];[0:v][logo]overlay=W-w-5:H-h-5, \
scale=320:-2,drawbox=x=0:y=122:color=yellow@0.4:width=iw:height=30:t=max, \
drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSans.ttf:text='This Is Running Text':\
fontcolor=white@1.0:fontsize=16:y=h-line_h-30:x=w/10*mod(t\,10):\
enable=gt(mod(t\,20)\,10),split=3[a][b][c]" \
-map "[a]" -map 0:a -vcodec libx264 -acodec aac -strict -2 -b:v 256k -b:a 32k -f flv rtmp://192.168.135.128:1935/myapp/mystream \
-map "[b]" -map 0:a -vcodec libx264 -acodec aac -strict -2 -b:v 128k -b:a 32k -f flv rtmp://192.168.135.128:1935/myapp/mystream2 \
-map "[c]" -map 0:a -vcodec libx264 -acodec aac -strict -2 -b:v 96k -b:a 32k -f flv rtmp://192.168.135.128:1935/myapp/mystream3


Result, Ovelay Image and Running Text can be seen in each output of streaming.



Pic 2. Overlay Image and Running Text can be implemented in each stream output

Thank you
Other Topics:





Thursday, April 6, 2017

How to Implement Running Text in Streaming with NGINX RTMP



In my previous tutorial, I have explained on How to Build NGINX RTMPSetup Live Streaming with NGINX RTMPCreate Adaptive Streaming with NGINX RTMP and Implementing Filtergraph in Streaming with NGINX RTMP.  Please read it before start to learn this tutorial.

Running Text is one of the very useful electronic or digital media to convey messages and information can also be used as a means of advertising.

In its development, the display running text now comes not only show a series of posts to walk alone but also able to display images or logos.

Running Text was elected by a lot of people as a means of advertising, as a means of advertising for reasons other than a very beatiful display, running text in itself proved to have an attaction for people around who saw it, as well as know, that the human visual sense be the eyes are very interested in a view that is bright, colorful, striking and others around him. This is the underlying color of the display running text inviting people around her eyes to look at him.

Here is the command on how to create "Hello World" Running Text in streaming

ffmpeg -i storm_spirit.mp4 -filter:v drawtext="fontfile=/usr/share/fonts/truetype/freefont/FreeSans.ttf:text='Hello World':fontcolor=white@1.0:fontsize=16:y=h-line_h-100:x=w/10*mod(t\,10):enable=gt(mod(t\,20)\,10)" -vcodec libx264 -acodec aac -strict -2 -b:v 256k -b:a 32k -f flv rtmp://192.168.135.128:1935/myapp/mystream


Result shown as picture below


Pic 1.  Running Text "Hello World"



This is to show 'Running Text in Streaming with NGINX RTMP'

ffmpeg -i storm_spirit.mp4 -filter:v drawtext="fontfile=/usr/share/fonts/truetype/freefont/FreeSans.ttf:text='Running Text in Streaming with NGINX RTMP':fontcolor=white@1.0:fontsize=16:y=h-line_h-100:x=w/10*mod(t\,10):enable=gt(mod(t\,20)\,10)" -vcodec libx264 -acodec aac -strict -2 -b:v 256k -b:a 32k -f flv rtmp://192.168.135.128:1935/myapp/mystream

Result shown as below:


Pic 2. Running Text "Running Text in Streaming with NGINX RTMP"

All above sample, Text is running from left to right.

Horizontal movement:

            x=w/10*mod(t\,10)

            where w is the input width
                        t is the time
                       w/10 is the speed of movement (whole width in 10s)
                        t mod 10 is used to repeat every 10s

Enabling:
           enable=gt(mod(t\,20)\,10)
           every 20s show the text animation for 10s after the initial 10s

                   

This is an example Running Text with Background. The command as below

ffmpeg -i /mnt/e/kurento/compile\ NGIX/storm_spirit.mp4 -filter:v "drawbox=y=ih/PHI:color=black@0.4:width=iw:height=30:t=max, drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSans.ttf:text='Addiestar Silaban Running Text':fontcolor=white@1.0:fontsize=16:y=h-line_h-115:x=w/10*mod(t\,10):enable=gt(mod(t\,20)\,10)" -vcodec libx264 -acodec aac -strict -2 -b:v 256k -b:a 32k -f flv rtmp://192.168.135.128:1935/myapp/mystream

Result shown as below


Pic 3. Running Text with Black Background



Don't forget to change the RTMP IP address (red color)
rtmp://192.168.135.128:1935/myapp/mystream  to your NGINX RTMP server IP Address


Thank you




Other Topics:



Wednesday, April 5, 2017

Implementing Filtergraph in Streaming with NGINX RTMP


In my previous tutorial, I have explained on How to Build NGINX RTMP, Setup Live Streaming with NGINX RTMP, Create Adaptive Streaming with NGINX RTMP.  Please read it before start to learn this tutorial.



Deinterlace

To prevent flicker and reducing transmission bandwidth, all analog camcorders, VCRs, broadcast television systems use interlaced scan. So, deinterlacing video is in practice the process of converting interlaced video into progressive video.

Please type this command on terminal to implement deinterlace:

ffmpeg -i adam_levine.mp4 -vf "yadif=0:0:0" -vcodec libx264 -acodec aac -strict -2 -b:v 256k -b:a 32k -f flv rtmp://192.168.135.128:1935/myapp/mystream



Pic 1. Deinterlace result



Turn Video to Black and White

If you need to turn video into black and white then this is the command

ffmpeg -i storm_spirit.mp4 -vf "yadif=0:0:0, hflip, hue=s=0" -vcodec libx264 -acodec aac -strict -2 -b:v 256k -b:a 32k -f flv rtmp://192.168.135.128:1935/myapp/mystream



Pic 2. Turn Video to Black and White


Split Screen

To make split screen, you can implement with this command

ffmpeg -i storm_spirit.mp4 -s 850x480 -vf "scale=850:240 [inScale]; color=c=black@1.0:s=850x480:r=29.97:d=30.0 [bg]; movie=adam_levine.mp4, scale=850:240 [vid2]; [bg][vid2] overlay=0:0 [basis1]; [basis1][inScale] overlay=0:240" -vcodec libx264 -acodec aac -strict -2 -b:v 256k -b:a 32k -f flv rtmp://192.168.135.128:1935/myapp/mystream




Pic 3. Split Screen



Overlay

To implement overlay image in your stream, you can do with this command

ffmpeg -i adam_levine.mp4 -vf "movie=addies.jpg [over]; [in][over]overlay=main_w-overlay_w-10:main_h-overlay_h-10" -vcodec libx264 -acodec aac -strict -2 -b:v 256k -b:a 32k -f flv rtmp://192.168.135.128:1935/myapp/mystream



Pic 4. Overlay Image



Picture in Picture (PiP)

This is the way to implement Picture in Picture (PiP). The command as below

ffmpeg -i storm_spirit.mp4 -i adam_levine.mp4 -i Slash.mp4 -filter_complex "[1:v]scale=iw/5:ih/5:flags=lanczos[pip1];[2:v]scale=iw/5:ih/5:flags=lanczos[pip2];[0:v][pip1]overlay=main_w-overlay_w-100:main_h-overlay_h-100[bg1];[bg1][pip2]overlay=main_w-overlay_w*4-100:main_h-overlay_h-100" -vcodec libx264 -acodec aac -strict -2 -b:v 256k -b:a 32k -f flv rtmp://192.168.135.128:1935/myapp/mystream




Pic 5. Picture in Picture (PiP)



Please change red color IP address rtmp://192.168.135.128:1935/myapp/mystream to your NGINX RTMP IP address

Thank you




Other Topics:



Monday, April 3, 2017

Create Adaptive Streaming with NGINX RTMP



In my previous articles How to build NGINX RTMP module, Setup Live Streaming with NGINX RTMP module and Publishing Stream with Open Broadcaster Software (OBS), I have examined how to stream a video file with FFmpeg encoder without any conversion. The streaming output is the same as the input sources.


For converting live streams into several streams resolution for adaptive streaming purpose, we need to make sure server have enough CPU for the workload. This is to prevent live streaming from continuous delays and even worst, server become unresponsive and hang. To prevent this case happen then we need to think about the resolution that will be offering for adaptive streaming. Normally, there are 4 variants that we can use for adaptive streaming consist of

1. 240p Low Definition stream at 288kbps
2. 480p Standard Definition stream at 448kbps
3. 540p Standard Definition stream at 1152kbps
4. 720p High Definition stream at 2048kbps



Configure nginx.conf for Adaptive Live Streaming

Here is my own configuration (simple configuration). In this configuration, I used resolution 240p, 480p, 720p.

#user  nobody;
worker_processes  1;

error_log  logs/error.log debug;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       8080;
        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
            # in my case, i used /home/addies/build/nginx-rtmp-module
            root /home/addies/build/nginx-rtmp-module;
        }

        location /hls {
                add_header 'Cache-Control' 'no-cache';
                add_header 'Access-Control-Allow-Origin' '*' always;
                add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
                add_header 'Access-Control-Allow-Headers' 'Range';

                if ($request_method = 'OPTIONS') {
                       add_header 'Access-Control-Allow-Origin' '*';
                       add_header 'Access-Control-Allow-Headers' 'Range';
                       add_header 'Access-Control-Max-Age' 1728000;
                       add_header 'Content-Type' 'text/plain charset=UTF-8';
                       add_header 'Content-Length' 0;
                       return 204;
                }

                #serve HLS fragments
                types {
                       application/dash+xml mpd;
                       application/vnd.apple.mpegurl m3u8;
                       video/mp2t ts;
                }

                root /home/addies/live/;
                add_header Cache-Control no-cache;            
        }

        # rtmp control
        location /control {
            rtmp_control all;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

rtmp {
    server {
        listen 1935;
        ping 30s;
        notify_method get;

        application live {
            live on;     

            exec_pull ffmpeg -re -i http://your_ip_source/$app/$name
 -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 1920k -b:a 128k -vf "scale=1280:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/show/${name}_720
-vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 1024k -b:a 128k -vf "scale=854:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/show/${name}_480
 -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 300k -b:a 96k -vf "scale=426:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/show/${name}_240;
        }


       application show {

            live on;

            hls on;
            hls_path /home/addies/live/hls;
            hls_nested on;
            record off;
            
            # Instruct clients to adjust resolution according to bandwidth

            hls_variant _720 BANDWIDTH=2048000; # High bitrate, HD 720p resolution
            hls_variant _480 BANDWIDTH=448000; # Medium bitrate, SD resolution
            hls_variant _240 BANDWIDTH=288000; # Low bitrate, sub-SD resolution

        }

    }
}

After finished the configuration then you need to create folder for hls files that created by nginx
cd ~
mkdir live
cd ~/live
mkdir hls
cd ~
chmod -R 755 /home/addies/live

To test your configuration then you need to open linux terminal and type command

ffmpeg -re -i /home/addies/stream/any_files_for_testing.mp4 -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 1920k -b:a 128k -vf "scale=1280:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/live/any_name  -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 1024k -b:a 128k -vf "scale=854:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/live/any_name  -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 300k -b:a 96k -vf "scale=426:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/live/any_name 



Next, you can play from vlc player by inputing the stream url:
http://your_server/hls/any_name.m3u8