美文网首页iOS点点滴滴
【iOS】自定义相机(六)拍照与录像

【iOS】自定义相机(六)拍照与录像

作者: Seacen_Liu | 来源:发表于2019-04-16 23:19 被阅读24次
巴黎圣母院

在完成了相机的各种设置之后,自定义相机最重要的功能就是拍照和录像。本篇文章将给大家介绍基于AVCaptureStillImageOutputAVCaptureMovieFileOutput的拍照与录像操作。虽然AVCaptureStillImageOutput在iOS 10 中被弃用,AVCaptureMovieFileOutput也不能与AVCaptureVideoDataOutput同时使用,但是鉴于这两个类用起来相对比较简便,并且可用于兼容低版本,因此还是将他的使用整理整理了。

对应的代码在SCCamera中的SCPhotographManager.mSCMovieFileOutManager.m中。

拍照操作

首先需要创建AVCaptureStillImageOutput对象,并设置outputSettings,然后再添加进当前使用的捕捉会话中。

AVCaptureStillImageOutput *stillImageOutput = [AVCaptureStillImageOutput new];
stillImageOutput.outputSettings = @{AVVideoCodecKey: AVVideoCodecJPEG};
if ([self.session canAddOutput:stillImageOutput]) {
    [self.session addOutput:stillImageOutput];
}

需要拍照的时候调用captureStillImageAsynchronouslyFromConnection:方法即可,完整声明如下:

- (void)captureStillImageAsynchronouslyFromConnection:(AVCaptureConnection *)connection completionHandler:(void (^)(CMSampleBufferRef _Nullable imageDataSampleBuffer, NSError * _Nullable error))handler;

该方法需要的参数如下:

  • connection:视频连接
  • handler:异步处理 Block,即获取拍照片的途径

下面将拍照操作分成拍照前拍照后两部分进行介绍:

拍照前操作

拍照之前重要的操作就是获取设置connectionhandler参数,在设置参数之前,我们可以通过以下方法获取connection并进行设置:

// 1. 获取 stillImageConnection
AVCaptureConnection* stillImageConnection = [stillImageOutput connectionWithMediaType:AVMediaTypeVideo];
// 2. 设置 stillImageConnection
if (stillImageConnection.supportsVideoOrientation) {
    stillImageConnection.videoOrientation = videoOrientation;
}

拍照后操作

handler中的操作就是拍照之后我们对图片处理的操作,他的类型是void (^)(CMSampleBufferRef, NSError *)。这里会有以下两个问题:1. 没看到熟悉的UIImage对象;2. 我们的预览视图可能设置成了AVLayerVideoGravityResizeAspectFill模式,拍出来的照片肯定和用户看到的预览不一样。为了解决这些问题,在照片的处理上,我们分为四步走:

  1. 获取照片原图
  2. 获取照片缩放图
  3. 获取照片裁剪图
  4. 根据需求进行后续操作
void (^completionHandler)(CMSampleBufferRef, NSError *) = ^(CMSampleBufferRef  _Nullable imageDataSampleBuffer, NSError * _Nullable error){
    if (!imageDataSampleBuffer || error) {
            // TODO: - 处理错误
        return;
    }
    // 1. 获取 originImage
    NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
    UIImage *originImage = [[UIImage alloc] initWithData:imageData];
    originImage = [originImage fixOrientation];
    // 2. 获取 scaledImage
    CGFloat width = previewLayer.bounds.size.width;
    CGFloat height = previewLayer.bounds.size.height;
    CGFloat scale = [[UIScreen mainScreen] scale];
    CGSize size = CGSizeMake(width*scale, height*scale);
    UIImage *scaledImage = [originImage resizedImageWithContentMode:UIViewContentModeScaleAspectFill size:size interpolationQuality:kCGInterpolationHigh];
    // 3. 获取 croppedImage
    CGRect cropFrame = CGRectMake((scaledImage.size.width - size.width) * 0.5, (scaledImage.size.height - size.height) * 0.5, size.width, size.height);
    UIImage *croppedImage = [scaledImage croppedImage:cropFrame];
    // 4. 根据需求进行后续操作
    // TODO: - 业务操作
};

这里的图片处理分别是先将图片缩放,再进行裁剪。这个过程其实就在模仿预览视图中ResizeAspectFill的操作,最后的croppedImage就和预览视图的一模一样了。(中间用到的UIImage方法具体见本项目中的UIImage+SCCamera.m

最后别忘了调用拍照方法:

[stillImageOutput captureStillImageAsynchronouslyFromConnection:stillImageConnection completionHandler: completionHandler];

录像操作

首先需要创建AVCaptureMovieFileOutput对象,然后再添加进当前使用的捕捉会话中。

self.movieFileOutput = [AVCaptureMovieFileOutput new];
if ([self.session canAddOutput:movieFileOutput]) {
    [self.session addOutput:movieFileOutput];
}

录制视频和拍照不同,他有一个录制开始和录制结束,我们可以直接调用AVCaptureMovieFileOutput的开始录制方法和录制结束方法进行操作。根据要求,我们还需要实现一个AVCaptureFileOutputRecordingDelegate代理进行录制状态的监听与处理,当然录制结束后,我们也需要在代理方法里面获取视频信息。我将这个录制过程分为下面四步:

第一步:生成文件路径

self.movieURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@%@", NSTemporaryDirectory(), @"movie.mov"]];

该路径用于录制过程中临时视频的保存,十分重要,需要使用强引用。

第二步:开始录像处理

- (void)start:(AVCaptureVideoOrientation)orientation {
    if (!self.movieFileOutput.isRecording) {
        AVCaptureConnection *videoConnection = [self.movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
        if (videoConnection.supportsVideoStabilization) {
            videoConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
        }
        if (videoConnection.supportsVideoOrientation) {
            videoConnection.videoOrientation = orientation;
        }
        [self.movieFileOutput startRecordingToOutputFileURL:self.movieURL recordingDelegate:self];
    }
}

AVCaptureVideoStabilizationModeAuto表示自动进行视频稳定录制

第三步:结束录像处理

- (void)stop{
    if (self.movieFileOutput.isRecording) {
        [self.movieFileOutput stopRecording];
    }
}

第四步:录像完成处理

- (void)captureOutput:(nonnull AVCaptureFileOutput *)output didFinishRecordingToOutputFileAtURL:(nonnull NSURL *)outputFileURL fromConnections:(nonnull NSArray<AVCaptureConnection *> *)connections error:(nullable NSError *)error {
    // 拿到 outputFileURL 进行后续操作
}

AVCaptureFileOutputRecordingDelegate中除了有上面第四步的用途,还可以处理录像被打断等多种情况。

补充

关于 videoOrientation

在拍照和录像中都用到了videoOrientation,该属性是AVCaptureVideoOrientation,共有四个方向:

  • AVCaptureVideoOrientationPortrait:竖直方向,HOME键在下面
  • AVCaptureVideoOrientationPortraitUpsideDown:竖直方向,HOME键在上面
  • AVCaptureVideoOrientationLandscapeRight:水平方向,HOME键在右边
  • AVCaptureVideoOrientationLandscapeLeft:水平方向,HOME键在左边

视频流是不知道我们需要什么方向的视频的,需要我们在连接(connection)中设置,剩下的方向转换工作就交给 AVFoundation 了。

相关文章

网友评论

    本文标题:【iOS】自定义相机(六)拍照与录像

    本文链接:https://www.haomeiwen.com/subject/fwjwwqtx.html