視頻錄制和自定義拍照

最近在學(xué)習(xí)視頻錄制方面的東西,在網(wǎng)上找了篇博客,寫的非常詳細(xì),這里是對(duì)這篇文章的學(xué)習(xí)

詞匯介紹

  • AVCaptureSession: 媒體(音頻、視頻)捕捉會(huì)話,負(fù)責(zé)把捕捉的音視頻數(shù)據(jù)輸出到輸出設(shè)備,一個(gè)捕捉會(huì)話可以有多個(gè)輸入輸出
  • AVCaptureDevice: 輸入設(shè)備 包括攝像頭、話筒等,通過該對(duì)象可以設(shè)置物理設(shè)備的屬性(相機(jī)的聚焦白平衡等)
  • AVCaptureDeviceInput: 輸入數(shù)據(jù)管理對(duì)象,可以根據(jù)AVCaptureDevice創(chuàng)建對(duì)應(yīng)的AVCaptureDeviceInput對(duì)象,該對(duì)象將會(huì)被添加到AVCaptureSession中管理
  • AVCaptureOutput:輸出數(shù)據(jù)管理對(duì)象,用于接受各類輸出數(shù)據(jù),通常使用其子類AVCaptureAudioDataOutput、AVCaptureStillImageOutput、AVCaptureVideoDataOutput、AVCaptureFileOutput,該對(duì)象將會(huì)被添加到AVCaptureSession中管理。注意:前面幾個(gè)對(duì)象的輸出數(shù)據(jù)都是NSData類型,而AVCaptureFileOutput代表數(shù)據(jù)以文件形式輸出,類似的,AVCcaptureFileOutput也不會(huì)直接創(chuàng)建使用,通常會(huì)使用其子類:AVCaptureAudioFileOutput、AVCaptureMovieFileOutput。當(dāng)把一個(gè)輸入或者輸出添加到AVCaptureSession
  • AVCaptrueVideoPreviewLayer: 相機(jī)拍攝預(yù)覽圖層,是CAPlayer的子類,使用該對(duì)象可以實(shí)時(shí)查看拍攝和視頻錄制的效果,創(chuàng)建該對(duì)象需要指定對(duì)應(yīng)的AVCaptureSession對(duì)象

使用AVFoundation框架實(shí)現(xiàn)拍照和視頻錄制的一般步驟

  1. 創(chuàng)建AVCaptureSession對(duì)象
  2. 使用AVCaptureDevice靜態(tài)方法獲得所需的設(shè)備,例如拍照和視頻就需要獲取攝像頭設(shè)備,錄音就需要獲取話筒設(shè)備
  3. 利用輸入設(shè)備AVCaptureDevice創(chuàng)建AVCaptureDeviceInput對(duì)象
  4. 初始化數(shù)據(jù)輸出管理對(duì)象,如果要拍照就初始化AVCaptureStillImageOutput對(duì)象,如果要錄制視頻就初始化AVCaptureMovieFileOutput對(duì)象
  5. 將數(shù)據(jù)輸入對(duì)象(AVCaptureDeviceInput)、數(shù)據(jù)輸出對(duì)象(AVCaptureOutput)添加進(jìn)媒體會(huì)話AVCaptureSession中
  6. 創(chuàng)建視頻預(yù)覽圖層AVCaptureVideoPreviewLayer并指定媒體會(huì)話,添加圖層到顯示容器中,并調(diào)用AVCaptureSession的startRunning方法開始捕捉
  7. 將捕獲的音頻或者視頻保存到指定文件

自定義拍照

我們將實(shí)現(xiàn)攝像頭預(yù)覽,攝像頭切換,閃光燈設(shè)置,對(duì)焦,拍照保存等功能

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    //1.初始化捕捉會(huì)話
    //1.1.初始化
    _session = [[AVCaptureSession alloc] init];
    //1.2.設(shè)置分辨率
    if ([_session canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
        [_session setSessionPreset:AVCaptureSessionPreset1280x720];
    }
    
    //2.獲得輸入設(shè)備 后置攝像頭
    AVCaptureDevice *captureDevice = [self getCameraDeviceWithPosition:AVCaptureDevicePositionBack];
    if (captureDevice == nil) {
        NSLog(@"獲取后置攝像頭失敗");
        return;
    }
    NSError *error = nil;
    //3.根據(jù)輸入設(shè)備創(chuàng)建輸入數(shù)據(jù)管理對(duì)象
    AVCaptureDeviceInput *captureInput = [[AVCaptureDeviceInput alloc] initWithDevice:captureDevice error:&error];
    self.captureDeviceInput = captureInput;
    if (error) {
        NSLog(@"取得設(shè)備輸入對(duì)象時(shí)出錯(cuò),%@", error.localizedDescription);
        return;
    }
    
    //4.創(chuàng)建輸出數(shù)據(jù)管理對(duì)象 用于獲得輸出數(shù)據(jù)
    AVCaptureStillImageOutput *imageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSettings = @{AVVideoCodecKey:AVVideoCodecJPEG};
    [imageOutput setOutputSettings:outputSettings];//輸出設(shè)置
    self.imageOutput = imageOutput;
    
    //5.添加輸入設(shè)備管理對(duì)象到捕捉會(huì)話
    if ([_session canAddInput:_captureDeviceInput]) {
        [_session addInput:_captureDeviceInput];
    }
    
    //6.添加輸出源
    if ([_session canAddOutput:_imageOutput]) {
        [_session addOutput:_imageOutput];
    }
    
    //7.設(shè)置預(yù)覽圖層
    _previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_session];
    _previewLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;//填充模式
    _previewLayer.frame = self.view.bounds;
    [self.view.layer insertSublayer:_previewLayer atIndex:0];
    
    //8.給設(shè)備添加通知 監(jiān)測(cè)監(jiān)控區(qū)域的變化
    [self addNotificationToCaptureDevice:captureDevice];
    
    //9.添加手勢(shì)
    [self addGestureToView];
}



viewWillApper:方法里面創(chuàng)建媒體捕捉會(huì)話,并添加輸入源、輸出源,添加對(duì)輸入設(shè)備的通知,監(jiān)測(cè)設(shè)備監(jiān)控區(qū)域的變化(拍照對(duì)準(zhǔn)的區(qū)域發(fā)生變化等等),添加手勢(shì)來聚焦和調(diào)整光標(biāo)位置,在viewDidAppear:方法中開始會(huì)話捕捉,在 viewDidDisappear:中停止會(huì)話捕捉

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    
    [_session startRunning];
}
- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    [_session stopRunning];
}

定義閃光燈開閉及自動(dòng)模式功能,注意無論是設(shè)置閃光燈、白平衡還是其他輸入設(shè)備屬性,在設(shè)置之前必須先鎖定配置,修改完后解鎖。

/* 定義閃光燈開閉及自動(dòng)模式功能,注意無論是設(shè)置閃光燈、白平衡還是其他輸入設(shè)備屬性,在設(shè)置之前必須先鎖定配置,修改完后解鎖。 */
/* 改變?cè)O(shè)備屬性 進(jìn)行的是鎖住設(shè)備操作 通過block返回輸入設(shè)備 */
- (void)changeDeviceProperty:(PropertyChangeBlock)block {
    //1.獲得設(shè)備
    AVCaptureDevice *device = self.captureDeviceInput.device;
    NSError *error;
    //2.鎖住設(shè)備
    BOOL success = [device lockForConfiguration:&error];
    if (success) {
        //1.鎖定成功 通過block返回輸入設(shè)備
        block(device);
        //2.解鎖
        [device unlockForConfiguration];
    }
    else {
        NSLog(@"設(shè)置設(shè)備屬性過程發(fā)生錯(cuò)誤,錯(cuò)誤信息%@", error.localizedDescription);
    }
    
}

添加通知的方法

- (void)addNotificationToCaptureDevice:(AVCaptureDevice *)device {
    //1.先鎖住輸入設(shè)備
    [self changeDeviceProperty:^(AVCaptureDevice *device) {
        //添加區(qū)域改變捕獲通知必須首先設(shè)置設(shè)備允許捕獲
        //表明接收方是否應(yīng)該監(jiān)控領(lǐng)域的變化(如照明變化,實(shí)質(zhì)移動(dòng)等) 可以通過AVCaptureDeviceSubjectAreaDidChangeNotification通知監(jiān)測(cè) 我們可以希望重新聚焦,調(diào)整曝光白平衡等的主題區(qū)域 在設(shè)置該屬性之前必須調(diào)用lockForConfiguration方法鎖定設(shè)備配置
        device.subjectAreaChangeMonitoringEnabled = YES;
    }];
    
    //2.監(jiān)測(cè)通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(areaChanged:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:device];
    
}

在通知方法里打印下log

#pragma mark -設(shè)備捕獲區(qū)域發(fā)生變化
- (void)areaChanged:(NSNotification *)notification {
       NSLog(@"捕獲區(qū)域改變...");
}

移除通知的方法

/* 移除監(jiān)控輸入設(shè)備通知 */
- (void)removeNotificationFromCaptureDevice:(AVCaptureDevice *)device {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:device];
}

添加手勢(shì)


- (void)addGestureToView {    
 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapScreen:)];
    [self.view addGestureRecognizer:tap];
}
-(void)tapScreen:(UITapGestureRecognizer *)tapGesture {
    CGPoint point = [tapGesture locationInView:self.view];
    //UI坐標(biāo)轉(zhuǎn)換成攝像頭坐標(biāo)
    CGPoint cameraPoint = [self.previewLayer captureDevicePointOfInterestForPoint:point];
    [self setFocusPoint:cameraPoint];
    
    [self focusWithMode:AVCaptureFocusModeAutoFocus exposureMode:AVCaptureExposureModeAutoExpose atPoint:cameraPoint];
}

在手勢(shì)方法里面設(shè)置光標(biāo)位置(光標(biāo)是一個(gè)imageView),并設(shè)置攝像頭的聚焦模式和曝光模式

設(shè)置光標(biāo)位置的方法

/* 設(shè)置光標(biāo)位置 */
- (void)setFocusPoint:(CGPoint)point {
    self.imageView.center = point;
    
    self.imageView.transform = CGAffineTransformMakeScale(1.5, 1.5);
    self.imageView.alpha = 1;
    
    [UIView animateWithDuration:1.0 animations:^{
        self.imageView.transform = CGAffineTransformIdentity;
    } completion:^(BOOL finished) {
        self.imageView.alpha = 0;
    }];
    
}

設(shè)置聚焦模式和曝光模式的方法

/* s設(shè)置聚焦和曝光模式 */
- (void)focusWithMode:(AVCaptureFocusMode)focusMode
         exposureMode:(AVCaptureExposureMode)exposeMode
              atPoint:(CGPoint)point
{
    //設(shè)置曝光模式和聚焦模式 先鎖住輸入設(shè)置
    [self changeDeviceProperty:^(AVCaptureDevice *device) {
        if ([device isFocusModeSupported:focusMode]) {
            [device setFocusMode:focusMode];
        }
        
        if ([device isExposureModeSupported:exposeMode]) {
            [device setExposureMode:exposeMode];
        }
        
        if ([device isFocusPointOfInterestSupported]) {
            [device setFocusPointOfInterest:point];
        }
        
        if ([device isExposurePointOfInterestSupported]) {
            [device setExposurePointOfInterest:point];
        }
        
    }];
}

拍照的方法

#pragma mark -拍照
- (IBAction)takePhoto:(id)sender {
    //1.根據(jù)數(shù)據(jù)輸出管理對(duì)象(輸出源)獲得鏈接
    AVCaptureConnection *connection = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
    //2.根據(jù)連接取得輸出數(shù)據(jù)
    [self.imageOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
        //獲取圖像數(shù)據(jù)
        NSData *imageData=[AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
        UIImage *image=[UIImage imageWithData:imageData];
        //存入相冊(cè)
        UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
    }];
}

切換攝像頭

切換攝像頭就是移除原有的輸入源,添加新的輸入源

#pragma mark -切換攝像頭
/* 切換攝像頭的過程就是將原有的輸入源移除 添加新的輸入源到會(huì)話中 */
- (IBAction)switchCamera:(id)sender {
    //1.獲取原來的輸入設(shè)備 根據(jù)數(shù)據(jù)輸入管理對(duì)象獲取
    AVCaptureDevice *oldCaptureDevice = [self.captureDeviceInput device];
    //2.移除輸入設(shè)備的通知
    [self removeNotificationFromCaptureDevice:oldCaptureDevice];
    
    //3.切換攝像頭的位置
    //3.1.獲取當(dāng)前的位置
    AVCaptureDevicePosition currentPosition = oldCaptureDevice.position;
    //3.2.獲取要切換的位置
    AVCaptureDevicePosition targetPosition = AVCaptureDevicePositionFront;
    if (currentPosition == AVCaptureDevicePositionFront || AVCaptureDevicePositionUnspecified) {
        targetPosition = AVCaptureDevicePositionBack;
    }
    
    //4.根據(jù)攝像頭的位置獲取當(dāng)前的輸入設(shè)備
    AVCaptureDevice *currentCaptureDevice = [self getCameraDeviceWithPosition:targetPosition];
    
    //5.添加對(duì)當(dāng)前輸入設(shè)備的通知
    [self addNotificationToCaptureDevice:currentCaptureDevice];
    
    //6.創(chuàng)建當(dāng)前設(shè)備的數(shù)據(jù)輸入管理對(duì)象
    AVCaptureDeviceInput *currentInput = [[AVCaptureDeviceInput alloc] initWithDevice:currentCaptureDevice error:nil];
    
    //7.添加新的數(shù)據(jù)管理對(duì)象到捕捉會(huì)話
    //7.1.開始設(shè)置
    [_session beginConfiguration];
    //7.2.移除原有的輸入源
    [_session removeInput:self.captureDeviceInput];
    
    //7.3.添加新的輸入源
    if ([_session canAddInput:currentInput]) {
        [_session addInput:currentInput];
        //.標(biāo)記當(dāng)前的輸入源
        self.captureDeviceInput = currentInput;
    }
    
    
    //7.4.提交設(shè)置
    [_session commitConfiguration];
}

根據(jù)攝像頭的位置(前置/后置)創(chuàng)建輸入設(shè)備

/* 根據(jù)攝像頭位置來獲取攝像頭 */
- (AVCaptureDevice *)getCameraDeviceWithPosition:(AVCaptureDevicePosition)position {
    NSArray *cameras = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for (AVCaptureDevice *device in cameras) {
        if (device.position == position) {
            return device;
        }
    }
    return nil;
}

需要說明的是在beginConfiguration方法需要和commitConfiguration方法配套使用,我們可以在這之間可以添加或刪除輸出,更改sessionPreset或配置單個(gè)AVCaptureInput或Output屬性

這里基本上就已經(jīng)實(shí)現(xiàn)了拍照功能,還有一些就是設(shè)置閃光燈的模式了
這里閃光模式一共有三種


typedef NS_ENUM(NSInteger, AVCaptureFlashMode) {
    AVCaptureFlashModeOff  = 0,
    AVCaptureFlashModeOn   = 1,
    AVCaptureFlashModeAuto = 2
} NS_AVAILABLE(10_7, 4_0) __TVOS_PROHIBITED;

設(shè)置閃光模式

#pragma mark - 設(shè)置閃光燈模式
- (void)setFlashMode:(AVCaptureFlashMode)mode {
    //先鎖住設(shè)備
    [self changeDeviceProperty:^(AVCaptureDevice *device) {
        if ([device isFlashModeSupported:mode]) {//如果支持該模式
            [device setFlashMode:mode];
        }
    }];
}

大致效果為

拍照.gif

錄制視頻

錄制視頻跟拍照大致差不多,比拍照要多一個(gè)麥克風(fēng)的數(shù)據(jù)輸入管理對(duì)象(麥克風(fēng)輸入源),拍照的話是創(chuàng)建AVCaptureStillImageOutput類型的輸出緣,錄制視頻的話是AVCaptureMovieFileOutput類型

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    //初始化捕捉會(huì)話
    _session = [[AVCaptureSession alloc] init];
    if ([_session canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
        [_session setSessionPreset:AVCaptureSessionPreset1280x720];
    }
    
    //獲得相機(jī)輸入設(shè)備
    AVCaptureDevice *cameraDevice = [self getCameraDeviceWithPosition:AVCaptureDevicePositionBack];
    if (cameraDevice == nil) {
        NSLog(@"獲取后置攝像頭失敗");
        return;
    }
    
    //根據(jù)相機(jī)輸入設(shè)備創(chuàng)建相機(jī)輸入源
    NSError *error = nil;
    _cameraDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:cameraDevice error:&error];
    if (error) {
        NSLog(@"%@", error.localizedDescription);
        return;
    }
    
    //獲得話筒輸入設(shè)備
    AVCaptureDevice *audioDevice = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio].firstObject;
    //創(chuàng)建話筒輸入源
    _audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil];
    
    //創(chuàng)建數(shù)據(jù)輸出管理對(duì)象
    _movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
    
    //添加輸入源
    if ([_session canAddInput:_cameraDeviceInput]) {
        [_session addInput:_cameraDeviceInput];
    }
    AVCaptureConnection *connection = [_movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
    if ([connection isVideoStabilizationSupported]) {
        
        connection.preferredVideoStabilizationMode=AVCaptureVideoStabilizationModeAuto;//通過將preferredVideoStabilizationMode屬性設(shè)置為AVCaptureVideoStabilizationModeOff以外的值,當(dāng)模式可用時(shí),流經(jīng)接收器的視頻會(huì)穩(wěn)定
    }
    
    if ([_session canAddInput:_audioDeviceInput]) {
        [_session addInput:_audioDeviceInput];
    }
    
    //添加輸出源
    if ([_session canAddOutput:_movieFileOutput]) {
        [_session addOutput:_movieFileOutput];
    }
    //創(chuàng)建預(yù)覽圖層
    _previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_session];
    _previewLayer.frame = self.view.bounds;
    _previewLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;//填充模式
    
    [self.view.layer insertSublayer:_previewLayer atIndex:0];
    
}


開始錄制視頻

- (IBAction)startRecording:(UIButton *)sender {
   
   if ([self.movieFileOutput isRecording]) {
       [self.movieFileOutput stopRecording];
       sender.selected = YES;
       return;
   }
   
   //獲得連接
   AVCaptureConnection *connection = [self.movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
   connection.videoOrientation = self.previewLayer.connection.videoOrientation;
   
   NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"myVideo.mp4"];
   NSURL *url = [NSURL fileURLWithPath:filePath];
   //開始錄制 并設(shè)置代理
   [self.movieFileOutput startRecordingToOutputFileURL:url recordingDelegate:self];
}

遵守AVCaptureFileOutputRecordingDelegate協(xié)議并實(shí)現(xiàn)代理方法

下面這個(gè)方法是必須實(shí)現(xiàn)的

#pragma mark - AVCaptureFileOutputRecordingDelegate
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
{
    NSLog(@"視頻錄制完成");
    //將視頻存入到相簿
    ALAssetsLibrary *assetsLibrary=[[ALAssetsLibrary alloc]init];
    [assetsLibrary writeVideoAtPathToSavedPhotosAlbum:outputFileURL completionBlock:^(NSURL *assetURL, NSError *error) {
        if (error) {
            NSLog(@"保存視頻到相簿過程中發(fā)生錯(cuò)誤,錯(cuò)誤信息:%@",error.localizedDescription);
        }
        
        NSLog(@"成功保存視頻到相簿.");
    }];
}

官方文檔是這么介紹該方法的

This method is called when the file output has finished writing all data to a file whose recording was stopped, either because startRecordingToOutputFileURL:recordingDelegate: or stopRecording were called, or because an error, described by the error parameter, occurred (if no error occurred, the error parameter will be nil). This method will always be called for each recording request, even if no data is successfully written to the file.

大致意思是

當(dāng)文件輸出已完成將所有數(shù)據(jù)寫入記錄已停止的文件時(shí),或者因?yàn)檎{(diào)用了startRecordingToOutputFileURL:recordingDelegate:或stopRecording,或者因?yàn)榘l(fā)生了由錯(cuò)誤參數(shù)描述的錯(cuò)誤(如果沒有發(fā)生錯(cuò)誤, 錯(cuò)誤參數(shù)將為nil)。 即使沒有數(shù)據(jù)成功寫入文件,也會(huì)為每個(gè)記錄請(qǐng)求調(diào)用此方法。

開始錄制時(shí)的代理方法

- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections
{
    NSLog(@"開始錄制視頻");
}

切換攝像頭的方法

- (IBAction)switchCamera:(id)sender {
    //1.獲得原來的輸入設(shè)備
    AVCaptureDevice *oldCaptureDevice = [self.cameraDeviceInput device];
    //2.移除原來輸入設(shè)備的通知
    [self removeNotificationFromDevice:oldCaptureDevice];
    //3.獲得現(xiàn)在的輸入設(shè)備
    //3.1.獲得原來的設(shè)備的位置
    AVCaptureDevicePosition oldPosition = oldCaptureDevice.position;
    //3.2.獲得現(xiàn)在的設(shè)備的位置
    AVCaptureDevicePosition currentPosition = AVCaptureDevicePositionFront;
    if (oldPosition == AVCaptureDevicePositionFront || oldPosition == AVCaptureDevicePositionUnspecified) {
        currentPosition = AVCaptureDevicePositionBack;
    }
    //3.3.根據(jù)位置創(chuàng)建當(dāng)前的輸入設(shè)備
    AVCaptureDevice *currnetCaptureDevice = [self getCameraDeviceWithPosition:currentPosition];
    //3.4.給當(dāng)前設(shè)備添加通知
    [self addNotificationToCaptureDevice:currnetCaptureDevice];
    
    //4.根據(jù)現(xiàn)在的輸入設(shè)備創(chuàng)建輸入源
    NSError *error = nil;
    AVCaptureDeviceInput *currentInput = [AVCaptureDeviceInput deviceInputWithDevice:currnetCaptureDevice error:&error];
    if (error) {
        NSLog(@"%@",error.localizedDescription);
        return;
    }
    
    //5.更換輸入源
    //5.1.開啟設(shè)置
    [_session beginConfiguration];
    //5.2.移除原來的輸入源
    [_session removeInput:self.cameraDeviceInput];
    //5.3.添加現(xiàn)在的輸入源
    if ([_session canAddInput:currentInput]) {
        [_session addInput:currentInput];
        self.cameraDeviceInput = currentInput;
    }
    //5.4.提交設(shè)置
    [_session commitConfiguration];
}

可以看出跟拍照的切換是一致的

大致效果

視頻.gif

還有一點(diǎn)需要注意的是因?yàn)檫@里調(diào)用了相機(jī)和話筒設(shè)備,所以需要在info.plist中添加相應(yīng)的字段

CCF99CA8-86F7-4721-A89C-9A3F7986CD74.png

代碼地址:點(diǎn)擊這里

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容