iOS Safari播放m3u8时如何检测video元素分片加载404错误
iOS Safari 原生video播放m3u8无法捕获分片404错误解决方案
iOS端Safari对原生HLS(m3u8)播放采用独立底层实现,分片加载失败(含分片404、中途断流、信号切断)的错误默认不会冒泡到<video>元素的标准error事件:播放器内部会默认发起数次重试,重试耗尽后直接卡停播放,不会对外抛出标准错误事件,这是Safari的已知实现差异,并非代码写法问题。
复现步骤
- 正常加载并播放m3u8流地址
- 播放过程中切断流传输信号,播放器停止播放,但
error事件始终不触发,无法执行错误兜底逻辑
测试参考代码
<!DOCTYPE html> <html> <body> <h1>The video autoplay attribute</h1> <video id="VIDEO" width="320" height="240" controls autoplay playsinline></video> <script> const linkPlay = "https://sgn-fpt-001-livecdn-vt.vieon.vn/7ed4de9c6e5740688d95878c8bd5a766/1654246367317/dvr_event/60b822a4-ef69-4886-b942-351ab352779a/playlist.m3u8" function init() { const video = document.getElementById("VIDEO") console.log(video) console.log(video.canPlayType('application/vnd.apple.mpegurl')) video.src = linkPlay video.load() video.addEventListener('error', (e)=> { console.log('error', e) }) } init(); </script> </body> </html>
可行解决方法
1. 无侵入兜底:等待状态超时检测(兼容性最好,支持所有iOS版本)
原生播放器在分片加载失败卡顿时,会触发waiting事件,且后续不会触发playing/canplay/timeupdate/progress这类播放/加载进度事件,可以基于这个逻辑做超时判断:
- 监听
waiting事件时启动计时器 - 只要触发
playing/canplay/timeupdate任意一个代表播放恢复的事件,就清空计时器 - 如果计时器超过阈值(建议设置为1015秒,即23个分片的总时长,可根据自身业务的分片时长调整)仍未被清空,就判定为流加载失败,执行错误处理逻辑
示例代码:
const video = document.getElementById("VIDEO") let errorTimer = null const ERROR_TIMEOUT = 12000 // 12秒超时阈值 // 启动错误检测 function startErrorDetect() { clearErrorTimer() errorTimer = setTimeout(() => { // 超时判定为加载失败,执行对应错误逻辑 console.log('流加载中断,触发错误处理') video.pause() // 可在此处添加错误提示、重试等业务逻辑 }, ERROR_TIMEOUT) } // 清除错误检测 function clearErrorTimer() { if (errorTimer) { clearTimeout(errorTimer) errorTimer = null } } // 绑定检测事件 video.addEventListener('waiting', startErrorDetect) video.addEventListener('stalled', startErrorDetect) video.addEventListener('playing', clearErrorTimer) video.addEventListener('canplay', clearErrorTimer) video.addEventListener('timeupdate', clearErrorTimer) // 保留原生error事件监听,捕获主列表加载失败等原生会抛出的错误 video.addEventListener('error', () => { clearErrorTimer() console.log('原生错误事件触发', video.error) })
2. 精准捕获错误:使用hls.js接管HLS解析(适用于iOS 17.1+版本)
iOS 17.1之后的Safari开放了HLS的MSE播放权限,可以引入hls.js关闭原生HLS接管,由JS层实现m3u8解析和分片加载,此时所有分片请求错误(404、超时、断流)都可以通过hls.js的ERROR事件精准捕获,不会出现原生不抛错的问题。
注意:iOS 17.1以下版本不支持该方案,仍需要搭配上述超时兜底逻辑使用。
注意事项
- 不要单独依赖原生
error事件处理HLS播放错误,该事件在iOS Safari原生HLS场景下,仅会在主m3u8列表加载失败、视频格式完全不支持这类初始化阶段的致命错误时触发,播放过程中的分片错误、断流绝大多数场景都不会触发该事件。 - 超时阈值不要设置过短(小于5秒),避免弱网下正常缓冲被误判为错误。
内容的提问来源于stack exchange,提问作者Trinh DL
相关产品推荐
相关产品推荐

