nginxvideoffmpegvideo-streamingrtmp

VLC and ffplay not receiving video from RTMP stream on Nginx


I'm streaming via OBS 30.1.2 to an RTMP server on a digitalocean droplet. The server is running on nginx 1.26.0 using the RTMP plugin (libnginx-mod-rtmp in apt).

OBS is configured to output H.264-encoded, 1200kbps, 24fps, 1920x1080 video and aac-encoded, stereo, 44.1kHz, 160kbps audio.

Below is the minimal reproducible example. When I attempt to play the rtmp stream with ffplay or VLC, it's a random chance whether I get video or not. Audio is always fine. The output from ffplay or ffprobe (example below) occasionally does not show any video stream.

rtmp {
        server {
                listen 1935;
                chunk_size 4096;

                application ingest {
                        live on;
                        record off;

                        allow publish <my ip address>;
                        deny publish all;

                        allow play all;
                }
        }
}

The server has two applications, "ingest" and "live", the former uses the following ffmpeg command to transcode the stream and create a corresponding stream on the latter application:

exec_push ffmpeg -i rtmp://localhost/ingest/$name -b:v 1200k -c:v libx264 -c:a aac -ar 44100 -ac 1 -f flv -preset veryfast -tune zerolatency rtmp://localhost/live/$name 2>>/tmp/rtmp-ingest-$name.log;

As you can see, this produces a log which shows the following:

Output #0, flv, to 'rtmp://localhost/live/ekobadd':
  Metadata:
    |RtmpSampleAccess: true
    Server          : NGINX RTMP (github.com/arut/nginx-rtmp-module)
    displayWidth    : 1920
    displayHeight   : 1080
    fps             : 23
    profile         :
    level           :
    encoder         : Lavf61.1.100
  Stream #0:0: Audio: aac (LC) ([10][0][0][0] / 0x000A), 44100 Hz, mono, fltp, 69 kb/s
      Metadata:
        encoder         : Lavc61.3.100 aac

The video is not present, though I can see on the digitalocean control panel that the server is pulling 1.2Mbps inbound, which is about the same as my OBS video bitrate. And, although the ffmpeg instance which is transcoding does not appear to see the video stream from the ingest application, ffprobe from my local machine does, sometimes:

> ffprobe rtmp://mydomain.com/ingest/ekobadd
...
Input #0, flv, from 'rtmp://mydomain.com/ingest/ekobadd':   0B f=0/0
  Metadata:
    |RtmpSampleAccess: true
    Server          : NGINX RTMP (github.com/arut/nginx-rtmp-module)
    displayWidth    : 1920
    displayHeight   : 1080
    fps             : 23
    profile         :
    level           :
  Duration: 00:00:00.00, start: 122.045000, bitrate: N/A
  Stream #0:0: Audio: aac (LC), 48000 Hz, stereo, fltp, 163 kb/s
  Stream #0:1: Video: h264 (High), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 1228 kb/s, 23 fps, 23.98 tbr, 1k tbn
     126.24 A-V: -1.071 fd=   0 aq=   54KB vq=  161KB sq=    0B f=0/0

Sometimes, however, it doesn't see the stream at all:

[rtmp @ 0000022d87d0fe00] Server error: No such stream
rtmp://mydomain.com/ingest/ekobadd: Operation not permitted

Testing the stream with VLC gives the same results.

Of course, the "live" application also doesn't have video. I have, however, streamed video from it before. I assume if I restart nginx enough, that the exec_push ffmpeg command will randomly see the video stream much like ffprobe does. I also have HLS and DASH configured, and they're both working perfect if you're a radio talk show host.

/etc/nginx/nginx.conf: (I'm quite sure I never touched anything in the HTTP section, but it's included just in case)

rtmp {
        server {
                listen 1935;
                chunk_size 8192;

                idle_streams off;

                application ingest {
                        live on;
                        record off;

                        # Transcode to h264/aac via flv, 1.2Mbps 24fps 44.1kHz, single audio channel video (HLS Ready)
                        exec_push ffmpeg -i rtmp://localhost/ingest/$name -b:v 1200k -c:v libx264 -c:a aac -ar 44100 -ac 1 -f flv -preset veryfast -tune zerolatency rtmp://localhost/live/$name 2>>/tmp/rtmp-ingest-$name.log;

                        allow publish <my ip address>;
                        deny publish all;

                        allow play all; # This was added for debugging.
                }

                application live {
                        live on;
                        record off;

                        hls on;
                        hls_path /var/www/mydomain.com/html/live/hls;
                        hls_fragment 6s;
                        hls_playlist_length 60;

                        dash on;
                        dash_path /var/www/mydomain.com/html/live/dash;

                        allow publish 127.0.0.1;
                        deny publish all;

                        allow play all;
                }
        }
}

http {

        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        types_hash_max_size 2048;
        server_tokens build; # Recommended practice is to turn this off

        server_names_hash_bucket_size 64;
        # server_name_in_redirect off;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # SSL Settings
        ##

        ssl_protocols TLSv1.2 TLSv1.3; # Dropping SSLv3 (POODLE), TLS 1.0, 1.1
        ssl_prefer_server_ciphers off; # Don't force server cipher order.

        ##
        # Logging Settings
        ##

        access_log /var/log/nginx/access.log;

        ##
        # Gzip Settings
        ##

        gzip on;

        # gzip_vary on;
        # gzip_proxied any;
        # gzip_comp_level 6;
        # gzip_buffers 16 8k;
        # gzip_http_version 1.1;
        # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

        ##
        # Virtual Host Configs
        ##

        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;
}

/etc/nginx/sites-available/mydomain.com:

server {
        listen 443 ssl;

        ssl_certificate     /etc/letsencrypt/live/mydomain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem;
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
        ssl_ciphers         HIGH:!aNULL:!MD5;

        root /var/www/mydomain.com/html;

        server_name mydomain.com www.mydomain.com;

        location / {
                root /var/www/mydomain.com/html/live;

#               add_header Cache-Control no-cache;
                add_header Access-Control-Allow-Origin *;
        }
}

types {
#       application/vnd.apple.mpegurl m3u8;
        application/dash+xml mpd;
}

Solution

  • The issue appears to have been resolved by placing interleave on; in both application blocks. I assume that this makes it impossible for audio and video data to arrive separately, and therefore much more difficult for a video player to misconstrue the number of streams in the data. It feels a bit hacky, because I still don't understand the issue, but it seems to have worked.