iOS媒體捕捉
一、捕捉類介紹
-
捕捉會話AVCaptureSession
AV Foundation捕捉棧的核心類是AVCaptureSession,這個類相當與一個插排,用于連接配接輸入和輸出資源,
捕捉會話還可以額外配置一個會話預設值(session preset)用來控制捕捉資料的格式和品質
-
捕捉裝置AVCaptureDevice
AVCaptureDevice為攝像頭或麥克風等實體裝置定義了一個接口,它針對實體硬體裝置定義了大量的控制
//根據媒體類型傳回一個系統指定的預設裝置 AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
-
捕捉裝置的輸入AVCaptureDeviceInput
AVCaptureDevice不能之間介入會話,需要借助AVCaptureDeviceInput執行個體來封裝一下
NSError *error = nil; AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
-
捕捉的輸出AVCaptureOutput
AVCaptureOutput是一個抽象基類,AVFoundation定義了一些這個抽象類的進階拓展類
- AVCaptureStillImageOutput:靜态圖檔輸出
- AVCaptureMovieFileOutput:視訊輸出
- AVCaptureVideoDataOutput:視訊資料輸出
- AVCaptureAudioDataOutput:音頻資料輸出
-
捕捉連接配接AVCaptureConnection
捕捉會話需要确定有給定捕捉裝置輸入渲染的媒體類型,并自動建立其能夠接收該媒體類型的捕捉輸出端的連接配接。
-
捕捉預覽AVCaptureVideoPreviewLayer
AVCaptureVideoPreviewLayer可以預覽正在捕捉的畫面
二、建立捕捉
建立捕捉的步驟
- 建立一個一個AVCaptureSession
- 擷取一個AVCaptureDevice
- 為AVCaptureDevice建立一個AVCaptureDeviceInput
- 将AVCaptureDeviceInput添加到AVCaptureSession
- 建立一個AVCaptureDeviceOutPut
- 将AVCaptureDeviceOutPut添加到AVCaptureSession
- AVCaptureSession開始捕捉
- 配置會話
- (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; }
- 開始停止捕捉
- (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]; }); } }
- 切換攝像頭
//擷取指定位置相機裝置 - (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]; }
- 設定聚焦點
- (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]; } } }
- 點選曝光
- (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]; } } }
- 設定閃光燈
- (void)setFlashMode:(AVCaptureFlashMode)flashMode { if([_videoDevice isFlashModeSupported:flashMode]){ NSError *error = nil; if([_videoDevice lockForConfiguration:&error]){ _videoDevice.flashMode = flashMode; [_videoDevice unlockForConfiguration]; } } }
- 設定手電筒
- (void)setTorchMode:(AVCaptureTorchMode)torchMode { if([_videoDevice isTorchModeSupported:torchMode]){ NSError *error = nil; if([_videoDevice lockForConfiguration:&error]){ _videoDevice.torchMode = torchMode; [_videoDevice unlockForConfiguration]; } } }
- 捕捉靜态圖檔
- (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; }
- 開始停止錄制
//開始錄制 - (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]; } }