• 关于自定义相机的整理


      前言 

       为什么不用系统相机要用自定义相机呢?

      由于系统相机功能单一,界面简单,在开发的过程中为了达到更好的个性化交互设计,符合app主题,提供更多更有趣的功能时候,我们会采用自定义相机。来达到更好的界面效果,更好的用户体验。接下来说说整个自定义相机过程,以及遇到的一些问题。

      概览

    1,流程

    2,详细各部分

    • 初始化,建立会话,获取摄像头
    • 嵌入实时预览图层
    • 相关设置
    • 拍摄获取照片
    • UIView层及UI交互

    3,遇到的坑

      流程

      AVCaptureSession通过把设备的麦克风/摄像头(AVCaptureDevice)实例化成数据流输入对象(AVCaptureDeviceInput)后,再通过建立连接(AVCaptionConnection)将录制数据通过数据流输出对象(AVCaptureOutput)导出,而录制的时候咱们可以同步预览当前的录制界面(AVCaptureVideoPreviewLayer).

    输出图像的时候需要用到AVCaptureConnection这个类,session通过AVCaptureConnection连接AVCaptureStillImageOutput进行图片输出,输入输出与connection的关系如下图

       详细各部分

       1.初始化,建立会话,获取摄像头

    - (AVCaptureSession *)recordSession {
        if (_recordSession == nil) {
            _recordSession = [[AVCaptureSession alloc] init];
            if ([_recordSession canAddInput:self.backCameraInput]) {
                   [_recordSession addInput:self.backCameraInput];
            }
          
             //将输入设备加入会话
             if ([_recordSession canAddOutput:self.imageOutput]) {
                   [_recordSession addOutput:self.imageOutput];
             }
    
             //设置分辨率
             if ([_recordSession canSetSessionPreset:AVCaptureSessionPresetPhoto]) {
                        [_recordSession setSessionPreset:AVCaptureSessionPresetPhoto];
             }
        }
    }
    
    //后置摄像头输入
    - (AVCaptureDeviceInput *)backCameraInput {
        if (_backCameraInput == nil) {
            NSError *error;
            _backCameraInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self backCamera] error:&error];
            if (error) {
                NSLog(@"获取后置摄像头失败~");
            }
        }
        return _backCameraInput;
    }
    
    //建立输出设备
    - (AVCaptureStillImageOutput *)imageOutput {
        if (_imageOutput == nil) {
            _imageOutput = [[AVCaptureStillImageOutput alloc]init];
            NSDictionary *settingDic = @{AVVideoCodecKey:AVVideoCodecJPEG};
            _imageOutput.outputSettings = settingDic;
    
        }
        return _imageOutput;
    }

      2.嵌入实时预览层

    //捕获到的视频呈现的layer
    - (AVCaptureVideoPreviewLayer *)previewLayer {
        if (_previewLayer == nil) {
            //通过AVCaptureSession初始化
            AVCaptureVideoPreviewLayer *preview = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.recordSession];
            //AVLayerVideoGravityResizeAspect
            //设置比例为铺满全屏AVLayerVideoGravityResizeAspectFill
            //设置比例为和预览layer一样大小 AVLayerVideoGravityResize
            preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
            _previewLayer = preview;
        }
        return _previewLayer;
    }

      

      3.相关设置

    //切换前后置摄像头
    - (void)changeCameraInputDeviceisFront:(BOOL)isFront {
        if (isFront) {
            [self.recordSession stopRunning];
            [self.recordSession removeInput:self.backCameraInput];
            if ([self.recordSession canAddInput:self.frontCameraInput]) {
                [self changeCameraAnimation];
                [self.recordSession addInput:self.frontCameraInput];
    
            }
        } else {
            [self.recordSession stopRunning];
            [self.recordSession removeInput:self.frontCameraInput];
            if ([self.recordSession canAddInput:self.backCameraInput]) {
                [self changeCameraAnimation];
                [self.recordSession addInput:self.backCameraInput];
            }
        }
    }
    
    //开启闪光灯
    - (void)openFlashLight {
        AVCaptureDevice *backCamera = [self backCamera];
        if (backCamera.flashMode == AVCaptureFlashModeOff) {
            [backCamera lockForConfiguration:nil];
            //        backCamera.torchMode = AVCaptureTorchModeOn;
            backCamera.flashMode = AVCaptureFlashModeOn;
            [backCamera unlockForConfiguration];
        }
    }
    
    //关闭闪光灯
    - (void)closeFlashLight {
        AVCaptureDevice *backCamera = [self backCamera];
        if (backCamera.flashMode == AVCaptureFlashModeOn) {
            [backCamera lockForConfiguration:nil];
            //        backCamera.torchMode = AVCaptureTorchModeOff;
            backCamera.flashMode = AVCaptureFlashModeOff;
            [backCamera unlockForConfiguration];
        }
    }
    
    //聚焦
    - (void)focusWithPoint:(CGPoint)aPoint {
        CGPoint focusPoint = [self.previewLayer captureDevicePointOfInterestForPoint:aPoint];
        AVCaptureDevice *device = [self.recordSession.inputs.lastObject device];
        if (device.isFocusPointOfInterestSupported && [device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
            if ([device lockForConfiguration:nil]) {
                device.focusPointOfInterest = focusPoint;
                device.focusMode = AVCaptureFocusModeContinuousAutoFocus;
                [device unlockForConfiguration];
            }
        }
    }

      4.拍摄获取照片

    - (void)takePhoto {
        AVCaptureConnection *connection = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
        if (connection.isVideoOrientationSupported) {
            connection.videoOrientation = [self currentVideoOrientation];
    
        }
        if ([connection isVideoStabilizationSupported]) {
            connection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeCinematic;
        }
        [self.imageOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
            UIImage *image = nil;
            NSData *data = nil;
            if (imageDataSampleBuffer != NULL) {
                data  = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
                image = [UIImage imageWithData:data];
            }
        }];
    }

      遇到的坑

    1,设置特殊分辨率的,再切换到前置摄像头闪退

      这个问题的原因在于前置摄像头不具备后置摄像头的高分辨率时,切换时就会闪退,所以在切换摄像头时要判断摄像头支持的分辨率。

    2,对焦和曝光

      我在设置对焦是 先设置了模式setFocusMode,后设置对焦位置,就会导致很奇怪的现象,对焦位置是你上次点击的位置。所以一定要先设置位置,再设置对焦模式。

    3,焦点位置

      点击屏幕时的焦点,要对应转化成摄像头上的坐标位置

      

  • 相关阅读:
    kernel list 实践
    rpm打包
    void out2() const{
    剑指offer python版 两个链表的第一个公共结点
    剑指offer python版 数组中的逆序对
    剑指offer python版 字符串中第一个只出现一次的字符
    剑指offer python版 丑数 (只含有2,3,5因子)
    剑指offer python版 最长不含重复字符的子字符
    剑指offer python版 礼物的最大价值
    剑指offer python版 数字序列中某一位的数字
  • 原文地址:https://www.cnblogs.com/Lanht/p/10556761.html
Copyright © 2020-2023  润新知