【第3204期】基于WebCodecs的网页端高性能视频截帧
前言
介绍了基于 WebCodecs 的网页端高性能视频截帧方案,通过对视频文件的元数据读取、寻帧和整体过程进行解析,实现了高效的视频截帧功能。相比过去的方案,WebCodecs 截帧速度更快,内存占用有所降低,提升了用户体验和性能表现。今日前端早读课文章由 @张锋分享,公号:哔哩哔哩技术授权。
正文从这开始~~
业务介绍
web 投稿页是 B 站的主要投稿来源,有很多高粉 UP 主使用 web 端进行投稿。
封面部分是投稿过程中耗时占比较高的步骤,因此在过去,web 投稿页已上线了自动的封面截取 & 推荐功能,有效提升了用户体验。同时在此过程中有了一定的技术积累。
自动封面功能依赖于对用户上传视频进行截帧的能力,最简单的方式是在上传完成之后由服务端进行视频截帧并返回推荐的候选封面,但显然这一步会有大量的等待时间,因此我们采用的是纯前端视频截帧能力。
实际上在 web 投稿页有多处需要截帧的地方:
封面推荐:截取多张低清图在前端进行 AI 打分,基于打分结果截取最多 10 张高清图供 UP 主选择
封面选帧:对默认推荐的帧不满意,手动获取准确时间点的帧画面
分区 & 话题推荐:从视频中截取多帧,打包上传至后台进行分析后返回推荐结果
过去方案
过去 web 投稿页采取两套视频截帧方案,wasm 优先,canvas 兜底
Video + Canvas
流程
Video 标签 --> 设置 video 时间
canvas context 2d,
drawImage()
直接成图
优点
开发简单:利用浏览器内部的视频播放器能力
缺点
无法进行错误处理,有时会黑屏,但不报错
不同浏览器有形态各异的表现,速度和可用性难以保证
播放器本身的缓存或预加载等机制带来性能浪费
WebAssembly + FFmpeg
流程
FFmpeg API 调用 + 数据传递为主
视频文件解封装
逐个读取关键帧图像数据
数据层层传递
web 端进行图像渲染(webgl /canvas)
优点
视频支持性好:几乎支持所有市面上可见的视频格式(行业标杆)
缺点
性能损耗大:相比 canvas 截帧慢;
内存消耗大:早期的 wasm 功能甚至会导致页面崩溃;
开发门槛高,需要了解 ffmpeg lib 的使用方式,要写 C 代码,需要手动构建各类基础库
现状:截帧成功率 97% 左右,封面推荐耗时(去掉极端数据)
平均:8.4s
50 分位:16s
90 分位:19s
WebCodecs 是什么
WebCodecs 于 21 年 9 月份推出,是用于在 web 页面上对音视频进行底层操纵(如编解码)的 API。
【第3176期】WebCodecs 开启 Web 音视频新篇章
WebCodecs 是相对底层的 API,准确来说是为有音视频开发基础的人准备的,对前端同学来说有一定的门槛。
在使用 FFmpeg 时可直接调用包装好的方法,主要门槛在于 wasm 环境的配置和构建。而使用 WebCodecs 时则需要基于编解码的原理手动实现功能。或许后续 WebCodecs 将会推出更加上层的 API。
所以在进一步介绍 WebCodecs 截帧方案之前,我想先介绍一些视频处理的入门知识,感兴趣的可以参考附录中的链接进一步学习。
MP4 的入门知识
视频处理的基本概念
编码 / 解码:
视频的编码是将原始的图像信息进行变换压缩等处理,方便传输并保证图像质量。解码则是将压缩后的文件还原成视频需要的一连串图像
常见的编码格式:H.265; mpeg4; vp9 ……
封装 / 解封装:
一个视频文件可能包含多个音频和视频流,通过封装格式将他们聚合在一起,在使用时按照规则逐步解析
常见的封装格式:mov,mp4,m4a,3gp,3g2; matroska; flv; avi ……
在这里简单介绍下.mp4 文件常用的 h264 编码以及 MP4 封装
编码 - 帧内编码(以 JPEG 图片压缩算法为例)
利用人眼的生物特性结合数学方法进行数据压缩,并确保图片质量。主要步骤:
具体流程在这就不展开了,总之,经过压缩后图片的文件大小将有非常显著的缩小:
压缩前:
压缩后:
原图大小:1620*1080*3/1024/1204
= 4.25MB ----> 编码后大小:856KB
PS:效果仅供参考,两者皆为经过 JPEG 压缩的图片,只不过压缩比不同
编码 - 帧间编码
尽管经过帧内编码的压缩,图片已经有了很明显的体积减少,但存储视频的每一帧是依然是很不明智的行为。因此需要帧间编码。
通常有两种方式进行帧间编码:动态补偿 + 帧间差异
动态补偿
通常,两个连续的帧之间是存在相同部分的,只是位置发生了变化因此可以通过存储 块的索引 + 偏移量(向量)以减少存储体积
帧间差异
仅有动态补偿还不够还原每一帧的画面,还需要通过两帧之间的 diff 帧来辅助还原
diff 帧的画面通常信息量比较低,因此通过帧内压缩会获得很高的压缩比
使用这两种方法,结合上一帧参考帧,便可以获得当前帧了
不同的帧类型
对应的,产生了三种帧类型
I 帧:俗称的关键帧,仅使用了帧内编码,可以被独立还原为图像
P 帧:帧的图像还原依赖前一帧的解码结果
B 帧:帧的图像还原依赖前一帧与后一帧的解码结果
帧的展示顺序与解码顺序可能是不一样的
封装
MP4 封装文件基本结构:所有数据存放在 box 中
WebCodecs 截帧方案
设想一个问题:只使用一个编程语言的基本 API,如何最高效地获取一个.mp4 文件中的某一个时间点所在的图像?
在了解了上面的基本知识后,我们可以分 4 步解决这个问题:
不同于播放器:截帧不需要预解码缓存等步骤。为了保证性能,需要多少数据拿多少,拿多少处理多少,避免多余的文件读取和解析造成性能和内存的浪费。
元数据读取 & 解析
读取文件头部 8byte 的数据,按照 box 的 header 规则逐个获取各 box 的位置以及大小
PS:moov 可能在文件的末尾,顺序不固定
将 moov box 所在文件块切片,提供给解封装器解析,获取到:
该视频的详细编码参数
所有帧的索引信息
寻帧
策略:帧的时间戳并不是连续的的 → 某个时间点对应的帧可能并不存在 → 使用距离最近的帧
获取到最近的关键帧和非关键帧之后,则要根据截帧的需求提供不同的文件块给解码器解码
只提供关键帧速度更快,适合精度不高的场景(封面推荐),准确截帧适合精度要求高的场景(封面选帧)
【第2909期】基于FFmpeg和Wasm的Web端视频截帧方案
整体过程
由于解封装器 (mp4box.js) 和解码器 (WebCodecs-VideoDecoder) 本身为流式设计,优先服务于流式的应用场景(如直播视频流,点播视频流,需要通过网络请求分块获取到文件内容)。而视频截帧是一个本地场景,已经有了完整的文件。且视频截帧的 API 最好是类似同步的方式,在一个方法调用中完成所有的帧截取,并一起返回。
因此设计了通过事件抛出以及定时器机制以达到对内部流式依赖库的包装。
同时将计算密集的解封装、解码、渲染工作挡在独立的 web worker 中执行,确保宿主页面运行流畅不受影响。
性能分析
本地测试:
测试机上模拟了 web 投稿页场景,对 WebCodecs / WebAssembly / Canvas 三种截帧方式的性能进行了测试。
测试样本:720p 视频 2 个,1080p 视频 3 个,2k 视频 1 个,4k 视频 3 个
测试环境:2020 M1 MacBook pro, 公司测试 windows 本(i5-1135G7 1.38~2.40GHz)
测试方式:在不同测试机上对每个视频跑三次测试用例,共 81 次
测试用例:模拟 web 投稿页截帧流程,数量,分辨率保持相同
实际场景中:视频的编码,分辨率,压制参数等都会对截帧性能有影响,在这里以分辨率进行粗略的分类
线上数据:
总结:
随着视频规格的提升,webcodecs 的截帧速度为 wasm 和 canvas 的 2.5~5 倍
提前 3~13s 完成页面所需的截帧任务,用户能够更快的看到推荐结果
在内存消耗上有一定的降低
WebCodecs 截帧方案的优点 & 缺点
优点
速度很快,受视频规格影响小
读取文件少
内存占用有一定降低,且表现稳定
缺点
依赖解封装器的实现,当前使用了 mp4box.js 作为解封装器,约能覆盖 95% 的视频
目前仅 mp4 和 webm 的解封装器较完善
WebCodecs 浏览器支持性一般,当前为 85% 左右
规划
作为 web 投稿页首选截帧方式,根据线上表现做进一步优化
其他封装格式的视频支持:支持 webm 封装格式(已支持,且开源了 mkv demuxer)
开源
附录
1、jpeg 压缩算法介绍:
B 站:https://www.bilibili.com/video/BV1TZ4y1S7iG
知乎:影像算法解析 ——JPEG 压缩算法 - 知乎(https://zhuanlan.zhihu.com/p/40356456)
2、视频编码介绍:https://www.youtube.com/watch?v=QoZ8pccsYo4
3、不同的帧类型:I, P, and B-frames - Differences and Use Cases Made Easy - OTTVerse:https://ottverse.com/i-p-b-frames-idr-keyframes-differences-usecases
4、codec string 的含义([avc1.4d0033] 代表什么):Codecs in common media types - Web media technologies | MDN(https://developer.mozilla.org/en-US/docs/Web/Media/Formats/codecs_parameter#using_the_codecs_parameter)
5、MP4 封装类型介绍:mp4 封装格式各 box 类型讲解及 IBP 帧计算 - 知乎:https://zhuanlan.zhihu.com/p/457888765
6、在线 MP4 解析工具:Online Mp4 Parser:https://www.onlinemp4parser.com/
7、WebCodecs 官方说明:WebCodecs:https://w3c.github.io/webcodecs/#videodecoder-interface
8、WebCodecs 代码示例:https://github.com/w3c/webcodecs
关于本文
作者:@张锋
原文:https://mp.weixin.qq.com/s/K41ctiIVPuvZ2XE1xyD1xQ
这期前端早读课
对你有帮助,帮” 赞 “一下,
期待下一期,帮” 在看” 一下 。