天天看點

iOS捕捉圖像iOS媒體捕捉

iOS媒體捕捉

iOS捕捉圖像iOS媒體捕捉

一、捕捉類介紹

  1. 捕捉會話AVCaptureSession

    AV Foundation捕捉棧的核心類是AVCaptureSession,這個類相當與一個插排,用于連接配接輸入和輸出資源,

    捕捉會話還可以額外配置一個會話預設值(session preset)用來控制捕捉資料的格式和品質

  2. 捕捉裝置AVCaptureDevice

    AVCaptureDevice為攝像頭或麥克風等實體裝置定義了一個接口,它針對實體硬體裝置定義了大量的控制

    //根據媒體類型傳回一個系統指定的預設裝置
    AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
               
  3. 捕捉裝置的輸入AVCaptureDeviceInput

    AVCaptureDevice不能之間介入會話,需要借助AVCaptureDeviceInput執行個體來封裝一下

    NSError *error = nil;
    AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
               
  4. 捕捉的輸出AVCaptureOutput

    AVCaptureOutput是一個抽象基類,AVFoundation定義了一些這個抽象類的進階拓展類

    • AVCaptureStillImageOutput:靜态圖檔輸出
    • AVCaptureMovieFileOutput:視訊輸出
    • AVCaptureVideoDataOutput:視訊資料輸出
    • AVCaptureAudioDataOutput:音頻資料輸出
  5. 捕捉連接配接AVCaptureConnection

    捕捉會話需要确定有給定捕捉裝置輸入渲染的媒體類型,并自動建立其能夠接收該媒體類型的捕捉輸出端的連接配接。

  6. 捕捉預覽AVCaptureVideoPreviewLayer

    AVCaptureVideoPreviewLayer可以預覽正在捕捉的畫面

二、建立捕捉

建立捕捉的步驟

  • 建立一個一個AVCaptureSession
  • 擷取一個AVCaptureDevice
  • 為AVCaptureDevice建立一個AVCaptureDeviceInput
  • 将AVCaptureDeviceInput添加到AVCaptureSession
  • 建立一個AVCaptureDeviceOutPut
  • 将AVCaptureDeviceOutPut添加到AVCaptureSession
  • AVCaptureSession開始捕捉
    1. 配置會話
    - (BOOL)setupSession {
    
     //設定session
     self.session = [[AVCaptureSession alloc] init];
     if([self.session canSetSessionPreset:AVCaptureSessionPresetMedium]){
         self.session.sessionPreset = AVCaptureSessionPresetMedium;
     }
    
     //設定視訊輸入裝置
     _videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
     _videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_videoDevice error:nil];
     if(_videoDeviceInput){
         if([self.session canAddInput:_videoDeviceInput]){
             [self.session addInput:_videoDeviceInput];
         }
     }else{
         return NO;
     }
    
     //設定音頻輸入裝置
     _audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
     _audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_audioDevice error:nil];
     if(_audioDeviceInput){
         if([self.session canAddInput:_audioDeviceInput]){
             [self.session addInput:_audioDeviceInput];
         }
     }else{
         return NO;
     }
    
     //設定視訊資料輸出
     _videoDataOutPut = [[AVCaptureMovieFileOutput alloc] init];
     if([self.session canAddOutput:_videoDataOutPut]){
         [self.session addOutput:_videoDataOutPut];
     }
    
     //設定圖檔輸出
     _stillImageOutPut = [[AVCaptureStillImageOutput alloc] init];
     _stillImageOutPut.outputSettings = @{AVVideoCodecKey:AVVideoCodecJPEG};
     if([self.session canAddOutput:_stillImageOutPut]){
         [self.session addOutput:_stillImageOutPut];
     }
    
     //運作線程
     _vidoQueue = dispatch_queue_create("Sun.VideoQueue", DISPATCH_QUEUE_SERIAL);
    
     return YES;
    }
               
    1. 開始停止捕捉
    - (void)startSession {
     if(self.session.isRunning == NO){
         dispatch_async(_vidoQueue, ^{
             [self.session startRunning];
         });
     }
    }
    
    - (void)stopSession {
     if(self.session.isRunning == YES){
         dispatch_async(_vidoQueue, ^{
             [self.session stopRunning];
         });
     }
    }
               
    1. 切換攝像頭
    //擷取指定位置相機裝置
    - (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position {
    
     NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
     for(AVCaptureDevice *device in devices){
         if(device.position == position){
             return device;
         }
     }
     return nil;
    }
    //是否可以切換攝像頭
    - (BOOL)canSwitchCamera {
     NSInteger count = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo].count;
     return (count>?YES:NO);
    }
    //沒有使用的攝像頭
    - (AVCaptureDevice *)inactiveCamera {
    
     AVCaptureDevice *device = nil;
     if([self canSwitchCamera]){
         if(self.videoDevice.position == AVCaptureDevicePositionBack){
             device = [self cameraWithPosition:AVCaptureDevicePositionFront];
         }else{
             device = [self cameraWithPosition:AVCaptureDevicePositionBack];
         }
     }
     return device;
    }
    //切換攝像頭
    - (void)swithCamera {
    
     if([self canSwitchCamera] == NO){
         return;
     }
    
     AVCaptureDevice *videoDevice = [self inactiveCamera];
     AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:nil];
     if(videoDeviceInput){
    
         [self.session beginConfiguration];
         [self.session removeInput:_videoDeviceInput];
         if([self.session canAddInput:videoDeviceInput]){
    
             [self.session addInput:videoDeviceInput];
             _videoDevice = videoDevice;
             _videoDeviceInput = videoDeviceInput;
         }else{
             [self.session addInput:_videoDeviceInput];
         }
         [self.session commitConfiguration];
     }
               
    1. 設定聚焦點
    - (void)focusAtPoint:(CGPoint)point {
     //轉換為裝置坐标
     AVCaptureVideoPreviewLayer *layer = (AVCaptureVideoPreviewLayer *)self.layer;
     point = [layer captureDevicePointOfInterestForPoint:point];
    
     if(_videoDevice.focusPointOfInterestSupported && [_videoDevice isFocusModeSupported:(AVCaptureFocusModeAutoFocus)]){
    
         NSError *error = nil;
         if([_videoDevice lockForConfiguration:&error]){
    
             _videoDevice.focusPointOfInterest = point;
             _videoDevice.focusMode = AVCaptureFocusModeAutoFocus;
             [_videoDevice unlockForConfiguration];
         }
     }
    }
               
    1. 點選曝光
    - (void)exposeAtPoint:(CGPoint)point {
    
     AVCaptureVideoPreviewLayer *layer = (AVCaptureVideoPreviewLayer *)self.layer;
     point = [layer captureDevicePointOfInterestForPoint:point];
    
     if(_videoDevice.isExposurePointOfInterestSupported && [_videoDevice isExposureModeSupported:AVCaptureExposureModeAutoExpose]){
    
         NSError *error = nil;
         if([_videoDevice lockForConfiguration:&error]){
    
             _videoDevice.exposurePointOfInterest = point;
             _videoDevice.exposureMode = AVCaptureExposureModeAutoExpose;
             [_videoDevice unlockForConfiguration];
         }
     }
    }
               
    1. 設定閃光燈
    - (void)setFlashMode:(AVCaptureFlashMode)flashMode {
    
     if([_videoDevice isFlashModeSupported:flashMode]){
    
         NSError *error = nil;
         if([_videoDevice lockForConfiguration:&error]){
             _videoDevice.flashMode = flashMode;
             [_videoDevice unlockForConfiguration];
         }
     }
    }
               
    1. 設定手電筒
    - (void)setTorchMode:(AVCaptureTorchMode)torchMode {
    
     if([_videoDevice isTorchModeSupported:torchMode]){
    
         NSError *error = nil;
         if([_videoDevice lockForConfiguration:&error]){
             _videoDevice.torchMode = torchMode;
             [_videoDevice unlockForConfiguration];
         }
     }
    }
               
    1. 捕捉靜态圖檔
    - (void)captureStillImage {
    
       AVCaptureConnection *connection = [_stillImageOutPut connectionWithMediaType:AVMediaTypeVideo];
       //調整圖檔方向
       if(connection.isVideoOrientationSupported){
           connection.videoOrientation = [self currentVideoOrientation];
       }
    
       [_stillImageOutPut captureStillImageAsynchronouslyFromConnection:connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
    
           if(imageDataSampleBuffer != NULL){
               NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
               UIImage *image = [UIImage imageWithData:imageData];
           }
       }];
    }
    
    - (AVCaptureVideoOrientation)currentVideoOrientation {
    
       AVCaptureVideoOrientation orientation;
       switch ([UIDevice currentDevice].orientation) {
           case UIDeviceOrientationPortrait:{
               orientation = AVCaptureVideoOrientationPortrait;
               break;
           }
           case UIDeviceOrientationLandscapeRight:{
               orientation = AVCaptureVideoOrientationLandscapeRight;
               break;
           }
           case UIDeviceOrientationLandscapeLeft:{
               orientation = AVCaptureVideoOrientationLandscapeLeft;
               break;
           }
           default:
               orientation = AVCaptureVideoOrientationPortrait;
               break;
       }
       return orientation;
    }
               
    1. 開始停止錄制
    //開始錄制
    - (void)startRecoding {
    
       if(_videoDataOutPut.isRecording == NO){
    
           AVCaptureConnection *connection = [_videoDataOutPut connectionWithMediaType:AVMediaTypeVideo];
           //設定裝置旋轉
           if([connection isVideoOrientationSupported]){
               connection.videoOrientation = [self currentVideoOrientation];
           }
           //設定視訊穩定模式
           if([connection isVideoStabilizationSupported]){
               connection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
           }
           //平滑聚焦
           if(_videoDevice.isSmoothAutoFocusSupported){
               NSError *error = nil;
               if([_videoDevice lockForConfiguration:&error]){
                   _videoDevice.smoothAutoFocusEnabled = YES;
                   [_videoDevice unlockForConfiguration];
               }
           }
    
           NSURL *outputUrl = [NSURL URLWithString:@""];
           [_videoDataOutPut startRecordingToOutputFileURL:outputUrl recordingDelegate:self];
    
       }
    }
    //定制錄制
    - (void)stopRecording {
    
       if(_videoDataOutPut.isRecording){
           [_videoDataOutPut stopRecording];
       }
    }