之前使用过AVFoundation实现二维码扫描的功能,当初第一次接触这个框架,只是搜索资料,实现功能就草草了事了,最近要实现视频的录制功能,又用到了这个框架,而且发现,步骤跟实现二维码的时候十分相似,所以来总结一下。
使用AVFoundation拍照和录制视频的一般步骤如下:
- 创建AVCaptureSession对象。
- 使用AVCaptureDevice的静态方法获得需要使用的设备,例如拍照和录像就需要获得摄像头设备,录音就要获得麦克风设备。
- 利用输入设备AVCaptureDevice初始化AVCaptureDeviceInput对象。
- 初始化输出数据管理对象,如果要拍照就初始化AVCaptureStillImageOutput对象;如果拍摄视频就初始化AVCaptureMovieFileOutput对象。
- 将数据输入对象AVCaptureDeviceInput、数据输出对象AVCaptureOutput添加到媒体会话管理对象AVCaptureSession中。
- 创建视频预览图层AVCaptureVideoPreviewLayer并指定媒体会话,添加图层到显示容器中,调用AVCaptureSession的startRuning方法开始捕获。
- 将捕获的音频或视频数据输出到指定文件。
录制视频
@property (weak, nonatomic) IBOutlet UIView *viewContainer;
@property (weak, nonatomic) IBOutlet UIButton *videoButton;
@property (strong, nonatomic) AVCaptureSession *captureSession;
@property (strong, nonatomic) AVCaptureDevice *audioDevice;
@property (strong, nonatomic) AVCaptureDevice *captureDevice;
@property (strong, nonatomic) AVCaptureDeviceInput *audioDeviceInput;
@property (strong, nonatomic) AVCaptureDeviceInput *captureDeviceInput;
@property (strong, nonatomic) AVCaptureMovieFileOutput *captureMovieOutput; //视频输出流
@property (strong, nonatomic) AVCaptureVideoPreviewLayer *capturePreviewLayer; // 相机预览化图层
// 初始化会话
if ([self.captureSession canSetSessionPreset:AVCaptureSessionPreset640x480]) {
// 设置分辨率
self.captureSession.sessionPreset = AVCaptureSessionPreset640x480;
}
// 获取输入数据 视频和音频
NSError *error;
self.captureDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:self.captureDevice error:&error];
if (error) {
NSLog(@"Error Description:%@", error.localizedDescription);
}
self.audioDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:self.audioDevice error:&error];
if (error) {
NSLog(@"Error Description:%@", error.localizedDescription);
}
// 初始化输出对象
self.captureMovieOutput = [[AVCaptureMovieFileOutput alloc] init];
// 将设备输入添加到会话
if ([self.captureSession canAddInput:self.captureDeviceInput] && [self.captureSession canAddInput:self.audioDeviceInput]) {
[self.captureSession addInput:self.audioDeviceInput];
[self.captureSession addInput:self.captureDeviceInput];
AVCaptureConnection *captureConnection = [self.captureMovieOutput connectionWithMediaType:AVMediaTypeVideo];
if ([captureConnection isVideoStabilizationSupported]) {
captureConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
}
}
// 将设备输出添加到会话中
if ([self.captureSession canAddOutput:self.captureMovieOutput]) {
[self.captureSession addOutput:self.captureMovieOutput];
}
// 创建预览化图层
self.capturePreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
CALayer *layer = self.viewContainer.layer;
self.capturePreviewLayer.frame = layer.bounds;
// 填充模式
self.capturePreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[layer insertSublayer:self.capturePreviewLayer below:self.videoButton.layer];
#pragma mark - Getter And Setter
- (AVCaptureSession *)captureSession{
if (_captureSession == nil) {
_captureSession = [[AVCaptureSession alloc] init];
}
return _captureSession;
}
- (AVCaptureDevice *)audioDevice{
if (_audioDevice == nil) {
_audioDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];
}
return _audioDevice;
}
- (AVCaptureDevice *)captureDevice{
if (_captureDevice == nil) {
NSArray *cameras = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for (AVCaptureDevice *camera in cameras) {
if ([camera position] == AVCaptureDevicePositionBack) {
return camera;
}
}
}
return _captureDevice;
}
二维码扫描
// 初始化捕捉设备(AVCaptureDevice),类型为AVMediaTypeVideo
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
// captureDevice创建输出流
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
if (!input) {
NSLog(@"%@",[error localizedDescription]);
return;
}
// 创建媒体数据输出流
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
// 实例化捕捉会话
_caputureSession = [[AVCaptureSession alloc] init];
// 输入流,输出流添加到会话
[_caputureSession addInput:input];
[_caputureSession addOutput:output];
// 设置代理
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
// 设置输出媒体数据类型为QRCode
[output setMetadataObjectTypes:[NSArray arrayWithObjects:AVMetadataObjectTypeQRCode,AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeUPCECode, AVMetadataObjectTypeCode39Mod43Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypeInterleaved2of5Code, nil]];
// 实例化预览图层
_videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_caputureSession];
// 设置图层填充方式
[_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
// _videoPreviewLayer.frame = _viewPreview.layer.bounds;
_videoPreviewLayer.frame = [UIScreen mainScreen].bounds;
// 添加到预览图层
[_viewPreview.layer addSublayer:_videoPreviewLayer];
// 扫描范围
// CGSize size = _viewPreview.bounds.size;
CGSize size = [UIScreen mainScreen].bounds.size;
CGRect cropRect = CGRectMake(_videoPreviewLayer.bounds.size.width/2 - (105/375.0)*SCREEN_WIDTH, (200/667.5)*SCREEN_HEIGHT, (210/375.0)*SCREEN_WIDTH, (210/667.5)*SCREEN_HEIGHT);
[output setRectOfInterest:CGRectMake(cropRect.origin.y/size.height, cropRect.origin.x/size.width, cropRect.size.height/size.height, cropRect.size.width/size.width)];
// 扫描框
_boxView = [[UIView alloc] initWithFrame:_videoPreviewLayer.frame];
_boxView.backgroundColor = [UIColor clearColor];
UIImageView *scanView = [[UIImageView alloc] initWithFrame:_boxView.frame];
scanView.image = [UIImage imageNamed:@"device_QR_scanning"];
[_boxView addSubview:scanView];
[_viewPreview addSubview:_boxView];
// 开始扫描
[_caputureSession startRunning];