采集數(shù)據(jù)需要使用AVFoundation下的相關(guān)API
AVFoundation在相關(guān)框架棧中的的位置:
為了捕捉視頻,我們需要這樣幾種類(與其它的子類)。
AVCaptureDevice 代表了輸入設(shè)備,例如攝像頭與麥克風(fēng)。
AVCaptureInput 代表了輸入數(shù)據(jù)源
AVCaptureOutput 代表了輸出數(shù)據(jù)源
AVCaptureSession 用于協(xié)調(diào)輸入與輸出之間的數(shù)據(jù)流
并且還有AVCaptureVideoPreviewLayer提供攝像頭的預(yù)覽功能
可以用這樣一幅圖來概述:
實際應(yīng)用AVFoundation來捕捉視頻流并不復(fù)雜琼了。
Talk is Cheap,Show me the Code.
我們用代碼簡單地描述用AVFoundation捕捉視頻的過程,其他捕捉音頻,靜態(tài)圖像的過程也是大同小異的另假。
1.創(chuàng)建AVCaputureSession崖叫。
作為協(xié)調(diào)輸入與輸出的中心,我們第一步需要創(chuàng)建一個Session
AVCaptureSession?*session?=?[[AVCaptureSession?alloc]?init];
2.創(chuàng)建AVCaptureDevice
創(chuàng)建一個AVCaptureDevice代表代表輸入設(shè)備齿尽。在這里我們制定設(shè)備用于攝像继榆。
此方法是獲得前攝像頭的
AVCaptureDevice?*videoDevice?=?[AVCaptureDevice?defaultDeviceWithMediaType:AVMediaTypeVideo];
想要同時獲得前后攝像頭可以使用下面方法
NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
AVCaptureDevice *frontCamera = [AVCaptureDeviceInput deviceInputWithDevice:videoDevices.firstObject error:nil];
AVCaptureDevice *backCamera =[AVCaptureDeviceInput deviceInputWithDevice:videoDevices.lastObject error:nil];
//初始化攝像頭
self.frontCamera = [AVCaptureDeviceInput deviceInputWithDevice:videoDevices.firstObject error:nil];
self.backCamera =[AVCaptureDeviceInput deviceInputWithDevice:videoDevices.lastObject error:nil];
初始化麥克風(fēng)
AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
3.創(chuàng)建AVCaptureDeviceInput,并添加到Session中
我們需要使用AVCaptureDeviceInput來讓設(shè)備添加到session中, AVCaptureDeviceInput負(fù)責(zé)管理設(shè)備端口栈虚。我們可以理解它為設(shè)備的抽象灌曙。一個設(shè)備可能可以同時提供視頻和音頻的捕捉。我們可以分別用AVCaptureDeviceInput來代表視頻輸入和音頻輸入节芥。
NSError?*error;
AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];
[session?addInput:input];
4.創(chuàng)建AVCaptureOutput
為了從session中取得數(shù)據(jù),我們需要創(chuàng)建一個AVCaptureOutput
AVCaptureVideoDataOutput *videoDataOutput = [[AVCaptureVideoDataOutput alloc]init];
[videoDataOutput setAlwaysDiscardsLateVideoFrames:YES];
//設(shè)置視頻輸出格式
[videoDataOutput setVideoSettings:@{
(__bridge NSString *)kCVPixelBufferPixelFormatTypeKey:@(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange)
}];
self.captureVideoDataOutput.alwaysDiscardsLateVideoFrames = YES;
這里的kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange是用于設(shè)置輸出的YUV,這里先簡單提一下在刺,稍后會有詳細(xì)的文章來介紹。
kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange ?//NV12
5.設(shè)置output delegate,將output添加至session,在代理方法中分析視頻流
為了分析視頻流,我們需要為output設(shè)置delegate,并且指定delegate方法在哪個線程被調(diào)用头镊。需要注意的是,線程必須是串行的,確保視頻幀按序到達蚣驼。
videoDataOutputQueue?=?dispatch_queue_create("VideoDataOutputQueue",?DISPATCH_QUEUE_SERIAL);
[videoDataOutput?setSampleBufferDelegate:self?queue:videoDataOutputQueue];
[session?addOutput:videoDataOutput];
我們可以在delegate方法中獲得視頻流及音頻流,并進行編碼相艇。
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection{
? ? ? ? ? ? ?if ([self.videoDataOutput isEqual:captureOutput]) {
? ? ? ? ? ? ? ? ? ?//判斷是視頻流
? ? ? ? ? ? ? }else if([self.audioDataOutput isEqual:captureOutput]){
? ? ? ? ? ? ? ? ?//判斷出是音頻流
? ? ? ? ? ? ? }
}
6.設(shè)置本機播放
AVCaptureVideoPreviewLayer *previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];
previewLayer.frame = preview.bounds;
[self.preview.layer addSublayer:self.previewLayer];
7.開始捕捉
[session?startRunning];
通過上面的簡單例子,我么可以看出使用AVFoundation來捕捉視頻流并不是十分復(fù)雜颖杏。重點是使用的過程需要了解配置的細(xì)節(jié),還有性能問題。