为什么我的 HLS 流在 iOS 15 safari 上无限加载,但在 iOS 14 上工作正常?

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

所以我有一个小网站,显示来自城市周围网络摄像机的不同流。 (例如:https://camstream.alteco.lv:8443/live/camera1.m3u8). The stream can be viewed here: https://camstream.alteco.lv/camera/76d4b7f895df

这是一个简单的页面,只有视频播放器尝试使用 hls.js 可以使用的流和用于 iOS 设备的本机 <video> 标签播放流。

一切正常,直到 iOS 15 推出中断了流,因此它们不再可见。它只是表明它正在加载,但没有任何反应。有趣的是,如果我尝试全屏打开视频并尝试搜索,视频会立即显示出来。我还使用 Inspect Element 检查了传入的 .m3u8 和 .ts 文件,一切似乎都很好。

起初,我认为问题出在流本身,但似乎并非如此,因为我尝试了各种不同的选项和配置文件(基线、主要、高)但是没有任何变化,所以它几乎感觉像是 safari 视频播放器的错误,但我发现来自不同站点的其他流工作正常。我还在 iPhone 上使用 VLC 应用程序测试了流,它在那里工作正常。它只在 Safari 上不起作用。

我正在使用带有 nginx-rtmp 模块的 nginx 来为客户端提供流服务。

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_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;
        }
    }
}

播放器页面的代码也非常简单

<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>

我也试过切换到 video.js,但没有用。发生了同样的问题。

过去 4 天我一直在尝试解决这个问题,但没有成功,所以我希望有人遇到过类似的事情,这可以为我指出一个方向

最后用nginx-rtmp模块解决不了问题,干脆换成Node-Media-Server https://github.com/illuspas/Node-Media-Server

有了这个,流在所有 iOS 版本上都能很好地工作

我遇到了类似的问题,我是这样解决的:

我有一个 nginx-rtmp 容器,图像 alfg/nginx-rtmp,基于 alpine linux。我尝试使用其他 nginx-rtmp docker 容器解决问题,所有这些图像都基于 alpine linux.

我通过基于 ubuntu linux 创建新图像解决了这个问题,在 nginx.conf 配置中我更改了 exec ffmpeg 的命令推送。

如果我不更改 exec ffmpeg 的 push 命令,问题没有解决。

我的场景是:

CAMS RTMP/RTSP --> SERVER 1(仅用于接收摄像头的实时图像和使用 ffmpeg 进行的处理)--> SERVER 2(从 SERVER1 接收实时图像并为用户直播)

我需要在 SERVER1 和 SERVER2

中更改为 ubuntu