HLS.js播放实时HLS流时,新增.ts文件触发页面频繁刷新问题
RTSP转HLS实时直播页面频繁刷新问题解决思路
问题场景
将实时RTSP流转换为HLS格式在浏览器播放,通过Python子进程执行FFmpeg命令完成转码。关闭子进程后,播放已生成的文件一切正常;但子进程运行、实时更新index.m3u8时,每当有新的.ts片段加入,直播页面就会触发刷新。
使用的FFmpeg命令
command_string ="ffmpeg -fflags nobuffer -report \ -loglevel debug \ -rtsp_transport tcp \ -re -i rtsp://username:password@192.168.12.43:554/stream1 \ -vsync 0 \ -vcodec copy \ -movflags frag_keyframe \ -f hls \ -hls_time 4 \ -hls_list_size 0 \ -force_key_frames \"expr:gte(t,n_forced*10)\" \ -hls_segment_type mpegts \ -hls_segment_filename public\%d.ts \ public\index.m3u8"
生成的index.m3u8内容
#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:6 #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:5.973744, 0.ts #EXTINF:4.015867, 1.ts #EXTINF:3.997500, 2.ts #EXTINF:3.999844, 3.ts #EXTINF:4.000000, 4.ts #EXTINF:4.012889, 5.ts
前端HLS.js实现代码
<!DOCTYPE html> <html lang="en"> <head> <!-- <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script> <link href="https://unpkg.com/video.js/dist/video-js.css" rel="stylesheet"> <script src="https://unpkg.com/video.js/dist/video.js"></script> --> <meta charset="utf-8" /> <script src="https://cdn.jsdelivr.net/npm/hls.js@1"></script> <!-- manifest.json provides metadata used when your web app is installed on a user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ --> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <title>React App</title> </head> <body> <!-- <noscript>You need to enable JavaScript to run this app.</noscript> --> <video id="video" controls autoplay></video> <div id="root"></div> </body> <script> if (Hls.isSupported()) { var video = document.getElementById('video'); var hls = new Hls(); hls.on(Hls.Events.MEDIA_ATTACHED, function () { console.log('video and hls.js are now bound together !'); }); hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) { console.log( 'manifest loaded, found ' + data.levels.length + ' quality level' ); }); hls.loadSource('index.m3u8'); // bind them together hls.attachMedia(video); // video.play() } </script> </html>
问题原因分析
- FFmpeg的m3u8写入方式:默认情况下,FFmpeg更新HLS播放列表时会先写入临时文件,再替换原
index.m3u8文件。这种替换操作会导致浏览器检测到文件内容突变,触发HLS.js重新加载整个播放列表,进而引发页面刷新。 - 关键帧与片段间隔不匹配:命令中
-hls_time 4设置每4秒生成一个片段,但-force_key_frames "expr:gte(t,n_forced*10)"每10秒才强制生成关键帧,导致部分片段开头无关键帧,HLS.js在切换片段时需等待关键帧,可能引发播放中断或刷新。 - HLS.js配置缺失:未显式配置manifest自动刷新策略,或默认刷新逻辑在文件替换时兼容性不佳。
解决方案
1. 调整FFmpeg的HLS写入策略
添加-hls_flags append_list+delete_segments参数,让FFmpeg直接在原m3u8文件末尾追加新片段,避免文件替换操作;同时将关键帧间隔调整为与片段时长一致,确保每个片段开头都是关键帧:
command_string ="ffmpeg -fflags nobuffer -report \ -loglevel debug \ -rtsp_transport tcp \ -re -i rtsp://username:password@192.168.12.43:554/stream1 \ -vsync 0 \ -vcodec copy \ -movflags frag_keyframe \ -f hls \ -hls_time 4 \ -hls_list_size 0 \ -force_key_frames \"expr:gte(t,n_forced*4)\" \ -hls_segment_type mpegts \ -hls_flags append_list+delete_segments \ -hls_segment_filename public\%d.ts \ public\index.m3u8"
2. 优化HLS.js配置
显式配置manifest自动刷新间隔及直播相关参数,提升播放稳定性:
if (Hls.isSupported()) { var video = document.getElementById('video'); var hls = new Hls({ manifestUpdateInterval: 1000, // 每秒刷新一次播放列表 liveSyncDurationCount: 3, // 同步最近3个片段 liveMaxLatencyDurationCount: 10, // 最大延迟不超过10个片段 manifestLoadingMaxRetry: 5, manifestLoadingRetryDelay: 1000 }); hls.on(Hls.Events.MEDIA_ATTACHED, function () { console.log('video and hls.js are now bound together !'); }); hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) { console.log( 'manifest loaded, found ' + data.levels.length + ' quality level' ); video.play(); }); hls.loadSource('index.m3u8'); hls.attachMedia(video); }
3. 配置HTTP服务器缓存策略
确保服务器对index.m3u8文件返回Cache-Control: no-cache响应头,避免浏览器缓存旧的播放列表,保证每次都能获取最新的片段信息。
内容的提问来源于stack exchange,提问作者debugehlot
相关产品推荐
相关产品推荐

