美文网首页iOS大咖说
iOS 自定义相机 拍照+视频录制(一)

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

作者: BlackStar暗星 | 来源:发表于2020-11-09 16:20 被阅读0次

    BSFramework 组件包:


    shortshoot.gif

    框架:<AVFoundation/AVFoundation.h>

    大致流程:

    • 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) {
                
                __weak typeof(self)weakSelf = self;
                
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (granted) {
                        [weakSelf authorization];
                    }else{
                        UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"" message:@"相机权限未开启,请前往 手机-设置 开启相机权限" preferredStyle:UIAlertControllerStyleAlert];
                        UIAlertAction *action = [UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                            
                            [weakSelf.navigationController popViewControllerAnimated:YES];
                            [weakSelf dismissViewControllerAnimated:YES completion:nil];
                        }];
                        
                        [controller addAction:action];
                        [weakSelf 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;
        }];
    

    友情链接


    相关文章

      网友评论

        本文标题:iOS 自定义相机 拍照+视频录制(一)

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