一、前言
随着抖音,快手等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分别是[email protected],[email protected], 现在我们搞清楚了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规定的最高标准如下:
7、iOS设备对Profile和level的支持情况
了解完视频的profile和level之后,大家会有疑问,既然每种profile对设备性能的要求不同,苹果的不同机型对各种profile支持程度是怎样的?可以参照下面的列表:
iPhone 3GS 和更早的设备支持 Baseline Profile level 3.0 及更低的级别
iPhone 4S 支持 High Profile level 4.1 及更低的级别
iPhone 5C 支持 High Profile level 4.1 及更低的级别
iPhone 5S 支持 High Profile level 4.1 及更低的级别
iPad 1 支持 Main Profile level 3.1 及更低的级别
iPad 2 支持 Main Profile level 3.1 及更低的级别
iPad with Retina display 支持 High Profile level 4.1 及更低的级别
iPad mini 支持 High Profile level 4.1 及更低的级别
三、 自定义视频压缩方案
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)完成压缩
压缩效果如下:
最终自定义的视频压缩方案有了,其实逐帧写入还可以做添加水印,滤镜等动作,之后可以在后续的文章里进一步介绍。