三、视频编解码-解码篇
Demo地址 在此之前我们通常使用的FFmpeg多媒体库,利用CPU来进行视频的编解码,占用CPU资源,效率低下,俗称软编解码.而苹果在2014年的iOS8中,开放了VideoToolbox.framwork框架,此框架使用GPU或专用的处理器来进行编解码,俗称硬编解码.而此框架在此之前只有MAC OS系统中可以使用,在iOS作为私有框架.终于苹果在iOS8.0中得到开放引入.
2014年的WWDCDirect Access to Video Encoding and Decoding中,苹果介绍了使用videoToolbox硬编解码. 使用硬编解码有几个优点:
- 提高性能;
- 增加效率;
- 延长电量的使用
对于编解码,AVFoundation框架只有以下几个功能:
- 直接解压后显示;
- 直接压缩到一个文件当中;
而对于Video Toolbox,我们可以通过以下功能获取到数据,进行网络流传输等多种保存:
- 解压为图像的数据结构;
压缩为视频图像的容器数据结构.
一、videoToolbox的基本数据
Video Toolbox视频编解码前后需要应用的数据结构进行说明。
CVPixelBuffer:编码前和解码后的图像数据结构。此内容包含一系列的CVPixelBufferPool内容
CMTime、CMClock和CMTimebase:时间戳相关。时间以64-bit/32-bit的形式出现。
pixelBufferAttributes:字典设置.可能包括Width/height、pixel format type、• Compatibility (e.g., OpenGL ES, Core Animation)
CMBlockBuffer:编码后,结果图像的数据结构。
CMVideoFormatDescription:图像存储方式,编解码器等格式描述。
(CMSampleBuffer:存放编解码前后的视频图像的容器数据结构。
CMClock
CMTimebase: 关于CMClock的一个控制视图,包含CMClock、时间映射(Time mapping)、速率控制(Rate control)
由二、采集视频数据可知,我们获取到的数据(CMSampleBufferRef)sampleBuffer
为未编码的数据;
图1.1
上图中,编码前后的视频图像都封装在CMSampleBuffer
中,编码前以CVPixelBuffer
进行存储;编码后以CMBlockBuffer
进行存储。除此之外两者都包括CMTime
、CMVideoFormatDesc
.
二、获取已编码数据流进行解码展示(获取编码后的数据进行解码展示)
图2.1
通过网络获取已编码的H.264数据流进行MPEG-4处理,通过使用AVSampleBufferDisplayLayer解码获取图像显示到设备上。 图2.2
2.1. 将获取到的已编码的数据流进行处理成CMSampleBuffer
.
图2.3
由图1.1可知:解码前的图像数据结构$$CMSampleBuffer = CMTime + FormatDesc + CMBlockBuffer$$组成 因此需要从H.264的码流需要以上三个信息组合成CMSampleBuffer
.
H.264码流由一系列的NALU单元组成.NALU单元包含视频图像数据(或视频帧片段)和H.264的参数信息。其中视频图像信息数据是CMBlockBuffer,而H.264参数信息可以组合成FormatDesc,包括编码所用的profile,level,图像的宽和高,deblock滤波器等.具体包含第一个NALU的SPS(Sequence Parameter Set)和第二个NALU的PPS(Picture Parameter Set)。 图2.4
* frame的数据可以分为多个slice(片段).
* 每个slice中的数据,在帧内预测只用到自己slice的数据, 与其他slice 数据没有依赖关系。
* NAL 是用来将编码的数据进行大包的。 比如,每一个slice 数据可以放在NAL 包中。
* I frame 是自己独立编码,不依赖于其他frame 数据。
* P frame 依赖 I frame 数据。
* B frame 依赖 I frame, P frame 或其他 B frame 数据。
* H.264码流的**第三个NALU是IDR**(即时解码器刷新),IDR图像都是I帧,H.264引入IDR图像为了解码的同步,使错
误不被传播,当解码器解码到IDR图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,
开一个新的序 列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。IDR图像之后的图像永远不
会使用IDR之前的图像的数据来解码。
1.1 使用CMVideoFormatDescriptionCreateFromH264ParameterSets
提取编码的SPS和PPS压缩转换成MPEG—4
需要的SPS和PPS,组合成CMVideoFormatDescription
(1)每个NALU的开始码是3或4字节头:00 00 01 或 00 00 00 01,按开始码可定位NALU;
(2)提取出SPS和PPS,通过获取到的编码流,判断开始码后的第一个byte的低5位,7代表SPS,8代表PPS.
(3)`CMVideoFormatDescriptionCreateFromH264ParameterSets`函数构建`CMVideoFormatDescription`.
1.2 获取CMBlockBuffer
(1)通过开始码,定位到NALU;
(2)确认类型数据将开始码替换为NALU的长度信息(4 Byte)
(3)通过CMBlockBufferCreateWithMemoryBlock接口构造CMBlockBufferRef
1.3 添加CMTime