跳转至

视频编解码

为什么需要编码

降低视频大小,方便存储和网络传输。

硬编码(AVFoundation已经实现)

视频

内容元素

  • 图像信息(Image)
  • 音频(Audio)
  • 元信息(Metadata)
  • 字幕

编码格式

  • Video:H264

  • Audio:AAC

容器封装

  • MP4、MOV、FLV、RM、RMVB、AVI

视频4个动作

  1. 采集--视频源数据CVPixelBufferRef
  2. 编码(硬编码VideoToolBox)--- NALU数据--- CMBlockBufferRef
  3. 解码(硬解码VideoToolBox)-- NALU数据--- CVPixelBufferRef
  4. 将数据显示到屏幕上(渲染)-- OpenGL ES视频渲染动作

VideoToolBox基本概念

VideoToolBox基于coreMediacoreVideocoreFundation框架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)

视频解码

解码思路

  1. 解析数据(NALU Unit 流单元)I帧P帧B帧

流数据NALU一个接一个,所以需要实时解码。

首先需要对数据解析,分析NALU数据,前面4个字节是起始位,标识一个NALU的开始,所以从第5位才开始来获取,从第五位才是NALU数据类型。

获取到第5位数据,转化为十进制,然后根据表格判断它的数据类型。

判断好数据类型,才能将NALU送入解码器。SPS/PPS只要获取就可以了,是不需要解码的。

  1. 初始化解码器

  2. 将解析后的H264流数据(NALU Unit)输入到解码器

  3. 解码完成后的回调,输出解码数据

  4. 解码数据显示,用到OpenGL ES

解码三个核心函数

  1. 创建session,VTDecompressionSessionCreate
  2. 解码一个frame,VTDecompressionSessionDecodeFrame
  3. 销毁解码session,VTDecompressionSessionInvalidate

原理分析

解码解的是H264原始码流,H264原始码流由一个一个流数据(NALU)组成。