视频解码API概述
AVFoundation
- AVAssetReader
- AVSampleBufferGenerator
Video Toolbox
- VTDecompressionSession
Core Video
- CVPixelBuffer integration with Metal
使用AVFoundation的AVPlayer、AVAssetExportSession、AVAssetReader和Video Toolbox的VTDecompressSesion都自动进行硬件加速以及CMSampleBuffer的RPC优化。
视频核心数据结构
CVPixelBuffer:原始图像+图像元数据
CMBlockBuffer:任意类型的二进制数据(压缩图像)+元数据
CMSampleBuffer:
- CVPixelBuffer+时间信息+帧元数据(CMFormatDescription)
- CMBlockBuffer+时间信息+帧元数据
- 只包含元数据
IOSurface:不同框架、设备中交换图像数据的高速通道,应用在:
- 不同框架之间:CoreVideo和Metal
- 不同进程之间:解码进程和App进程
- 不同的内存区:显存和内存
CVPixelBufferPool:实现了CVPixelBuffer中的IOSurface的复用与回收。
解码流程
在解码的过程中如果配置的输出格式与原始数据格式不一致,还会发生转码,触发内存拷贝,要尽量避免。
获取解封装后的数据
要想获得解码前的裸数据,即解封装后的裸数据(输出为CMSampleBuffer),可以通过以下方式实现:
- AVAssetReader:创建track ouput时把
outputSetting
设为nil。 - AVSampleBufferGenerator:只能读出未解码的裸数据。
- 自己生成CMSampleBuffer:把数据读取出来,构建CMBlockBuffer,再加上时间信息,构建出CMSampleBuffer。这样的CMSampleBuffer不带RPC优化。
使用Video Toolbox解码
VTDecompressionSession包含三部分:
- 解码器
- CVPixelBufferPool
- VTPixelTransferSession
使用VTDecompressionSession的步骤:
- 创建VTDecompressionSession;
- 通过
VTSessionSetProperty
配置session; - 传递CMSampleBuffer视频帧给session解码。
- 从回调中获取解码CMSampleBuffer。
虽然回调是异步的,但回调中的逻辑仍会反向影响解码器的性能。常见的做法是把回调中的解码帧用队列缓存起来,在另外的线程处理。
CVPixelBuffer与Metal交互
拿到了解码帧CMSampleBuffer,就可以从中取出CVPixelBuffer,接下来就是如何处理和渲染了,这里使用Metal完成。
CVPixelBuffer与Metal交互方式:
- 直接使用IOSurface。即直接通过从CVPixelBuffer取出的IOSurface创建Metal纹理,但要手动处理IOSurface的内存释放(通过
IOSurfaceIncrementUseCount
、IOSurfaceDecrementUseCount
)。 - 使用CVMetalTextureCache。
- 创建CVMetalTextureCache:
CVMetalTextureCacheCreate
- 通过向CVMetalTextureCache传入CVPixelBuffer创建CVMetalTexture:
CVMetalTextureCacheCreateTextureFromImage
- 通过CVMetalTexture创建MTLTexture:
CVMetalTextureGetTexture
- 创建CVMetalTextureCache: