作者简介
孙龙波,携程内容信息研发部 Native 开发 leader。目前主要负责携程攻略,行程,视频直播等项目的前端开发和团队管理。
一、前言
随着抖音,快手等APP的迅猛发展,短视频在移动端的地位越来越突出。而视频压缩是视频传输中很关键的一步。
本文会通过一个示例引入视频的一些基本概念并做稍微深入的介绍,最终给出在iOS上实现自定义码率和分辨率的视频压缩方案。这篇文章同时也是一个大杂烩,对于很多首次接触视频领域的同学是一个不错的入门文章。
二、 传统视频压缩方式的缺陷
1、传统压缩的实现
产品需求:不管原视频的清晰度如何,压缩后的视频码率和分辨率是一样的。大家首先想到的应该是iOS在AVFoundation中已经提供了简单的视频压缩方法,示例代码如下:
正常情况下这段代码不会出现任何问题,但是大家可以用下面的视频做个测试,链接: https://pan.baidu.com/s/1wLVbDFtzROVPo8T1qw6MXA 密码: ij7d。
结果会发现原视频分辨率1080x608,大小 90M,经过上面的代码压缩后变成了分辨率960x540, 大小147M!分辨率降低但是文件大小增加了! 输出的日志如下:
2、压缩参数分析
问题出在哪里?这个视频有什么特殊的地方?我们尝试用mediainfo工具查看压缩前后两个视频的详细参数。
原视频参数信息
压缩后的视频参数:
3、视频参数详解
首先我们要清楚截图中几个关键指标的含义。
1)码率(bit rate)是指数据传输时单位时间传送的数据位数,单位是bit per second(bps)。简单的说码率=视频文件大小/视频时长。
2)帧率(frame rate)指每秒钟有多少个画面,单位Frame Per Second简称FPS。视频实际是由一组连续的图片组成的,由于人眼有视觉暂留现象,画面帧率高于16的时候大脑就会把图片连贯成动画,高于24大脑就认为是非常流畅了。所以24FPS是视频行业的标准。
但这并不是人眼的极限,帧率继续提高能获取更好更流畅的体验,直到人眼无法区别(极限因人而异,美国空军曾做过一项测试,极限大概是220FPS,正常人远低于这个数字)。所以游戏行业为了更逼真的效果获取更好的用户体验将标准定为30FPS
3)分辨率:习惯上我们说的分辨率是指图像的高/宽像素值,严格意义上的分辨率是指单位长度内的有效像素值ppi(每英寸像素Pixel per inch)。差别是,图像的高/宽像素值和尺寸无关,但单位长度内的有效像素值ppi和尺寸就有关了。比如,同样Width x Height的图片,尺寸越大ppi越小。
4、视频编码标准
解释完上面几个概念大家可以得出比较直观的结论,帧率相同的情况下(压缩前后都是30FPS),分辨率越高码率越大,但是截图的中的参数显示码率大的分辨率低。仔细对比两个视频的参数会发现唯一有区别的是 Format profile,这个参数才是问题的根源。
在介绍这个参数之前需要了解另一个概念,H264视频编码。所谓视频编码方式就是指通过特定的压缩技术,将某个视频格式的文件转换成另一种视频格式文件的方式。
如果视频不编码会出现什么后果?我们来计算一下,以原视频为例,每秒钟包含了30张1080x600的图片,那一秒钟的视频大小应该是 1080x600*30/(1024*1024*8) = 2.3 MB. 这个视频有3分42秒 ,文件大小应该是 2.3*222 = 510MB 远超过95M。既然编码是必须的那编码标准有哪些呢?
国际上制定视频编解码技术的组织有两个,一个是“国际电联(ITU-T)”,它制定的标准有H.261、H.263、H.263+等,另一个是“国际标准化组织(ISO)”它制定的标准有MPEG-1、MPEG-2、MPEG-4等。
而H.264则是由两个组织联合组建的联合视频组(JVT)共同制定的新数字视频编码标准,所以它既是ITU-T的H.264,又是ISO/IEC的MPEG-4高级视频编码(Advanced Video Coding,AVC)的第10 部分。所以大家在用不同工具查看同一个视频时有时候会显示AVC有时候会显示H.264实际是同一种编码方式。
5、H264编码详解
而H264最大的优势就是低码率情况下提供高质量的视频图像。怎么做到的?这个问题比较复杂可以新开一篇文章来专门介绍了。有兴趣的大家可以看一下这篇介绍:http://read.pudn.com/downloads147/ebook/635957/%E6%96%B0%E4%B8%80%E4%BB%A3%E8%A7%86%E9%A2%91%E5%8E%8B%E7%BC%A9%E7%BC%96%E7%A0%81%E6%A0%87%E5%87%86H.264.pdf
总的来说编码流程可以分为五部分:帧间和帧内预测(Estimation)、变换(Transform)和反变换、量化(Quantization)和反量化、环路滤波(Loop Filter)、熵编码(Entropy Coding)。而H264为了满足不同设备不同场景的需要(比如直播注重实时性,存储注重压缩比)定义了多种编码层次也就是Profile,官方给Profile的定义是:
The standarddefines a set of capabilities, which are referred to as profiles,targeting specific classes of applications. These are declared as a profilecode (profile_idc) and a set of constraints applied in the encoder. This allowsa decoder to recognize the requirements to decode that specific stream.
Profiles可以细分为十几种,实际使用的主要有以下四种,
1)BaslineProfile:支持I/P 帧,只支持无交错(Progressive)和CAVLC
Extended Profile:支持I/P/B/SP/SI 帧,只支持无交错(Progressive)和CAVLC
2)MainProfile:提供I/P/B 帧,支持无交错(Progressive)和交错(Interlaced),也支持CAVLC 和CABAC
3)High Profile:在mainProfile 的基础上增加了8x8内部预测、自定义量化、 无损视频编码和更多的YUV 格式;
大家对里面的术语可能不太理解,简单介绍下。
视频压缩很重要的一个就是帧间预测,也就是视频相邻的几帧有很大的相关性,变化不会太大,所以存在很多冗余信息,压缩要做的就是去除这些冗余信息。帧类型主要有以下几种
1)I帧表示关键帧,这一帧保留完整的画面数据,解码时只需要本帧数据就可以完成
2)P帧,前向预测帧,表示的是这一帧跟之前的一个关键帧(或P帧)的差别,解码时需要用之前的画面叠加上本帧定义的差别,生成最终画面。
3)B帧是双向预测帧,也就是B帧记录的是本帧与前后帧的差别,要解码B帧,不仅要取得之前的画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时比较耗费CPU 。
总结起来就是Profile 越高,压缩比就越高,但是编码、解码时要求的设备性能也就越高,编码、解码的效率也就越低。
6、Profile与Level详解
回到之前的两个视频信息,profile分别是main@L3.1,high@L3.1, 现在我们搞清楚了main和high是profile,L3.1是什么?这个是profile的码流级别,同样给出官方的定义:
As the term is used in the standard, a "level" is aspecified set of constraints that indicate a degree of required decoderperformance for a profile. For example, a level of support within a profilespecifies the maximum picture resolution, frame rate, and bit rate that adecoder may use. A decoder that conforms to a given level must be able todecode all bitstreams encoded for that level and all lower levels.
简单的说level就是对每个profile的能力细分。
而3.1规定的最高标准如下:
Level | Max. decoding speed | Max. frame size | Max. video bit rate for video coding layer (VCL) kbit/s (Baseline, Extended and Main Profiles) | Examples for high resolution @ highest frame rateToggle additional details | ||
---|---|---|---|---|---|---|
Luma samples/s | Macroblocks/s | Luma samples | Macroblocks | |||
3.1 | 27,648,000 | 108,000 | 921,600 | 3,600 | 14,000 | 352x288@172 352x576@130 640x480@90 720×576@601,280×720@30 |
7、iOS设备对Profile和level的支持情况
了解完视频的profile和level之后,大家会有疑问,既然每种profile对设备性能的要求不同,苹果的不同机型对各种profile支持程度是怎样的?可以参照下面的列表:
三、 自定义视频压缩方案
1、实现思路
基本概念都搞清楚了,而我们只需要支持iphone 5C以上机型的背景下,要想获得最大的视频压缩率采取的最好办法就是:
(1)指定highprofile
(2)降低帧率
(3)适当降低分辨率
最终来获取更低的码率。 问题来了,文章最开始的压缩方式不支持指定profile,帧率和码率。所以只有通过其他方式来实现。参照了括苹果官网的一个录像时自定义码率的实现
https://developer.apple.com/library/archive/samplecode/RosyWriter/Introduction/Intro.html
在录像时需要将拍摄的每一帧sampleBuffer(音频或者视频)传给assetWriter,并制定压缩参数。
而我们要实现的是视频压缩,不是录像,怎么办?思路很简单,先通过assetReader取出每一帧sampleBuffer(音频或视频),然后指定压缩参数后将每一帧传给assetWriter最终实现自定义压缩的目的。具体的流程如下:
2、代码实现
1)初始化 reader,writer,video/audio track, video/audio input, video/audio output
2)指定音视频的压缩码率,profile,帧率等关键参数信息
3)开始读写
4)视频逐帧写入
5)音频逐帧写入
6)完成压缩
压缩效果如下:
最终自定义的视频压缩方案有了,其实逐帧写入还可以做添加水印,滤镜等动作,之后可以在后续的文章里进一步介绍。