LearningAVFoundation之拍摄+实时滤镜+实时写入

2,808 阅读4分钟

前言

AVFoundation框架的功能十分强大,同时也充斥着各种类,比如各种session,各种input,各种output。之前并没有对整个框架进行过完整梳理,虽然也能东拼西凑的那各种类完成需求,但遇到深度定制的需求以及踩到坑之后,总会比较吃力。最近,在看《learning AV Foundation》这本书,看完后尝试着梳理了一个整体脉络,并将理解的知识点整合用Swift重写了一个demo,包括拍摄+实时滤镜+实时写入+自定义导出分辨率等。本篇为视频拍摄部分,下一章会更新视频的组合编辑及音频混合部分。

整体脉络

整体架构

可以看到,整个流程可以分为三部分,分别为数据采集、数据加工和数据保存。

数据采集: 数据采集不仅限于本文场景中的通过摄像头和麦克分设备采集,还比如AVAssetReader从AVAsset实例中读取。无论以什么方式采集,这一阶段的输出都为CMSampleBuffer。值得一提的是,摄像头采集的是yuv格式的压缩的视频信号,在输出时要还原成可以处理的数字信号,这一配置在AVCaptureVideoDataOutput的videoSettings属性中。

数据加工: 数据加工阶段可以基于CMSampleBuffer进行各种处理,包括加滤镜等,都在这个阶段。sampleBuffer会包含一个CVPixelBuffer,它是一个带有单个视频帧原始像素数据的Core Video对象,据此我们可以进行像素级别的加工。

数据保存: 数据保存阶段将加工后的媒体资源进行编码并写入到容器文件中,比如mp4文件或.mov文件等。此处使用AVAssetWriter,它支持实时写入。它期望接收到的数据也是CMSampleBuffer格式。同时我们也可以传入其他数据,通过pixelBufferAdaptor适配成它所期望的数据。比如,本文的demo中传入了CIImage,可以先将CIImage渲染成CVPixelBuffer,再进行写入。

以上就是整体脉络,本文的demo也是基于这个思路封装的。CaptureManager负责数据采集,通过block回调输出CMSampleBuffer数据。VideoWriteManager负责数据保存,接收CMSampleBuffer数据,通过block回调生成的文件路径。CameraViewController作为两者的调度方,并承担数据加工工作以及将加工后的数据展示给用户进行预览。

设备采集

通过设备采集的核心类是AVCaptureSession,它的输入是AVCaptureDeviceInput,输出是AVCaptureOutput,管理从物理设备中得到的数据流,并按照output的配置输出指定的文件或数据。AVCaptureOutput是一个抽象基类,如果定制化需求不高,可以直接使用AVCaptureMovieOut高级类来直接输出文件。但是如果需要进行底层的数据加工或自定义配置,就需要使用AVCaptureVideoDataout和AVCaptureAudioDataOutput来输出CMSampleBuffer格式的原始数据。此外,为了不阻塞主线程,我们一般会为AVCaptureOutput分配专门的串行队列。

数据加工-添加滤镜

滤镜大多使用GPUImage框架,但这不是本文的核心,因此,demo中仅使用了CoreImage框架来实现滤镜效果。为了达到实时滤镜的效果,需要在每一帧的回调数据中,都对每一帧的图像数据都应用当前滤镜的效果,从而用户可以在拍摄过程中不断切换各种滤镜。

此处在学习《learning AV Foundation》书中的demo时,书中的demo是把原始数据分别传给用户预览界面和写入类,两者各自处理。但我觉得这样相当于同样的加工处理了两遍,从代码维护和性能上都不是很可取。因为,此处我是处理完后,把处理完的数据分别传给预览界面显示和写入类保存。

数据保存

AVAssetWriter通过多个(音频、视频等)AVAssetWriterInput对象配置。AVAssetWriterInput通过mediaType和outputSettings来初始化,我们可以在outputSettings中进行视频比特率、视频宽高、关键帧间隔等细致的配置,这也是AVAssetWrite相比AVAssetExportSession明显的优势。AVAssetWriterInput在附加数据后会在最终输出时生成一个独立的AVAssetTrack.

此处用到了PixelBufferAdaptor来附加CVPixelBuffer类型的数据,它在附加CVPixelBuffer对象的视频样本时能提供最优性能。

以上就是AVFoundation Caputure部分的整体思路和脉络,更多采坑细节如视频旋转问题等请参考Demo,内有详细注释。