量化视频封装的成本

2019-07-01 16:05:25 浏览数 (1)

不必要的封装信息占用了可观的空间,如果能优化这些封装信息,就能进一步压缩视频,提升用户的观看体验。本文来自Mux科技博客,LiveVideoStack对原文进行了摘译。

文 / MatthewSzatmary

译 / John

原文:

https://mux.com/blog/quantifying-packaging-overhead-2/

Mux可使您就像调用单个API一样轻松在您的应用或网站上添加视频,实现这种简易操作需要多项可分析视频内容并将其转换为具有出色播放兼容性的媒体文件或数据流的处理步骤,这些步骤一般都十分繁琐且庞大,我们将其按一定顺序组成的集合称为媒体处理流程。

处理流程主要是对每个音频或视频帧执行的一系列数据分析或转换。不同阶段对应不同的帧处理步骤,某一阶段步骤结束之后下一阶段步骤被执行操作,多步骤所组成的简化处理流程如下图所示:

这些步骤中的每一个都值得深度发掘,但今天我们主要关注处理流程中经常被忽视的一项——封装。

封装器的主要工作是获取音频和视频编码器的输出并插入如果按照正确速率播放媒体所需的时间戳与信令等信息,同时还要确保音频与视频的同步性。最终得到被封装在“容器”中的文件或流并允许播放器成功打开与访问数据,如mp4或HLS格式文件。

几年前,Apple在HLS中添加了对分片mp4文件的支持,但并非所有设备都能获得这一新特性。因此,大多数流仍然使用较旧的传输流(通常称为TS)格式。TS似乎是一种令人费解的格式,但对于广播或有线电视领域的从业者来说这种格式无处不在。而无处不在也意味着硬件解码器普遍对TS有良好的兼容性与支持,如果让我推测,这也就是为什么Apple在第一代iPhone中普遍选择TS而非HLS,以及为什么TS在今天仍然非常普遍。

TS有一些不同寻常的特性。由于其本质上是为以太网之前的世界构建,包括丢失、乱序数据封装检测以及远程时间同步等数字无线广播必需的功能在互联网上仅需借助TCP与每个设备中的高精度时钟之间的协作即可处理;除此之外,TS还使用188字节的固定封装大小,每个封装包以同步字节开始,以便于识别初始封装。(这种设计如果用于在随机位置加入多条播放的数据流,即可获得良好效果,例如切换电视频道时;但就像HLS的情况一样,这对于通过HTTP拉取数据流并以文件形式保存视频的互联网视频传输来说并非必需。而不使用这些功能的缺陷就是存储空间被白白占用。对于具有高码率的文件而言这不是问题,但对处于低带宽环境中的服务来说,却意味着高昂的成本。

每个188字节的TS包具有4字节的标头(header)。该标头包含同步字节、一部分标志位、封装的ID(或具有唯一标识的音频或视频流 PID)以及连续性计数器(用于识别丢失或无序的包)。然后每个帧都有一个前置的Packetised基本流(PES)标头。PES标头最少为14个字节(如果帧解码时间与呈现时间不匹配,则为19个字节,即B帧),并会对帧时间戳进行编码等。因此,第一个数据包最多可用170个字节,而后续数据封装包有184个字节可用。如果帧少于170个字节,则必须对其进行填充以使用完整数据包。如果帧是171字节,则需要第二个数据封装包,因此需要376个字节(188x2)来传输171个字节的有效负载,这会将所需带宽增加一倍以上。实际上,170字节以下的帧并不常见。但是,在1Mbps以下的比特率下,10%或更多的(Overhead)开销并不罕见。

一个现实世界的例子

我们拍摄了一段测试视频,使用以下命令通过FFmpeg将其编码为HLS:

代码语言:javascript复制
ffmpeg -i tears_of_steel_720p.mp4 -vcodec libx264 -preset faster -x264opts keyint=120:min-keyint=120:scenecut=-1 -b:v 500k -b:a 96k -hls_playlist_type vod ffmpeg/ffmpeg.m3u8

最终组合流大小为58196152字节,封装开销(overhead)为6.24%。考虑到2.13%(184/188)是理论上的最小值且折扣PES标题和填充,实际表现并没有那么糟糕。

但我们能做得更好吗?如果可以,我们希望节省的码率可用于降低缓冲以改善视频质量继而改善用户体验。但任改善实践的第一步是确定如何衡量封装开销。已注册的Apple开发人员可以访问HTTP Live Streaming Tools等工具,这些工具存在两个问题:第一是仅支持MacOS,第二是最新版本似乎不再显示封装开销。为了解决这个问题,我们开源了我们的muxincstreamvalidator工具(https://github.com/muxinc/hlstools)。尽管在编写初期,此工具仅报告封装开销,但其后续版本中可能会扩展更多功能。以上是用于衡量FFmpeg封装开销的工具。

为减少封装开销,我们可以利用编码媒体码流的一些属性。大多数音频编解码器使用固定的采样率和per-frame的采样数进行编码。AAC音频则固定每帧使用1024个样本。因此,在48000Khz时,每帧持续21⅓毫秒。因为帧持续时间可以由解码器确定而其中不包含来自PES帧头的时间戳,所以我们可以为每个PES标头打包多于一个的音频帧,从而减少PES开销与最小化帧的最终TS分组所需的填充。但是,这里的视频帧中并没有可导出的时间戳,因此打包不起作用。MPEG视频编解码器确实包含用于识别每个帧的第一个字节,被称为起始码的特定比特序列。因此,解码器不需要容器发送信号以通知每帧开始时流中的确切位置。当有一个小于184字节的最终有效载荷需要填充时,我们可以截断那些额外的字节,采用零填充策略并将字节前进到下一帧。不幸的是,对于170字节以下的视频帧,我们仍然无法做到这一点。

Mux的代码转换器使用但不限于使用这些技术以将开销降至最低。我们将相同的 tears_of_steel_720p.mp4 视频摄取到Mux的muxincstreamvalidator工具中并测量其开销。

传输流包含4个PID,其中PID 0始终是程序关联表(PAT),其编码节目映射表(PMT)的PID在这种情况下为4096;PMT对音频(257)和视频(256)流的PID进行编码,由于不包含媒体只包含元数据,PAT和PMT的开销为100%。最终流为55330092字节,开销为3.32%。理论最小值更接近2.12%。

为了确保这是一个同类比较,我们使用FFmpeg重新混合Mux编码流并测量结果。

代码语言:javascript复制
ffmpeg -i ./mux/manifest.m3u8 -codec copy -hls_playlist_type vod remux/remux.m3u8

FFmpeg包含一个额外的“服务”PID(17),除了额外1713244字节的开销,其他看上去差别不大类似。

我们尝试了一项实验,通过增加既定百分比的码率生成相似且效率较低但视频质量得到明显改善的封装文件,最终结果的VMAF评分低于3分,我们可以认为这改善了视觉质量。因此,通过节省一部分处理来改善网络环境较差的网络边缘地区用户的产品使用体验似乎是一项不错的选择。

LiveVideoStack 招募

LiveVideoStack正在招募编辑/记者/运营,与全球顶尖多媒及技术专家和LiveVideoStack年轻的伙伴一起,推动多媒体技术生态发展。了解岗位信息请在BOSS直聘上搜索“LiveVideoStack”,或通过微信“Tony_Bao_”与主编包研交流。同时,我们也欢迎通过业余时间向LiveVideoStack贡献内容。

0 人点赞