iOS 自定义相机 拍照+视频录制(一)



BSFramework 组件包:

  • 2D、3D无限轮播图组件
  • 图片视频选择、图片视频预览、图片视频拍摄组件
  • GitHub 地址
  • iOS 自定义相机 拍照+视频录制(二) 视频篇

shortshoot.gif

框架:

大致流程:

  • session 初始化
  • device 初始化
  • input,output 初始化,并关联device
  • session 添加 input 和 output
  • 初始化预览层 AVCaptureVideoPreviewLayer
  • session startRunning
  • 点击拍照, didFinishProcessingPhotoSampleBuffer 代理回调后,处理数据,生成照片

PS : 其中还含有一些摄像头翻转,闪光灯等操作,但属于额外功能,不算流程,具体全部功能看源码


一、使用 AVCaptureSession 进行拍照



需要的属性大致有

@property (nonatomic ,strong) AVCaptureSession *session;
@property (nonatomic ,strong) AVCaptureDevice *device;
@property (nonatomic ,strong) AVCaptureDeviceInput *deviceInput;//图像输入源
@property (nonatomic ,strong) AVCaptureOutput *outPut;          //图像输出源
@property (nonatomic ,strong) AVPlayer *player;
@property (nonatomic ,strong) AVPlayerLayer *playerLayer;
@property (nonatomic ,strong) AVCaptureConnection *connection;



首先处理权限问题

#pragma mark - 相机授权
-(void)authorization{
    //请求相机权限
    AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    
    if (status == AVAuthorizationStatusNotDetermined) {
        
        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
                        
            dispatch_async(dispatch_get_main_queue(), ^{
                if (granted) {
                    [self authorization];
                }else{
                    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"" message:@"相机权限未开启,请前往 手机-设置 开启相机权限" preferredStyle:UIAlertControllerStyleAlert];
                    UIAlertAction *action = [UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                        
                        [self.navigationController popViewControllerAnimated:YES];
                        [self dismissViewControllerAnimated:YES completion:nil];
                    }];
                    
                    [controller addAction:action];
                    [self presentViewController:controller animated:YES completion:nil];
                    return;
                }
            });
        }];
        
    }else if (status == AVAuthorizationStatusDenied) {
        
        UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"" message:@"相机权限未开启,请前往 手机-设置 开启相机权限" preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *action = [UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            
            [self.navigationController popViewControllerAnimated:YES];
            [self dismissViewControllerAnimated:YES completion:nil];
        }];
        
        [controller addAction:action];
        [self presentViewController:controller animated:YES completion:nil];
        
        return;
    }else if (status == AVAuthorizationStatusAuthorized){
        [self configData];
        [self initSubViews];
        [self masonryLayout];
    }
}

只有权限通过了,我才初始化 UI 界面,否则就 alert 提示。

然后初始化 session ,添加 device 、input、output

-(void)configData{
    
    self.session = [[AVCaptureSession alloc]init];
    if ([self.session canSetSessionPreset:AVCaptureSessionPresetHigh]){
        self.session.sessionPreset = AVCaptureSessionPresetHigh;
    }else if ([self.session canSetSessionPreset:AVCaptureSessionPresetiFrame960x540]) {
        self.session.sessionPreset = AVCaptureSessionPresetiFrame960x540;
    }

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //如果不放在子线程里,跳转到相机的时候,会卡
        [self addPicIO];
        [self addVideoIO];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            self.previewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:self.session];
            self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
            self.previewLayer.frame = CGRectMake(0, 30, SCREEN_WIDTH, SCREEN_HEIGHT - 30 - 150);
            [self.view.layer insertSublayer:self.previewLayer atIndex:0];
            [self.session startRunning];
        });
    });
}

#pragma mark 设置 拍照类型的输入输出源
-(void)addPicIO{
    NSError *error = nil;

    self.deviceInput = [[AVCaptureDeviceInput alloc]initWithDevice:self.device error:&error];

    if (!error) {

        if ([self.session canAddInput:self.deviceInput]) {
            [self.session addInput:self.deviceInput];
        }

        if ([self.session canAddOutput:self.outPut]) {
            [self.session addOutput:self.outPut];
        }
    }
}


点击拍照处理

#pragma mark - action 交互事件

// 拍照
-(void)takePicture{
    
    // 防止快速连点
    if (self.bottomView.recordStatus == RECORD_STATUS_UNRECORD) {
        return;
    }

    if (@available(iOS 10.0, *)) {

        AVCapturePhotoOutput *outPut = (AVCapturePhotoOutput *)self.outPut;

        AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettingsWithFormat:@{AVVideoCodecKey:AVVideoCodecJPEG}];
        [outPut capturePhotoWithSettings:settings delegate:self];
   
    }else{
        
        // 兼容iOS 10以下机型,未测试,不清楚可不可以用
        self.connection = [self.outPut connectionWithMediaType:AVMediaTypeVideo];
        [self.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];

        AVCaptureStillImageOutput *outPut = (AVCaptureStillImageOutput *)self.outPut;

        [outPut captureStillImageAsynchronouslyFromConnection:self.connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {

            [self.session stopRunning];
            
            NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
            UIImage *image = [UIImage imageWithData:jpegData];
            self.photoImageView.image = image;
            self.photoImageView.hidden = NO;
        }];
    }

    if ([self.delegate respondsToSelector:@selector(photoCameraTakeBtnClicked)]) {
        [self.delegate photoCameraTakeBtnClicked];
    }
}

代理回调处理

-(void)captureOutput:(AVCapturePhotoOutput *)output didFinishProcessingPhotoSampleBuffer:(CMSampleBufferRef)photoSampleBuffer previewPhotoSampleBuffer:(CMSampleBufferRef)previewPhotoSampleBuffer resolvedSettings:(AVCaptureResolvedPhotoSettings *)resolvedSettings bracketSettings:(AVCaptureBracketedStillImageSettings *)bracketSettings error:(NSError *)error API_AVAILABLE(ios(10.0)){

    if (photoSampleBuffer) {
        [self.session stopRunning];
        NSData *data = [AVCapturePhotoOutput JPEGPhotoDataRepresentationForJPEGSampleBuffer:photoSampleBuffer previewPhotoSampleBuffer:previewPhotoSampleBuffer];
        UIImage *image = [UIImage imageWithData:data];
        self.photoImageView.image = image;
        self.photoImageView.hidden = NO;
    }
}

PS : 此代理是 iOS 10 以后的方法,低于 iOS 10 需要使用 ↓↓↓

// 兼容iOS 10以下机型,未测试,不清楚可不可以用
    self.connection = [self.outPut connectionWithMediaType:AVMediaTypeVideo];
    [self.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];

    AVCaptureStillImageOutput *outPut = (AVCaptureStillImageOutput *)self.outPut;

    [outPut captureStillImageAsynchronouslyFromConnection:self.connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {

        [self.session stopRunning];
            
        NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
        UIImage *image = [UIImage imageWithData:jpegData];
        self.photoImageView.image = image;
        self.photoImageView.hidden = NO;
    }];

友情链接

  • GitHub 地址
  • iOS 自定义相机 拍照+视频录制(二) 视频篇

你可能感兴趣的:(iOS 自定义相机 拍照+视频录制(一))