视频编解码¶
为什么需要编码¶
降低视频大小,方便存储和网络传输。
硬编码(AVFoundation已经实现)
视频¶
内容元素
- 图像信息(Image)
- 音频(Audio)
- 元信息(Metadata)
- 字幕
编码格式
-
Video:H264
-
Audio:AAC
容器封装
- MP4、MOV、FLV、RM、RMVB、AVI
视频4个动作¶
- 采集--视频源数据CVPixelBufferRef
- 编码(硬编码VideoToolBox)--- NALU数据--- CMBlockBufferRef
- 解码(硬解码VideoToolBox)-- NALU数据--- CVPixelBufferRef
- 将数据显示到屏幕上(渲染)-- OpenGL ES视频渲染动作
VideoToolBox基本概念¶
VideoToolBox
基于coreMedia
,coreVideo
,coreFundation
框架C语言API。
三种类型会话:编码,解码,像素移动。
CMSampleBufferRef¶
编码后的视频帧CMSampleBuffer¶
- CMTime
- CMVideoFormatDescriptionRef:视频格式描述。包括编码尺寸,视频尺寸。
- CMBlockBuffer:块缓冲区
- CMBlockBufferRef里面是frame帧
未编码的视频帧CMSampleBuffer¶
- CMTime
- CMVideoFormatDescriptionRef:视频格式描述。包括编码尺寸,视频尺寸。
- CVPixelBufferRef:像素缓冲区。保存的是解码后的数据或者未编码前的数据。
YUV¶
CVPixelBufferRef里面存储的不是RGB而是YUV信息
OpenGLES默认的颜色体系是RGB,需要YUV转换RGB,需要两个纹理。
视频由2个图层构成:Y图层和UV图层。
图片数据只有Y数据(明亮度,灰阶值),可以显示,但是是黑白的。加上UV(色度)信息图片才会变成彩色的。
YUV是三种分量,合在一起表示一个像素。
YUV排列格式有两种:打包格式packed和平面格式planer。
- YUV4:4:4采样,表示色度频道没有下采样,即一个Y分量对应一个U分量和一个V分量。
Y0 U0 V0
- YUV4:2:2采样,表示2:1的水平下采样,没有垂直下采样,即每两个Y分量共用一个U分量和一个V分量。
Y0 U0 V0
Y1 U0 V0
- YUV4:2:0采样,表示2:1的水平下采样,2:1的垂直下采样,即每四个Y分量共用一个U分量和一个V分量。
Y0 U0 V0
Y1 U0 V0
Y2 U0 V0
Y3 U0 V0
视频渲染就是纹理的渲染,也就是片元着色器填充。width * height正方形(渲染2个纹理)。
视频编码¶
编码的输入和输出¶
原始数据(CVPixelBuffers) --> 经过VTCompressionSessionRef(VideoEncoder视频编码器) --> 得到H264文件(CMSampleBufferRefs)
视频解码¶
解码思路¶
- 解析数据(NALU Unit 流单元)I帧P帧B帧
流数据NALU一个接一个,所以需要实时解码。
首先需要对数据解析,分析NALU数据,前面4个字节是起始位,标识一个NALU的开始,所以从第5位才开始来获取,从第五位才是NALU数据类型。
获取到第5位数据,转化为十进制,然后根据表格判断它的数据类型。
判断好数据类型,才能将NALU送入解码器。SPS/PPS只要获取就可以了,是不需要解码的。
-
初始化解码器
-
将解析后的H264流数据(NALU Unit)输入到解码器
-
解码完成后的回调,输出解码数据
-
解码数据显示,用到OpenGL ES
解码三个核心函数¶
- 创建session,
VTDecompressionSessionCreate
- 解码一个frame,
VTDecompressionSessionDecodeFrame
- 销毁解码session,
VTDecompressionSessionInvalidate
原理分析¶
解码解的是H264原始码流,H264原始码流由一个一个流数据(NALU)组成。