前两篇文章提出一些视频解码的方法,接下来讲一下视频编码的例子。
当我们从相机或者其他渠道获取到CVPixelBuffers这种原始视频流,并且想将它压缩写入视频文件中时,我们可以使用AVAssetWriter这个类来实现。
AVAssetWriter内部有一个编码器,它可以将原始视频帧压缩成CMSampleBuffers,并且写入视频文件中。
而当我们获取到原始视频流,不想将它写入视频文件中,而是获取到每一帧压缩图像,并通过网络发送出去时。我们可以使用VTCompressionSession这个类来实现。
创建VTCompressionSession时,需要以下几个参数:
1、压缩后的长宽信息
2、压缩后的类型
3、即将发送给VTCompressionSession的CVPixelBuffer的描述(可选)
4、实现一个输出回调的代码块
我们可以通过VTSessionSetProperty来配置VTCompressionSession,以下列出一些常用的属性
我们使用VTCompressionSessionEncodeFrame这个方法来编码CVPixelBuffer,由于CVPixelBuffer没有携带展示时间的数据,所以我们要按照展示时间顺序来提供CVPixelBuffer。
compressionSession通常需要几条帧数据一起处理,所以回调的输出可能会有延迟。可能需要一定数量的视频帧加入到编码器中才会有压缩的视频帧输出。最后当我们把所有的数据都加入到compressionSession中后,我们需要调用VTCompressionSessionCompleteFrames这个方法来让它输出所有的压缩数据。
在compressionSession的输出回调中,我们会收到CMSampleBuffers,当编码出现错误或丢帧时,也会收到错误信息。压缩的视频帧是按解码顺序来输出的。
当我们收到CMSampleBuffers时,说明它们是MPEG-4 packaging格式的,但是我们想将它通过网络发送出去,所以我们需要把它们变成Elementary Stream packaging格式的数据。
首先,我们需要将parameter sets从CMVideoFormatDescription中抽离出来,打包成NAL单元。我们可以使用CMVideoFormatDescriptionGetH264ParameterSetAtIndex这个方法来实现。
接下来,我们将NAL单元从CMSampleBuffer中取出来,并将其中的length code转换成start code。
本片文章总结:
1、如何创建VTCompressionSession
2、通过VTSessionSetProperty来配置VTCompressionSession
3、如何将CVPixelBuffer提供给compressionSession进行压缩
4、如何将CMSampleBuffers转换成H.264 Elementary Stream packaging
本文翻译自WWDC14:Direct Access to Video Encoding and Decoding