美文网首页AV Foundation专题
AVFoundation:捕捉媒体

AVFoundation:捕捉媒体

作者: MonKey_Money | 来源:发表于2020-09-02 00:11 被阅读0次
    image.png

    捕捉会话 AVCaptureSession

    AVFoundation捕捉栈的核心类是AVCaptureSession。一个捕捉会话相当于一个虚拟的“插线板”,用于连接输入和输出的资源。
    捕捉会话管理从屋里设备得到的数据流,比如摄像头和麦克风设备,输出到一个或多个目的地。可以动态配置输入和输出的线路,可以再会话进行中按需配置捕捉环境。
    捕捉会话还可以额外配置一个会话预设值(session preset),用来控制捕捉数据的格式和质量。会话预设值默认为AVCaptureSessionPresetHigh,适用于大多数情况。还有很多预设值,可以根据需求设置。

    捕捉设备 AVCaptureDevice

    AVCaptureDevice为摄像头或麦克风等物理设备定义了一个接口。对硬件设备定义了大量的控制方法,如对焦、曝光、白平衡和闪光灯等。
    AVCaptureDevice定义大量类方法用用访问系统的捕捉设备,最常用的是defaultDeviceWithMediaType:,根据给定的媒体类型返回一个系统指定的默认设备
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];请求的是一个默认的视频设备,在包含前置和后置摄像头的iOS系统,返回后置摄像头。

    捕捉设备的输入 AVCaptureInput

    AVCaptureInput是一个抽象类,提供一个连接接口将捕获到的输入源连接到AVCaptureSession。
    抽象类无法直接使用,只能通过其子类满足需求:AVCaptureDeviceInput-使用该对象从AVCaptureDevice获取设备数据(摄像头、麦克风等)、AVCaptureScreenInput-通过屏幕获取数据(如录屏)、AVCaptureMetaDataInput-获取元数据
    以 AVCaptureDeviceInput 为例
    使用捕捉设备进行处理前,需要将它添加为捕捉会话的输入。通过将设备(AVCaptureDevice)封装到AVCaptureDeviceInput实例中,实现将设备插入到AVCaptureSession中。
    AVCaptureDeviceInput在设备输出数据和捕捉会话间,扮演接线板的作用。

    //AVMediaTypeVideo指视频,也可以设置音频AVMediaTypeAudio
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    NSError *error;
    AVCaptureDeviceInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];
    

    坐标空间转换

    对于iphone 5手机 屏幕左上角为(0,0),垂直模式下右下角坐标为(320,568)。
    水平模式下右下角为(568,320)。捕捉设备坐标系有着不同的定义,他们通常是基于摄像头传感器的本地设置,左上角为(0,0),右下角为(1,1),AVCaptureVideoPreviewLayer提供两个方法,让两者之间相互转换
    captureDevicePointOfInterestForPoint :获取屏幕坐标系的CGPoint数据,返回转换得到设备坐标系CGPoint数据
    pointForCaptureDevicePointOfInterest:获取摄像头坐标系的CGPoint数据,返回转换得到屏幕坐标系CGPoint数据。

    设置输出

        // Setup the still image output//拍照
        self.imageOutput = [[AVCaptureStillImageOutput alloc] init];            // 8
        self.imageOutput.outputSettings = @{AVVideoCodecKey : AVVideoCodecJPEG};
    
        if ([self.captureSession canAddOutput:self.imageOutput]) {
            [self.captureSession addOutput:self.imageOutput];
        }
    
        // Setup movie file output //视频记录
        self.movieOutput = [[AVCaptureMovieFileOutput alloc] init];             // 9
    
        if ([self.captureSession canAddOutput:self.movieOutput]) {
            [self.captureSession addOutput:self.movieOutput];
        }
    //记录视频方法
    - (void)startRecording {
    
        if (![self isRecording]) {
    
            AVCaptureConnection *videoConnection =                              // 2
                [self.movieOutput connectionWithMediaType:AVMediaTypeVideo];
    
            if ([videoConnection isVideoOrientationSupported]) {                // 3
                videoConnection.videoOrientation = self.currentVideoOrientation;
            }
    
            if ([videoConnection isVideoStabilizationSupported]) {              // 4
                
                videoConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
                
                // Deprecated approach below
                // videoConnection.enablesVideoStabilizationWhenAvailable = YES;
            }
    
            AVCaptureDevice *device = [self activeCamera];
    
            if (device.isSmoothAutoFocusSupported) {                            // 5
                NSError *error;
                if ([device lockForConfiguration:&error]) {
                    device.smoothAutoFocusEnabled = NO;
                    [device unlockForConfiguration];
                } else {
                    [self.delegate deviceConfigurationFailedWithError:error];
                }
            }
    
            self.outputURL = [self uniqueURL];                                  // 6
            [self.movieOutput startRecordingToOutputFileURL:self.outputURL      // 8
                                          recordingDelegate:self];
    
        }
    }
    //拍照
    - (void)captureStillImage {
        AVCaptureConnection *connection =                                   
            [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
        if (connection.isVideoOrientationSupported) {                       
            connection.videoOrientation = [self currentVideoOrientation];
        }
        id handler = ^(CMSampleBufferRef sampleBuffer, NSError *error) {
            if (sampleBuffer != NULL) {
                NSData *imageData =
                    [AVCaptureStillImageOutput
                        jpegStillImageNSDataRepresentation:sampleBuffer];
                UIImage *image = [[UIImage alloc] initWithData:imageData];
                [self writeImageToAssetsLibrary:image];                         // 1
            } else {
                NSLog(@"NULL sampleBuffer: %@", [error localizedDescription]);
            }
        };
        // Capture still image
        [self.imageOutput captureStillImageAsynchronouslyFromConnection:connection
                                                      completionHandler:handler];
    }
    

    切换摄像头

    - (BOOL)switchCameras {
    
        if (![self canSwitchCameras]) {                                         // 1
            return NO;
        }
    
        NSError *error;
        AVCaptureDevice *videoDevice = [self inactiveCamera];                   // 2
    
        AVCaptureDeviceInput *videoInput =
        [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
    
        if (videoInput) {
            [self.captureSession beginConfiguration];                           // 3
    
            [self.captureSession removeInput:self.activeVideoInput];            // 4
    
            if ([self.captureSession canAddInput:videoInput]) {                 // 5
                [self.captureSession addInput:videoInput];
                self.activeVideoInput = videoInput;
            } else {
                [self.captureSession addInput:self.activeVideoInput];
            }
    
            [self.captureSession commitConfiguration];                          // 6
    
        } else {
            [self.delegate deviceConfigurationFailedWithError:error];           // 7
            return NO;
        }
    
        return YES;
    }
    - (AVCaptureDevice *)inactiveCamera {                                       // 4
        AVCaptureDevice *device = nil;
        if (self.cameraCount > 1) {
            if ([self activeCamera].position == AVCaptureDevicePositionBack) {  // 5
                device = [self cameraWithPosition:AVCaptureDevicePositionFront];
            } else {
                device = [self cameraWithPosition:AVCaptureDevicePositionBack];
            }
        }
        return device;
    }
    - (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position { // 1
        NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
        for (AVCaptureDevice *device in devices) {                              // 2
            if (device.position == position) {
                return device;
            }
        }
        return nil;
    }
    

    配置设备对焦模式

    - (BOOL)cameraSupportsTapToFocus {                                          // 1
        return [[self activeCamera] isFocusPointOfInterestSupported];
    }
    
    - (void)focusAtPoint:(CGPoint)point {                                       // 2
    
        AVCaptureDevice *device = [self activeCamera];
    
        if (device.isFocusPointOfInterestSupported &&                           // 3
            [device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
    
            NSError *error;
            if ([device lockForConfiguration:&error]) {                         // 4
                device.focusPointOfInterest = point;
                device.focusMode = AVCaptureFocusModeAutoFocus;
                [device unlockForConfiguration];
            } else {
                [self.delegate deviceConfigurationFailedWithError:error];
            }
        }
    }
    

    重新设置对焦和曝光

    - (void)resetFocusAndExposureModes {
    
        AVCaptureDevice *device = [self activeCamera];
    
        AVCaptureExposureMode exposureMode =
        AVCaptureExposureModeContinuousAutoExposure;
    
        AVCaptureFocusMode focusMode = AVCaptureFocusModeContinuousAutoFocus;
    
        BOOL canResetFocus = [device isFocusPointOfInterestSupported] &&        // 1
        [device isFocusModeSupported:focusMode];
    
        BOOL canResetExposure = [device isExposurePointOfInterestSupported] &&  // 2
        [device isExposureModeSupported:exposureMode];
    
        CGPoint centerPoint = CGPointMake(0.5f, 0.5f);                          // 3
    
        NSError *error;
        if ([device lockForConfiguration:&error]) {
    //对焦
            if (canResetFocus) {                                                // 4
                device.focusMode = focusMode;
                device.focusPointOfInterest = centerPoint;
            }
    //曝光
            if (canResetExposure) {                                             // 5
                device.exposureMode = exposureMode;
                device.exposurePointOfInterest = centerPoint;
            }
            
            [device unlockForConfiguration];
            
        } else {
            [self.delegate deviceConfigurationFailedWithError:error];
        }
    }
    

    调整闪光灯和手电筒

    typedef NS_ENUM(NSInteger, AVCaptureFlashMode) {
        AVCaptureFlashModeOff  = 0, //闪光关闭
        AVCaptureFlashModeOn   = 1,//闪光开启
        AVCaptureFlashModeAuto = 2,//闪光自适应
    }
    typedef NS_ENUM(NSInteger, AVCaptureTorchMode) {
        AVCaptureTorchModeOff  = 0,//手电筒关闭
        AVCaptureTorchModeOn   = 1,//手电筒开启
        AVCaptureTorchModeAuto = 2,//自动
    }
    - (BOOL)cameraHasFlash {
        return [[self activeCamera] hasFlash];
    }
    
    - (AVCaptureFlashMode)flashMode {
        return [[self activeCamera] flashMode];
    }
    
    - (void)setFlashMode:(AVCaptureFlashMode)flashMode {
    
        AVCaptureDevice *device = [self activeCamera];
    
        if (device.flashMode != flashMode &&
            [device isFlashModeSupported:flashMode]) {
    
            NSError *error;
            if ([device lockForConfiguration:&error]) {
                device.flashMode = flashMode;
                [device unlockForConfiguration];
            } else {
                [self.delegate deviceConfigurationFailedWithError:error];
            }
        }
    }
    
    - (BOOL)cameraHasTorch {
        return [[self activeCamera] hasTorch];
    }
    
    - (AVCaptureTorchMode)torchMode {
        return [[self activeCamera] torchMode];
    }
    
    - (void)setTorchMode:(AVCaptureTorchMode)torchMode {
    
        AVCaptureDevice *device = [self activeCamera];
    
        if (device.torchMode != torchMode &&
            [device isTorchModeSupported:torchMode]) {
    
            NSError *error;
            if ([device lockForConfiguration:&error]) {
                device.torchMode = torchMode;
                [device unlockForConfiguration];
            } else {
                [self.delegate deviceConfigurationFailedWithError:error];
            }
        }
    }
    

    捕捉静态图片

    - (void)captureStillImage {
    
        AVCaptureConnection *connection =                                   
            [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
    
        if (connection.isVideoOrientationSupported) {                       
            connection.videoOrientation = [self currentVideoOrientation];
        }
    
        id handler = ^(CMSampleBufferRef sampleBuffer, NSError *error) {
            if (sampleBuffer != NULL) {
    
                NSData *imageData =
                    [AVCaptureStillImageOutput
                        jpegStillImageNSDataRepresentation:sampleBuffer];
    
                UIImage *image = [[UIImage alloc] initWithData:imageData];
                [self writeImageToAssetsLibrary:image];                         // 1
    
            } else {
                NSLog(@"NULL sampleBuffer: %@", [error localizedDescription]);
            }
        };
        // Capture still image
        [self.imageOutput captureStillImageAsynchronouslyFromConnection:connection
                                                      completionHandler:handler];
    }
    

    保存相册

    - (void)writeImageToAssetsLibrary:(UIImage *)image {
    
        
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            [PHAssetChangeRequest  creationRequestForAssetFromImage:image];
        } completionHandler:^(BOOL success, NSError * _Nullable error) {
            if (success) {
                NSLog(@"成功");
            } else {
                NSLog(@"失败");            
            }
        }];
    
    }
    

    视频捕捉

    
    - (BOOL)isRecording {                                                       // 1
        return self.movieOutput.isRecording;
    }
    
    - (void)startRecording {
    
        if (![self isRecording]) {
    
            AVCaptureConnection *videoConnection =                              // 2
                [self.movieOutput connectionWithMediaType:AVMediaTypeVideo];
    
            if ([videoConnection isVideoOrientationSupported]) {                // 3
                videoConnection.videoOrientation = self.currentVideoOrientation;
            }
    
            if ([videoConnection isVideoStabilizationSupported]) {              // 4
                
                videoConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
                
                // Deprecated approach below
                // videoConnection.enablesVideoStabilizationWhenAvailable = YES;
            }
            AVCaptureDevice *device = [self activeCamera];
    
            if (device.isSmoothAutoFocusSupported) {                            // 5
                NSError *error;
                if ([device lockForConfiguration:&error]) {
                    device.smoothAutoFocusEnabled = NO;
                    [device unlockForConfiguration];
                } else {
                    [self.delegate deviceConfigurationFailedWithError:error];
                }
            }
            self.outputURL = [self uniqueURL];                                  // 6
            [self.movieOutput startRecordingToOutputFileURL:self.outputURL      // 8
                                          recordingDelegate:self];
        }
    }
    
    - (CMTime)recordedDuration {
        return self.movieOutput.recordedDuration;
    }
    
    - (NSURL *)uniqueURL {                                                      // 7
    
        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSString *dirPath =
            [fileManager temporaryDirectoryWithTemplateString:@"kamera.XXXXXX"];
    
        if (dirPath) {
            NSString *filePath =
                [dirPath stringByAppendingPathComponent:@"kamera_movie.mov"];
            return [NSURL fileURLWithPath:filePath];
        }
    
        return nil;
    }
    
    - (void)stopRecording {                                                     // 9
        if ([self isRecording]) {
            [self.movieOutput stopRecording];
        }
    }
    

    录制视频写入相册

    - (void)captureOutput:(AVCaptureFileOutput *)captureOutput
    didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
          fromConnections:(NSArray *)connections
                    error:(NSError *)error {
        if (error) {                                                            // 1
            [self.delegate mediaCaptureFailedWithError:error];
        } else {
            [self writeVideoToAssetsLibrary:[self.outputURL copy]];
        }
        self.outputURL = nil;
    }
    
    - (void)writeVideoToAssetsLibrary:(NSURL *)videoURL {
    
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            [PHAssetChangeRequest  creationRequestForAssetFromVideoAtFileURL:videoURL];
        } completionHandler:^(BOOL success, NSError * _Nullable error) {
            if (success) {
                NSLog(@"成功");
                
            } else {
                NSLog(@"失败");
    
            }
        }];
    
    }
    

    相关文章

      网友评论

        本文标题:AVFoundation:捕捉媒体

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