FilterShowcase是GPUImage中一個示例demo,對由攝像頭獲取的實時視頻進行處理加工。從這個示例中,結合AVFoundation先了解GPUImageVideoCamera
這個類。
GPUImageVideoCamera
GPUImageVideoCamera繼承自GPUImageOutput,遵循AVCaptureVideoDataOutputSampleBufferDelegate
和AVCaptureAudioDataOutputSampleBufferDelegate
兩個協議,采用攝像頭數據作為數據源,是數據響應鏈的源頭。
視頻捕捉核心類:AVCaptureSession
AVCaptureSession用于連接輸入和輸出的資源。一個捕捉會話相當于一個虛擬插線板,管理從物理設備得到的數據流,如攝像頭和麥克風,輸出到一個或多個目的地。可以動態配置輸入和輸出的線路,以此在會話進行中按需重新配置捕捉環境。session調用startRunning
開始數據流的流入流出,調用stopRunning
停止數據流流動。但不要在主線程調用startRunning
。
AVCaptureSessionPreset:session的屬性sessionPreset用來自定義一些設置,在session運行的時候動態配置也可以。
GPUImage中初始化
_captureSession = [[AVCaptureSession alloc] init];
[_captureSession beginConfiguration];
//一些配置
[_captureSession commitConfiguration];
輸入:AVCaptureDevice
AVCaptureDevice為攝像頭等物理設備定義了一個接口,并對這些硬件設備定義了大量控制方法,如對焦、曝光等。AVCaptureDevice定義了大量類方法用于訪問系統的捕捉設備,最常用的一個方法是defaultDeviceWithMediaType:
。但一個捕捉設備不能直接添加到AVCaptureSession中,可以將它封裝到一個AVCaptureDeviceInput對象中添加。
NSError *error
AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error]
這個方法需要一個有效的NSError指針,因為輸入中遇到的任何錯誤描述信息會在這里體現。
輸出:AVCaptureOutput
AVCaptureAudioDataOutput和AVCaptureVideoDataOutput可以直接訪問硬件捕捉到的數字樣本,他們繼承自抽象基類AVCaptureOutput。這兩個類可以提供強大的功能,如對音頻和視頻流進行實時處理。視頻的一個新圖像幀會被傳遞到AVCaptureVideoDataOutput,如果需要對視頻幀處理加工,需要設置AVCaptureVideoDataOutput的代理方法
- (void)setSampleBufferDelegate:(nullable id<AVCaptureVideoDataOutputSampleBufferDelegate>)sampleBufferDelegate
queue:(nullable dispatch_queue_t)sampleBufferCallbackQueue;
delegate會通過代理方法
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
獲得圖像幀。代理的函數會在sampleBufferCallbackQueue
中調用,并且必須是一個同步隊列,以保證視頻幀的順序是正確的——GPUImage創建了一個cameraProcessingQueue
。如果處理速度比采集速度慢,隊列會堵塞,等待處理的圖像會占住內存,默認setAlwaysDiscardsLateVideoFrames屬性為YES,這樣就會丟棄由于隊列阻塞而不斷新增來不及處理的新圖像,GPUImage把這一屬性改為NO。
dispatch_semaphore_t:GCD用來創建一個并發控制來同步任務和有限資源訪問控制的方法
GPUImage中的屬性frameRenderingSemaphore幀渲染信號量用于處理完一幀后接著處理下一幀。
GPUImageVideoCamera的初始化
GPUImageVideoCamera的初始化方法
- (id)initWithSessionPreset:(NSString *)sessionPreset
cameraPosition:(AVCaptureDevicePosition)cameraPosition;
- 創建了視頻處理隊列
cameraProcessingQueue
和音頻處理隊列audioProcessingQueue
- 創建了信號量
frameRenderingSemaphore
- 創建了核心類
AVCaptureSession
,添加了輸入videoInput
和輸出videoOutput
- 充血了
runSynchronouslyOnVideoProcessingQueue
,稍后在介紹GPUImageOutput時詳解。