如果不想看文章,可以直接翻到最后,我已经把代码上传到gist上,但这样你会失去一个理解代码的机会。
该文章会涉及到的概念包括:
AVCaptureDeviceInput
,AVCaptureVideoDataOutput
,AVCaptureVideoPreviewLayer
,AVCaptureSession
,AVAssetWriterInput
,AVAssetWriter
,AVCaptureAudioDataOutputSampleBufferDelegate
,AVCaptureVideoDataOutputSampleBufferDelegate
以上技术概念都属于AVFundation下
实现目标:显示自定义比例的相机并且将相机拍摄的数据以视频的方式保存到本地。
在开始之前,我先对上面的涉及到的每个概念做一个简单说明,便于对后面代码的理解
AVCaptureDeviceInput
包含videoInput,audioInput,分别获取音视频设备,这里videoInput还要区分front camera和back camera ,可以定义三个AVCaptureDeviceInput,分别是current camera(front/back),一个front camera,一个back camera。切换camera时,只要给current camera赋不同的camera即可。
AVCaotureVideoPreviewLayer
用来显示camera的图像的layer,通过设置它的frame和videoGravity属性,就可以实现显示不同尺寸的画面了。
AVCaptureVideoDataOutput
与DeviceInput相对应,要声明两个output,分别是video output和audio output,其中可以通过设置video output的AVCaptureConnection控制摄像头是否是镜像显示,摄像头方向,auto focus等数据,该output的效果直接显示在previewLayer上。
AVCaptureSession
AVCaptureSession的是起到一个bridge的作用,它建立起AVCaptureDeiviceInput和AVCaptureDeviceOutput之间的关系,这里需要注意,session同时只能有一种output,该博客中的方案是建立AVCaptureVideoDataOutput,也就是每一帧图片都有一个buffer的帧回调,还有一种output是AVCaptureFileOutputRecordingDelegate,这种回调是直接把buffer写到文件中,拿不到帧回调数据,也不能自定义帧大小。只能使用系统提供的几种帧比例。
AVAssetWriterInput
需要分别定义一个audio和video的writer,之前说道的device intput,device output都是显示上的设置,这里主要涉及的是写文件,video asset writer设置的分辨率要与previewLayer的分辨率保持一致,否则会出现显示和保存的画质不一致情况。
AVAssetWriter
AVAssetWriter绑定audio,video writer,指定写文件路径,控制开始和结束。
图中可以看到整个流程分为三大块:session,previewlayer,asswriter,preview layer初始化的时候会传参一个session,session通过output delegate和asswriter建立联系,asswiter通过捕捉回调帧数据,写视频文件。
真正实现的时候,还会涉及到很多参数配置,配置的先后顺序也是要注意的点,详细过程还要看代码。
这里只对声明的所有属性做一个简单的注解,其他模块的代码可以在文章底部自行下载查看。
//preview Layer依附的View,外部传进来的变量
@property (nonatomic ,strong) UIView *attachView;
@property (nonatomic ,strong) AVCaptureVideoPreviewLayer *previewLayer;
//用于DeviceOutput
@property (nonatomic ,strong) dispatch_queue_t recoredingQuene;
//AssetWriter配置项
@property (nonatomic ,strong) NSDictionary *audioSetting;
@property (nonatomic ,strong) NSDictionary *videoSetting;
//AsstWriter
@property (nonatomic ,strong) AVAssetWriterInput *audioWriterInput;
@property (nonatomic ,strong) AVAssetWriterInput *videoWriterInput;
@property (nonatomic ,strong) AVAssetWriter *assetWriter;
//video file的保存路径
@property (nonatomic ,strong) NSURL *recordingURL;
//Output
@property (nonatomic ,strong) AVCaptureVideoDataOutput *videoOutput;
@property (nonatomic ,strong) AVCaptureVideoDataOutput *audioOutput;
//session
@property (nonatomic ,strong) AVCaptureSession *session;
//Input Device
@property (nonatomic ,strong) AVCaptureDeviceInput *currentCameraInput;
@property (nonatomic ,strong) AVCaptureDeviceInput *frontCamera;
@property (nonatomic ,strong) AVCaptureDeviceInput *backCamera;
@property (nonatomic ,strong) AVCaptureDeviceInput *audioMic;
//闪光灯
@property (nonatomic ,strong) AVCaptureDevice *flashLight;
//控制录制的变量
@property (nonatomic ,assign) BOOL isRecording;
@property (nonatomic, assign) BOOL isRecordingSessionStarted;
Source Code