Camera Without Fear——iOS

前言

摄像头是移动设备的重要工具。随着移动端技术的发展,摄像头作为移动设备的图像采集工具,也变得越来越重要。不论是AR特效,计算机视觉技术,都离不开摄像头稳定高效地工作。

本文记录iOS的AVFoundation中Camera相关API的使用方法。

Camera架构

Camera Without Fear——iOS_第1张图片
image.png

我们可以看到,总的来说移动端的视觉设备是由,输入、会话、输出三部分组成。


//捕获设备,通常是前置摄像头,后置摄像头,麦克风(音频输入)
@property (nonatomic, strong) AVCaptureDevice *device;

//AVCaptureDeviceInput 代表输入设备,他使用AVCaptureDevice 来初始化
@property (nonatomic, strong) AVCaptureDeviceInput *input;

//输出文件
@property (nonatomic ,strong) AVCaptureMovieFileOutput *fileOutput;

//session:由他把输入输出结合在一起,并开始启动捕获设备(摄像头)
@property (nonatomic, strong) AVCaptureSession *session;

//图像预览层,实时显示捕获的图像
@property (nonatomic ,strong) AVCaptureVideoPreviewLayer *previewLayer;

上面的五个成员,就满足了我们上图模型中的各个位置。

初始化Camera

- (void)initCamera
{
    self.recordPath = [self createRecordFilePath];
    //    AVCaptureDevicePositionFront 前置摄像头
    self.device = [self cameraWithPosition:AVCaptureDevicePositionFront];
    self.input = [[AVCaptureDeviceInput alloc] initWithDevice:self.device error:nil];
    self.fileOutput = [[AVCaptureMovieFileOutput alloc] init];
    self.session = [[AVCaptureSession alloc] init];
    //     拿到的图像的大小可以自行设定
    //    AVCaptureSessionPreset320x240
    //    AVCaptureSessionPreset352x288
    //    AVCaptureSessionPreset640x480
    //    AVCaptureSessionPreset960x540
    //    AVCaptureSessionPreset1280x720
    //    AVCaptureSessionPreset1920x1080
    //    AVCaptureSessionPreset3840x2160
    self.session.sessionPreset = AVCaptureSessionPreset640x480;
    //输入输出设备结合
    if ([self.session canAddInput:self.input]) {
        [self.session addInput:self.input];
    }
    if ([self.session canAddOutput:_fileOutput]) {
        [self.session addOutput:_fileOutput];
    }
    //预览层的生成
    self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
    CGFloat viewX = (_viewWidth - PREVIEW_WIDTH)/2;
    CGFloat viewY = (_viewHeight - PREVIEW_HEIGHT)/2;
    self.previewLayer.frame = CGRectMake( viewX, viewY, PREVIEW_WIDTH, PREVIEW_HEIGHT);
    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [self.view.layer addSublayer:self.previewLayer];
    //设备取景开始
    [self.session startRunning];
}

- (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position{
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for ( AVCaptureDevice *device in devices )
        if ( device.position == position ){
            return device;
        }
    return nil;
}

上面的代码思路很清晰,大致的过程就是:

  • 获取相机设备队象
  • 从相机设备中获取输入流
  • 创建输出流
  • 创建会话
  • 为会话添加输入,输出流
  • 为预览层添加会话
  • 启动会话

完成上面步骤后,我们就可以previewLayer中看到前置摄像头的画面了。

录制视频


- (void)recordMovie
{  
    AVCaptureConnection *captureConnection=[self.fileOutput connectionWithMediaType:AVMediaTypeVideo];
    // 开启视频防抖模式
    AVCaptureVideoStabilizationMode stabilizationMode = AVCaptureVideoStabilizationModeCinematic;
    if ([self.input.device.activeFormat isVideoStabilizationModeSupported:stabilizationMode]) {
        [captureConnection setPreferredVideoStabilizationMode:stabilizationMode];
    }
    // 预览图层和视频方向保持一致,这个属性设置很重要,如果不设置,那么出来的视频图像可以是倒向左边的。
    captureConnection.videoOrientation=[_previewLayer connection].videoOrientation;
    // 路径转换成 URL 要用这个方法,用 NSBundle 方法转换成 URL 的话可能会出现读取不到路径的错误
    NSURL *fileUrl=[NSURL fileURLWithPath:_recordPath];
    // 往路径的 URL 开始写入录像 Buffer ,边录边写
    [self.fileOutput startRecordingToOutputFileURL:fileUrl recordingDelegate:self];
}

- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections
{
    NSLog(@"---- 开始录制 ----");
}

- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
{
    NSLog(@"---- 录制结束 ---- ");
}

#define VIDEOPREFIX @"zx_video_record_"

/**
 Create the file path of record video. The name of file is created based  on system timeInterval.
 */
- (NSString *)createRecordFilePath
{
    // 获取时间戳
    NSDate *datenow = [NSDate date];
    NSInteger timeSp = [[NSNumber numberWithDouble:[datenow timeIntervalSince1970]] integerValue];
    NSString *ts = [NSString stringWithFormat:@"%ld",(long)timeSp];
    NSString *recordFilePath = [[[NSTemporaryDirectory() stringByAppendingString:VIDEOPREFIX]stringByAppendingString:ts]stringByAppendingString:@".mp4"];
    return recordFilePath;
}

以上就是iOS中摄像头的基本使用。我们可以将摄像头获取的视频流,实时展示在预览Layer上。同时,也可以将视频流输出到文件中,完成录制。

如有问题,欢迎指正。

我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=cpjwfah0tqeo

你可能感兴趣的:(Camera Without Fear——iOS)