Skip to content

Instantly share code, notes, and snippets.

@ccoles146
Created April 3, 2024 15:12
Show Gist options
  • Select an option

  • Save ccoles146/87023f1ebc89c0525801bc46d3bf4c97 to your computer and use it in GitHub Desktop.

Select an option

Save ccoles146/87023f1ebc89c0525801bc46d3bf4c97 to your computer and use it in GitHub Desktop.
Quick Local Video streaming server with push to multiple destinations

Video Streaming Server

Installation

  1. Download and install Ubuntu, (e.g. server 22.04)
  2. Configure server with static IP address
  3. Install Nginx-RTMP
sudo apt update
sudo apt install libnginx-mod-rtmp

Installation of ffmpeg (optional)

ffmpeg can be used for streaming a pre-recorded video directly from this server. It is useful for testing.

sudo apt install ffmpeg

Installation of youtube-dl (optional)

youtube-dl can be used for downloading streaming content from YouTube or elsewhere.

sudo apt install youtube-dl

youtube-dl can simply be run using a command like:

youtube-dl https://www.youtube.com/watch?v=iom_nhYQIYk

Streaming a video to the RTMP server (optional)

This will only work once the RTMP service is running. The command to use later is:

ffmpeg -re -i "Introducing App Platform by DigitalOcean-iom_nhYQIYk.mp4" -c:v copy -c:a aac -ar 44100 -ac 1 -f flv rtmp://localhost/live/stream

Streaming at multiple different qualities (Transcoding) can be done as follows, but RTMP must first be configured using dash_variant and/or hls_variant

ffmpeg -re -i "Test Video.mp4" \
    -c:a aac -ac 2 -b:a 128k -c:v libx264 -pix_fmt yuv420p -profile:v baseline -preset ultrafast -tune zerolatency -vsync cfr -x264-params "nal-hrd=cbr" -b:v 500k -minrate 500k -maxrate 500k -bufsize 1000k -g 60 -s 640x360 -f flv rtmp://example.com/dash/streamname_low \
    -c:a aac -ac 2 -b:a 128k -c:v libx264 -pix_fmt yuv420p -profile:v baseline -preset ultrafast -tune zerolatency -vsync cfr -x264-params "nal-hrd=cbr" -b:v 1500k -minrate 1500k -maxrate 1500k -bufsize 3000k -g 60 -s 1280x720 -f flv rtmp://example.com/dash/streamname_med \
    -c:a aac -ac 2 -b:a 128k -c:v libx264 -pix_fmt yuv420p -profile:v baseline -preset ultrafast -tune zerolatency -vsync cfr -x264-params "nal-hrd=cbr" -b:v 5000k -minrate 5000k -maxrate 5000k -bufsize 10000k -g 60 -s 1920x1080 -f flv rtmp://example.com/dash/streamname_high 

Configure RTMP

Edit the nginx.conf file using nano which may need installing first.

sudo apt install nano /Y
sudo nano /etc/nginx/nginx.conf

Add the following text to the end:

rtmp {
        server {
                listen 1935;
                chunk_size 4096;
                allow publish 127.0.0.1;
                deny publish all;
                # Specify buffer settings
                buflen 5s;  # Set the buffer length

                application live {
                        live on;
                        record off;
                }
        }
}

Note allow publish ip-address; # is the IP address that streams may be receive from. This will need modifying to accept a stream from another server e.g. OBS or ProPresenter7.

Sending Streams to the server

When the application is called live then the target can be set as follows:

rtmp://ip-address/live

The path or the key can be whatever you want e.g.: obs_stream

Warning Ensure the RMTP server settings in nginx.conf is configured to allow publish from the sending ip-address.

Watching an RTMP stream

To watch the RTMP stream from the local server:

  • Use VLC player
  • Open Network Stream
  • rtmp://ip-address/live/obs_stream

Add Monitoring Configuration (optional)

The monitoring site will be available at port 8080

Creating the following configuration:

sudo nano /etc/nginx/site-available/rtmp

Add the following contents:

server {
    listen 8080;
    server_name  localhost;

    # rtmp stat
    location /stat {
        rtmp_stat all;
        rtmp_stat_stylesheet stat.xsl;
    }
    location /stat.xsl {
        root /var/www/html/rtmp;
    }

    # rtmp control
    location /control {
        rtmp_control all;
    }
}

Create the necessary folders and templates:

sudo mkdir /var/www/html/rtmp
sudo gunzip -c /usr/share/doc/libnginx-mod-rtmp/examples/stat.xsl.gz > /var/www/html/rtmp/stat.xsl
sudo ln -s /etc/nginx/sites-available/rtmp /etc/nginx/sites-enabled/rtmp

View your stats at http://ip-address:8080/stat

Add Modern Stream Formats

To add HLS and MPEG DASH support we need the following configuration without our live application:

sudo nano /etc/nginx/nginx.conf

Create the config to match:

...
rtmp {
        server {
...
                application live {
                    	live on;
                    	record off;
                        hls on;
                        hls_path /var/www/html/stream/hls;
                        hls_fragment 3;
                        hls_playlist_length 60;

                        dash on;
                        dash_path /var/www/html/stream/dash;
                }
        }
}
...

Now create the necessary directory and edit the rtmp site config

sudo mkdir /var/www/html/stream
sudo nano /etc/nginx/sites-available/rtmp
. . .
server {
    listen 8088;

    location / {
        add_header Access-Control-Allow-Origin *;
        root /var/www/html/stream;
    }
}

types {
    application/dash+xml mpd;
}

Note Now reload the configuration.

View the streams using a stream viewer

HLS: http://ip-address:8088/hls/stream.m3u8 DASH: http://ip-address:8088/dash/stream.mpd

View the streams from the Internet

You need a player such as a Chrome extension. However there is a player here: https://reference.dashif.org/dash.js/latest/samples/dash-if-reference-player/index.html

Enter the URL as above to view the stream.

Alternative configurations

rtmp {
    server {
        listen 1935;
        chunk_size 4096;

        publish_time_fix off;

        application dash {
            live on;
            record off;
            allow publish ip-address;
            allow publish 127.0.0.1;
            deny publish all;

            # Copy incoming streams to the HLS application
            exec ffmpeg -re -i rtmp://localhost:1935/$app/$name -c:v copy -c:a copy -f flv rtmp://localhost:1935/hls/${name};

            dash on;
            dash_nested on;
            dash_path /tmp/dash;
            dash_fragment 3;
            dash_playlist_length 120;
            dash_cleanup on;

            dash_clock_compensation http_head;
            dash_clock_helper_uri https://<your_server_domain_here>/time;

            dash_variant _low   bandwidth="500000"  width="640"  height="360";
            dash_variant _med  bandwidth="1500000" width="1280"  height="720";
            dash_variant _high bandwidth="5000000" width="1920" height="1080" max;
        }

        application hls {
            live on;
            hls on;
            hls_path /tmp/hls;
            hls_nested on;

            hls_variant _low   BANDWIDTH=500000;
            hls_variant _med  BANDWIDTH=1500000;
            hls_variant _high BANDWIDTH=5000000;
        }
    }
}

Reload the changed configuration

sudo systemctl reload nginx

Restream to Web-based services

In order to push the stream out to other servers such as YouTube or Facebook the following can be used:

sudo nano /etc/nginx/nginx.conf
        application relays {
            live on;
            push rtmp1.youtube.com;
            push rtmp1.facebook.com;
        }

Note Don't forget to reload the configuration.

Firewall Configuration

If you have a firewall such as ufw then the following rules will be required:

  • 8088/tcp #dash or hls streams
  • 1935/tcp #rtmp streams
  • 8080/tcp #stats page

In ufw use the following:

sudo ufw allow from your_ip_address to any port http-alt
sudo ufw allow 8088/tcp
sudo ufw allow 1935/tcp

Encryption

If the server can have a subdomain e.g. live.example.com then the certificate will apply to that. Then we may use some dynamic dns service to keep the dns entry updated if we don't have a static IP.

  • Install letsencrypt sudo apt install letsencrypt
  • Stop nginx sudo systemctl stop nginx
  • sudo letsencrypt certonly
  • Edit /etc/nginx/nginx.conf
    server {
        listen 80;
        server_name <your_server_domain_here>;
        return 301 https://$host$request_uri;
    }

    server {
        listen       443 ssl;
        server_name  <your_server_domain_here>;

        ssl_certificate /etc/letsencrypt/live/<your_server_domain_here>/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/<your_server_domain_here>/privkey.pem;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_dhparam /etc/ssl/certs/dhparam.pem;
        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;
        ssl_stapling on;
        ssl_stapling_verify on;
        add_header Strict-Transport-Security max-age=15768000;
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment