解决 iOS 18.3 播放 WebM 出错
发现问题
手机升级 iOS 18.3.2 后发现网站播放视频出错。表现为播放时骤停,失去响应。捕获error
事件,得到 code: 3(MEDIA_ERR_DECODE),message: "Media failed to decode"。
我对视频的处理是优先使用 WebM 格式,MP4 作为备用。因为 MP4 是被广泛支持的格式,不太可能出现解码问题,我自然怀疑问题出在 WebM。果不其然,移除 WebM 链接后播放恢复正常。
解决问题
知道问题所在,我很快写好了修复代码,判断系统是 iOS 时不使用 WebM。但是在提交之前我冒出了一个念头,这是 iOS 更新造成的兼容问题,我为什么要为苹果的错误买单,打一个丑陋的针对性的补丁呢?于是我继续折腾,用通用的思路做优化。
最终方案如下:
首次播放视频时使用 MP4;同时创建一个虚拟节点加载 WebM,捕获到error
判定为不支持,捕获到canplay
则为支持,写入全局变量;如果支持 WebM,则在后续播放视频时使用 WebM。
值得一提的是,因为 iOS 的严格限制,必须手动播放才能触发事件,所以上述方案在 iOS 不生效,即恒为不支持 WebM。从效果来看,等同于包含了第一种方案。
修复已经上线。iOS 各浏览器以及 macOS Safari 优先播放 MP4,其他 macOS 和 Windows 下的浏览器均能正常播放 WebM。
深挖问题
我不想就此止步,决定进一步深挖 iOS 18.3 带来 WebM 兼容问题的来龙去脉。
查看 iOS 18.3 之后的更新日志,与浏览器直接相关的是关于 WebKit 的更新内容:
Impact: Maliciously crafted web content may be able to break out of Web Content sandbox. This is a supplementary fix for an attack that was blocked in iOS 17.2. (Apple is aware of a report that this issue may have been exploited in an extremely sophisticated attack against specific targeted individuals on versions of iOS before iOS 17.2.)
Description: An out-of-bounds write issue was addressed with improved checks to prevent unauthorized actions.
影响:恶意制作的网页内容或许能够突破网页内容沙盒。这是针对 iOS 17.2 中阻止的某个攻击所做的补充修复。(有报告指出,在针对 iOS 17.2 之前的 iOS 版本上的特定目标个人所发起的极复杂攻击中,这个问题可能已经遭到利用;Apple 已知晓这一报告。)
描述:已通过改进检查解决越界写入问题,从而避免出现未授权的操作。
简单来说,此更新修复了 WebKit 安全漏洞。另据网上评论,解决了可能导致部分流媒体内容无法播放的问题。我合理怀疑 WebM 兼容性问题是被误伤。
基于我个人习惯,只会上传 MOV 和 MP4 两种视频文件。经后台程序调用 FFmpeg 转码为 WebM,视频编码器为 VP9(-c:v libvpx-vp9
),音频编码器为 Opus(-c:a libopus
)。
iOS 18.3.2 Safari canPlayType('video/webm;codecs="vp9,opus"')
返回probably
,但实际播放时又报解码错误,很显然是 BUG。但遗憾的是,我将测试手机升级到 iOS 18.4 beta 问题仍然存在,也就是说短期内苹果不会解决这个 BUG。
我进一步确认是否编码器的问题,所以用 VP8、VP9 和 Opus、Vorbis 两两配对生成 4 组文件,问题相同。
最后我尝试在 iOS Safari 直接访问 WebM 文件地址,可以唤起原生视频播放器正常播放。非嵌入式<video>
(不加playsinline
)也可以唤起播放器播放。不过这两种情形都是被播放器接管,已经脱离浏览器范畴。这证明了新版 iOS 支持 WebM 播放,但是浏览器不支持。
至此可以断定 WebKit 改动影响了 WebM 兼容性。