nginx-rtmp-module icon indicating copy to clipboard operation
nginx-rtmp-module copied to clipboard

Why is my HLS stream infinitely loading on iOS 15 safari but works fine on iOS 14?

Open speekadievs opened this issue 3 years ago • 6 comments

So I have a small website that shows different streams from web cameras around the city. (ex: https://camstream.alteco.lv:8443/live/camera1.m3u8). The stream can be viewed here: https://camstream.alteco.lv/camera/76d4b7f895df

This is a simple page with just the video player trying to play the stream using hls.js where it can be used and native

All was working well until iOS 15 rolled out which broke the streams, so they are not viewable anymore. It simply shows that it's loading but nothing happens. Interestingly enough, that if I try to open the video in full screen and try seeking, the video instantly shows up. I also checked the incoming .m3u8 and .ts files using Inspect Element and everything seems to be fine.

At first, I thought that the issue is with the stream itself, but that doesn't seem to be the case, as I've tried all kinds of different options and profiles (baseline, main, high) but nothing changes, so it almost feels like a bug with the safari video player, but other streams from different sites I've found work fine. I've also tested the stream using the VLC app on iPhone and it works fine there. It only doesn't work on Safari.

I'm using nginx with the nginx-rtmp module to server the stream to clients.

daemon off;

error_log /dev/stdout info;

events {
    worker_connections 1024;
}

rtmp {
    server {
        listen 1935;
        chunk_size 4000;

        application stream {
            live on;

            exec ffmpeg -i rtmp://localhost:1935/stream/$name
              -c:a aac -c:v libx264 -vf yadif -b:v 1100k -f flv -g 60 -r 30 -s 1280x720 -force_key_frames expr:gte(t,n_forced*2) -preset superfast -profile:v main rtmp://localhost:1935/hls/$name_720p2628kbs
              -c:a aac -c:v libx264 -vf yadif -b:v 600k -f flv -g 60 -r 30 -s 854x480 -force_key_frames expr:gte(t,n_forced*2) -preset superfast -profile:v main rtmp://localhost:1935/hls/$name_480p1128kbs
              -c:a aac -c:v libx264 -vf yadif -b:v 300k -f flv -g 60 -r 30 -s 640x360 -force_key_frames expr:gte(t,n_forced*2) -preset superfast -profile:v main rtmp://localhost:1935/hls/$name_360p878kbs;
        }

        application hls {
            live on;
            hls on;
            hls_fragment_naming system;
            hls_fragment 6s;
            hls_path /opt/data/hls;
            hls_datetime system;
            hls_nested on;

            hls_variant _720p2628kbs BANDWIDTH=2628000,RESOLUTION=1280x720;
            hls_variant _480p1128kbs BANDWIDTH=1128000,RESOLUTION=854x480;
            hls_variant _360p878kbs BANDWIDTH=878000,RESOLUTION=640x360;
            #hls_variant _240p528kbs BANDWIDTH=528000,RESOLUTION=426x240;
            #hls_variant _240p264kbs BANDWIDTH=264000,RESOLUTION=426x240;
        }
    }
}

http {
    server {
        listen 80;

        listen 443 ssl;

        ssl_certificate /etc/nginx/ssl/fullchain.pem;
        ssl_certificate_key /etc/nginx/ssl/privkey.pem;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

        location /hls {
            types {
                application/vnd.apple.mpegurl m3u8;
                video/mp2t ts;
            }
            root /opt/data;
            add_header Cache-Control no-cache;
            add_header Access-Control-Allow-Origin *;
        }


        location /live {
          alias /opt/data/hls;
          types {
              application/vnd.apple.mpegurl m3u8;
              video/mp2t ts;
          }
          add_header Cache-Control no-cache;
          add_header Access-Control-Allow-Origin *;
        }


        location = /crossdomain.xml {
            root /www/static;
            default_type text/xml;
            expires 24h;
        }
    }
}

The code for the player page is also dead simple

<video id="video" autoplay muted controls playsinline preload="metadata"></video>

    <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
    <script src="//code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
            crossorigin="anonymous"></script>

<script>
$(document).ready(function () {

        var video = document.getElementById('video');

        if (Hls.isSupported()) {

            var hls = new Hls();
            hls.loadSource('{{$camera->m3u8}}');
            hls.attachMedia(video);
            hls.on(Hls.Events.MANIFEST_PARSED, function () {
                video.play();
            });
            hls.on(Hls.Events.MEDIA_ATTACHED, function () {
                //can we get cam on load?
                setTimeout(function () {
                    fitToScreen()
                }, 500);
            })
        } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
            console.log("No HLS support. Switching to native <video>")

            video.src = '{{$camera->m3u8}}';
            video.addEventListener('loadedmetadata', function () {
                console.log("loadedmetadata");

                video.play();
            });
        }

        $(window).resize(function () {
            fitToScreen()
        }).resize();

        setInterval(function () {
            fitToScreen()
        }, 3000);
    })
</script>

I've also tried switching to video.js but that didn't help. The same issue happened.

I've been trying to resolve this issue for the last 4 days without any success, so I'm hoping that someone has encountered something like this which could point me in a direction where to look at

speekadievs avatar Jan 06 '22 22:01 speekadievs

I also noticed this issue #1649 and tried to rebuild the nginx-rtmp module with this pull request and I've also added the hls_datetime directive, but that didn't help. The problem still persists

speekadievs avatar Jan 06 '22 22:01 speekadievs

Just a suggestion : try to remove the "RESOLUTION" property from "hls_variant", maybe the problem comes from that. It worked for me.

samihamine avatar Feb 12 '22 10:02 samihamine

Hello I had similar problem. I had a nginx-rtmp container with image alfg/nginx-rtmp, based in alpine linux. I tryed solve the problem using others nginx-rtmp docker container, all this images are based in alpine linux. I solved the problem creating new image based in ubuntu linux and in the nginx.conf configuration I changed the command push for exec ffmpeg. If I not change push command for exec ffmpeg, the problem is not solved. I hope help to you and other peoples, I was many time for solve this.

My scenary is:

CAMS RTMP/RTSP --> SERVER 1 (only for receive live image of cams and proces with ffmpeg) --> SERVER 2 (receibe live image from SERVER1 and streaming live for users)

I needed change to ubuntu in SERVER1 and SERVER2

Regards

fredy-pc avatar Feb 28 '22 17:02 fredy-pc

Hello! I am having the same exact issue. Was this issue ever solved?

devenreilly avatar Aug 30 '22 16:08 devenreilly

Strangely enough the iPhone seems to load the HLS video stream if you suddenly stop streaming to RTMP via ffmpeg. It looks like the iPhone is getting the stream files with no issue just not displaying them

devenreilly avatar Aug 30 '22 17:08 devenreilly

The issue is still there. It is connected to the directive "hls_datetime system;". To fix it I used this fork: https://github.com/sergey-dryabzhinsky/nginx-rtmp-module

vitadostal avatar Feb 05 '23 10:02 vitadostal