iOS 視頻采集

前言

AVFoundation框架是iOS中很重要的框架,所有與音視頻相關的軟硬件控制都在這個框架里。本文主要介紹iOS媒體捕捉和視頻采集。

媒體捕捉流程

媒體捕捉(網侵刪).png

簡單介紹

  • AVCaptureSession:媒體捕獲會話(包括音頻和視頻),負責把捕獲的音視頻數據輸出到輸出設備中,一個AVCaptureSession可以有多個輸入輸出。
    在視頻或音頻捕捉時,客戶端可以實例AVCaptureSession,添加適當的AVCaptureInputs、AVCaptureDeviceInput和輸出。
  • AVCaptureInput和AVCaptureDevice:設備輸入數據管理對象,可以根據AVCaptureDevice創建對應AVCaptureDeviceInput對象,該對象將會被添加到AVCaptureSession中管理。
  • AVCaptureOutput:設備輸出數據管理對象。
  • AVCaptureVideoPreviewLayer和AVSampleBufferDisplayLayer,相機拍攝預覽圖層,是CALayer的子類,前者創建需要AVCaptureSession對象,后者可以直接創建,添加CMSampleBufferRef進行展示。

相關代碼展示

- (void)configureCamera{
    /// 參數設置
    // 默認后置攝像頭
    AVCaptureDevicePosition position = AVCaptureDevicePositionBack;
    // 幀率
    int frameRate = 25;
    // 顯色方案
    OSType videoFormat = kCVPixelFormatType_32BGRA;
    // 分辨率高
    int resolutionHeight = 720;
    
    /// 創建AVCaptureSession對象
    AVCaptureSession *session = [[AVCaptureSession alloc] init];
    /// 設置分辨率
    session.sessionPreset = AVCaptureSessionPreset1280x720;
    /// 獲取攝像頭
    AVCaptureDevice *captureDevice;
    // 默認AVCaptureDevicePositionBack,后置攝像頭
    AVCaptureDeviceDiscoverySession *deviceDiscoverySession =  [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera] mediaType:AVMediaTypeVideo position:position];
    NSArray *devices = deviceDiscoverySession.devices;
    for (AVCaptureDevice *device in devices) {
        if (AVCaptureDevicePositionBack == device.position) {
            captureDevice = device;
        }else if (AVCaptureDevicePositionFront == device.position){
            captureDevice = device;
        }
    }
    /// 設置幀率和分辨率高度
    BOOL isSuccess = NO;
    for(AVCaptureDeviceFormat *vFormat in [captureDevice formats]) {
        CMFormatDescriptionRef description = vFormat.formatDescription;
        float maxRate = ((AVFrameRateRange*) [vFormat.videoSupportedFrameRateRanges objectAtIndex:0]).maxFrameRate;
        if (maxRate >= frameRate && CMFormatDescriptionGetMediaSubType(description) == videoFormat) {
            if ([captureDevice lockForConfiguration:NULL] == YES) {
                // 對比鏡頭支持的分辨率和當前設置的分辨率
                CMVideoDimensions dims = CMVideoFormatDescriptionGetDimensions(description);
                if (dims.height == resolutionHeight && dims.width == [self.class getResolutionWidthByHeight:resolutionHeight]) {
                    [session beginConfiguration];
                    if ([captureDevice lockForConfiguration:NULL]){
                        captureDevice.activeFormat = vFormat;
                        [captureDevice setActiveVideoMinFrameDuration:CMTimeMake(1, frameRate)];
                        [captureDevice setActiveVideoMaxFrameDuration:CMTimeMake(1, frameRate)];
                        [captureDevice unlockForConfiguration];
                    }
                    [session commitConfiguration];
                    isSuccess = YES;
                }
            }else {
                NSLog(@"%s: 失敗",__func__);
            }
        }
    }
    
    NSError *error;
    
    //添加輸入
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
    if (error != noErr) {
        NSLog(@"配置設備輸入失敗:%@",error.localizedDescription);
        return;
    }
    [session addInput:input];
    
    //添加輸出
    AVCaptureVideoDataOutput *videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
    if ([session canAddOutput:videoDataOutput]) {
        [session addOutput:videoDataOutput];
    }
    videoDataOutput.videoSettings = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:videoFormat]
                                                                forKey:(id)kCVPixelBufferPixelFormatTypeKey];
    //當此屬性的值為YES時,接收方將立即丟棄捕獲的幀,而處理現有幀的調度隊列在captureOutput:didOutputSampleBuffer:fromConnection: delegate方法中被阻塞。當此屬性的值為NO時,將允許委托在丟棄新幀之前有更多的時間處理舊幀,但應用程序的內存使用量可能會顯著增加。默認值為“YES”。(機翻)
    videoDataOutput.alwaysDiscardsLateVideoFrames = NO;
    
    //創建一個隊列接收數據
    dispatch_queue_t videoQueue = dispatch_queue_create("video_receive_queue", NULL);
    [videoDataOutput setSampleBufferDelegate:self queue:videoQueue];
    
    //創建接收對象
    AVCaptureVideoPreviewLayer *videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
    videoPreviewLayer.backgroundColor = [[UIColor blackColor] CGColor];
    CGRect frame = [videoPreviewLayer bounds];
    NSLog(@"previewViewLayer = %@",NSStringFromCGRect(frame));
    
    //設置尺寸和填充方式
    [videoPreviewLayer setFrame:[UIScreen mainScreen].bounds];
    [videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspect];
    
    if ([[videoPreviewLayer connection] isVideoOrientationSupported]) {
        [videoPreviewLayer.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
    }else{
        NSLog(@"不支持視頻定向");
    }
    
    //需要在哪個view上展示
    UIView *showView = [[UIView alloc] init];
    [showView.layer insertSublayer:videoPreviewLayer atIndex:0];
    
}
//采集視頻的回調,如果需要編碼H264/H265,在這里操作
- (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection{
    /*
    //另一種展示方式
    AVSampleBufferDisplayLayer *previewLayer = [AVSampleBufferDisplayLayer layer];
    previewLayer.videoGravity =  AVLayerVideoGravityResizeAspectFill;
    [previewLayer enqueueSampleBuffer:sampleBuffer];
    //需要在哪個view上展示
    UIView *showView = [[UIView alloc] init];
    [showView.layer insertSublayer:previewLayer atIndex:0];
     */
}
///需要考慮橫豎屏情況,這里暫未考慮
+ (int)getResolutionWidthByHeight:(int)height {
    switch (height) {
        case 2160:
            return 3840;
        case 1080:
            return 1920;
        case 720:
            return 1280;
        case 480:
            return 640;
        default:
            return -1;
    }
}

Tips:配置采集之前,記得申請攝像頭權限,如果沒有權限,需要自己做判斷,這里省略。
Demo地址整理后奉上。
有其他不明白的,可以留言,看到就會回復。
如果喜歡,請幫忙點贊。支持轉載,轉載請附原文鏈接。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 概述 音視頻采集包括兩部分:視頻采集音頻采集 在iOS開發中,是可以同步采集視頻&音頻的,使用方式也非常簡單 相關...
    CoreCoder閱讀 624評論 0 0
  • 前言 在直播和短視頻行業日益火熱的發展形勢下,音視頻開發(采集、編解碼、傳輸、播放、美顏)等技術也隨之成為開發者們...
    G_Jayson閱讀 1,351評論 1 1
  • 前言 在直播和短視頻行業日益火熱的發展形勢下,音視頻開發(采集、編解碼、傳輸、播放、美顏)等技術也隨之成為開發者們...
    iOS亮子閱讀 878評論 0 7
  • 概述 在直播應用中,視頻的采集一般都是用AVFoundation框架,因為利用它我們能定制采集視頻的參數;也能做切...
    iosmedia閱讀 5,830評論 0 3
  • 概述 音視頻采集是直播架構的第一環,是視頻的來源其實視頻的采集有多個應用場景:比如二維碼開發 音視頻采集包括兩部分...
    黃曉堅閱讀 552評論 1 0