1. 程式人生 > >iOS 音視訊採集 AVCaptureSession

iOS 音視訊採集 AVCaptureSession

在之前的文章中,對多媒體音視訊開發的經典流程做過一個簡單的介紹。在這篇文章中,將首先就音視訊從採集部分做一個例項的講解。首先以iOS平臺為例。

AVFoundation

Apple 官方給我們提供了一個很大的一個集合框架 AVFoundation。Apple的官方介紹原文如下

AVFoundation is one of several frameworks that you can use to play and create time-based audiovisual media. It provides an Objective-C interface you use to
work on a detailed level with time-based audiovisual data. For example, you can use it to examine, create, edit, or reencode media files. You can also get input streams from devices and manipulate video during realtime capture and playback.

AVFoundation是你可以用來播放和建立基於時間的多媒體視聽體驗的框架之一,它提供了Objective-C的介面來讓我們操作這些基於時間的視聽多媒體資料。比如,你可以用它來檢測,建立,編輯或者重新編碼媒體檔案。你也可以從裝置中獲取流,並且在媒體流的實時採集和播放的過程中對它進行操作。

AVFoundation

AVCaptureSession

我們在音視訊的採集技術選擇上我們可以首先考慮AVFoundation 提供的AVCaptureSeesion 及其涉及的一系列輸入輸出物件。

AVCaptureSession是iOS提供的一個管理和協調輸入裝置到輸出裝置之間資料流的物件。

AVCaptureSession

在這個期間我們除了會涉及到AVCaptureSession之外,我們還會涉及到例如AVCaptureDevice, AVCaptureInput, AVCaptureOutput,AVCaptureVideoPreviewLayer等一系列的類。
其中AVCpatureDevice抽象了具體的裝置,比如麥克風,攝像頭
AVCaptureInput 是一個抽象類,用於給Capture session中提供輸入資料的作用。它的子類AVCaptureDeviceInput就是 輸入資料是從AVCaptureDevice中獲得。
AVCaptureOutput 也是一個抽象類,用於從Capture session中獲取輸出資料。它的子類包括,AVCaptureAudioDataOutput 音訊資料輸出,AVCaptureVideoDataOutput 視訊資料輸出,AVCaptureMovieFileOutput 檔案輸出,AVCaptureStillImageOutput 影象照片輸出等等。
AVCaptureVideoPreviewLayer 是CALayer的子類,用於顯示採集到的視訊影象資料的。起預覽作用。

首先我們需要建立一個AVCaptureSession 的例項物件。

_captureSession = [[AVCaptureSession alloc]init];

然後我麼就可以開始建立輸入輸出裝置了並將他們新增到之前建立好的AVCaptureSession 中。

        //get an AVCaptureDevice instance , here we want camera
        NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
        for(AVCaptureDevice *device in devices){
            if(device.position == AVCaptureDevicePositionBack){
                _inputCamera = device;
            }
        }

        NSError *error = nil;
        //initialize an AVCaptureDeviceInput with camera (AVCaptureDevice)
        _videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:_inputCamera error:&error];
        if(error){
            NSLog(@"Camera error");
            return nil;
        }

        //add video input to AVCaptureSession
        if([self.captureSession canAddInput:_videoInput]){
            [self.captureSession addInput:_videoInput];
        }

        //initialize an AVCaptureVideoDataOuput instance
        _videoDataOutput = [[AVCaptureVideoDataOutput alloc]init];
        [self.videoDataOutput setAlwaysDiscardsLateVideoFrames:NO];
        [self.videoDataOutput setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange] forKey:(id)kCVPixelBufferPixelFormatTypeKey]];
        [self.videoDataOutput setSampleBufferDelegate:self queue:videoCaptureQueue];

        //add video data output to capture session
        if([self.captureSession canAddOutput:self.videoDataOutput]){
            [self.captureSession addOutput:self.videoDataOutput];
        }

        //setting orientaion
        AVCaptureConnection *connection = [self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo];
        connection.videoOrientation = AVCaptureVideoOrientationPortrait;
        if ([connection isVideoStabilizationSupported]) {
            connection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
        }
        connection.videoScaleAndCropFactor = connection.videoMaxScaleAndCropFactor;


        error = nil;
        //get an AVCaptureDevice for audio, here we want micphone
        _inputMicphone = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];

        //intialize the AVCaputreDeviceInput instance with micphone device
        _audioInput =[[AVCaptureDeviceInput alloc]initWithDevice:_inputMicphone error:&error];
        if(error){
            NSLog(@"micphone error");
        }

        //add audio device input to capture session
        if([self.captureSession canAddInput:_audioInput]){
            [self.captureSession addInput:_audioInput];
        }

        //initliaze an AVCaptureAudioDataOutput instance and set to capture session
        self.audioDataOutput = [[AVCaptureAudioDataOutput alloc] init];
        if([self.captureSession canAddOutput:self.audioDataOutput]){
            [self.captureSession addOutput:self.audioDataOutput];
        }

        [self.audioDataOutput setSampleBufferDelegate:self queue:audioCaptureQueue];

我們還需要告訴AVCaptureSession,我們希望採集什麼樣的質量等級的音視訊資料。在這裡我們不用一個個引數去設定。iOS給我們提供了很多可用的preset(預製值)。我們只需選擇符合我們要求的preset就可以了。

        if([_captureSession canSetSessionPreset:AVCaptureSessionPreset640x480]){
            [_captureSession setSessionPreset:AVCaptureSessionPreset640x480];
            _capturePresent = AVCaptureSessionPreset640x480;
        }

最後如果我們想開始音視訊採集的話,就直接給AVCaptureSession發 startRunning 訊息

-(void)start{
    [self.captureSession startRunning];
}

具體程式碼在Github: MultiMedia 的AVCaptureSessionTry