通過《AVFoundation》這篇文章,我們對AV Foundation框架有了一些初步瞭解,下面我們就在此基礎上一步步的看一下這個框架的基本使用吧。
使用AV Foundation的時機
- 跨平臺的媒體資料處理
- 對效能要求較高,並需要與高層的Media Player、Assets Library或底層的Core Media、Core Audio互動時,以OC的方式實現而非C Api。
AV Foundation是蘋果OS X和iOS系統中用於處理基於時間的媒體資料的高階Objective-C的高階框架,是針對64位系統裝置設計的,可以發揮64位的所有優勢;充分利用了多核的優勢並大量使用了Block&GCD機制將複雜的計算過程放在了後臺執行緒執行,會自動提供硬體的加速要求,確保在大部分的應用上高速執行。AV Foundation的設計也充分考慮了電量效率來滿足如Iphone和Ipad的諸類的移動裝置對電量的要求。
程式碼示例
AVSpeechSynthesizer類可以使我們方便的在cocoa新增文字語音的功能
1 2 3 |
AVSpeechSynthesizer *synthesizer = [[AVSpeechSynthesizer alloc] init];//合成器 AVSpeechUtterance *utterpace = [[AVSpeechUtterance alloc] initWithString:@"711"];// 說話方式 [synthesizer speakUtterance:utterpace];// 按照方式說話 |
執行便可聽到語音。
其實,就是這麼簡單。
AV Foundation捕捉視訊的類與子類
媒體捕捉不支援模擬器,也不能同時使用iOS裝置上的前置攝像頭和後置攝像頭進行捕捉。
- AVCaptureDevice 代表了輸入裝置,例如攝像頭與麥克風。
- AVCaptureInput 代表了輸入資料來源
- AVCaptureOutput 代表了輸出資料來源
- AVCaptureSession 用於協調輸入與輸出之間的資料流
- AVCaptureConnection 是一個連線,這個連線是inputPort和output之間或者是影象當前預覽層和當前會話之間的。
- AVCaptureVideoPreviewLayer 提供攝像頭的預覽功能,照片以及視訊的顯示就是通過把這個物件新增到UIView 的layer上的。
不能直接建立AVCaptureDevice的例項,只能通過該類的 devices、defaultDeviceWithMediaType:(NSString )mediaType、devicesWithMediaType:(NSString )mediaType方法 來獲取對應的輸入裝置陣列,接下來即 可獲取前置攝像頭、後置攝像頭或麥克風,程式就可設定該物件的對焦模式、閃光燈模式、曝光補償、白平衡 等各種拍照相關屬性。在配置攝像頭的相關屬性之前,必須先呼叫lockForConfiguration:方法執行鎖定,配置完成後呼叫unlockForConfiguration方法解鎖。
AVCaptureInput根據AVCaptureDevice建立對應的AVCaptureDeviceInput物件,從AVCaptureDevice裝置獲取資料,該物件將會被新增到AVCaptureSession中管理。它配置抽象硬體裝置的ports。AVCaptureScreenInput 可以從螢幕獲取資料(用於錄製螢幕動作),會被新增給AVCaptureSeesion管理。
AVCaptureOutput輸出的可以是圖片(AVCaptureStillImageOutput)或者視訊(AVCaptureMovieFileOutput)。AVCaptureAudioDataOutput、AVCaptureAudioPreviewOutput、AVCaptureFileOutput 、AVCaptureStillImageOutput、AVCaptureVideoDataOutput它們都是AVCaptureOutput的子類,用於接收各種資料。該物件也會被新增給AVCaptureSession管理,其中AVCaptureFileOutput依然代表輸出到檔案的輸出端。AVCaptureAudioFileOutput、AVCaptureMovieFileOutput 分別代表輸出到音訊檔案、電影檔案的輸出端。
對於一個AVCaptureSession, 可以配置多個inputs和outputs。每個session稱之為一個會話,也就是在應用執行過程中如果你需要改變會話的一些配置(例如:切換攝像頭),此時需要先開啟配置,配置完成之後再提交配置。有些情況下, 會涉及到如何表示一個inputs的多個埠(ports), 以及這些ports如何連線到outputs的問題。AVCaptureSession中使用 AVCaptureConnection 表示inputs和outputs之間的連線,一個Inputs包含一個或多個input ports( AVCaptureInputPort ), Outputs可以從一個或多個來源接收資料,比如 AVCaptureMovieFileOutput 可以同時接收視訊和音訊資料。在AVCaptureSession中新增一個input或output時,AVCaptureSession會為所有可匹配的inputs和outputs之前生成connections( AVCaptureConnection )。可以使用一個connection來開啟或關閉一個input或output資料流,也可以使用connection監控一個audio頻道的位元速率平均值和峰值。它有startRunning和stopRunning兩種方法來開啟會話和結束會話。
可以使用AVCaptureSession的 sessionPreset 屬性指定圖片質量和解析度:
- AVCaptureSessionPresetHigh: 高解析度, 最終效果根據裝置不同有所差異
- AVCaptureSessionPresetMedium: 中等解析度, 適合Wi-Fi分享. 最終效果根據裝置不同有所差異
- AVCaptureSessionPresetLow: 低解析度, 適合3G分享, 最終效果根據裝置不同有所差異
- AVCaptureSessionPreset640x480: 640×480, VGA
- AVCaptureSessionPreset1280x720: 1280×720, 720p HD
- AVCaptureSessionPresetPhoto: 全屏照片, 不能用來作為輸出視訊
閒話少說,上程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
#import "ViewController.h" #import @interface ViewController () @property (nonatomic, strong) UIImageView *cameraImageView; @property (nonatomic, strong) AVCaptureStillImageOutput *stillImageOutput; @property (nonatomic, strong) AVCaptureSession *session; @end @implementation ViewController - (UIImageView *)cameraImageView{ if (!_cameraImageView) { _cameraImageView = [[UIImageView alloc] initWithFrame:CGRectMake(50, 230, 200, 200)]; } return _cameraImageView; } - (void)viewDidLoad { [super viewDidLoad]; // 採集按鈕 UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)]; btn.backgroundColor = [UIColor grayColor]; [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside]; // 拍照 UIButton *btn1 = [[UIButton alloc] initWithFrame:CGRectMake(220, 100, 100, 100)]; btn1.backgroundColor = [UIColor blackColor]; [btn1 addTarget:self action:@selector(btnClick1:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:btn]; [self.view addSubview:btn1]; [self.view addSubview:self.cameraImageView]; } // 按鈕點選事件 - (void)btnClick:(id)sender{ [self openCamera:AVCaptureDevicePositionBack]; } // 拍照 - (void)btnClick1:(id)sender{ AVCaptureConnection *connection = [self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo]; [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) { NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer]; UIImage *image = [UIImage imageWithData:imageData]; self.cameraImageView.image = image; [self.session stopRunning]; }]; } // 採集 - (void)openCamera:(AVCaptureDevicePosition)cameraPostion{ BOOL hasCamera = [[AVCaptureDevice devices] count] >0; if (hasCamera) { _session = [[AVCaptureSession alloc] init]; _session.sessionPreset = AVCaptureSessionPresetPhoto; AVCaptureDevice *device = [self getCamera:cameraPostion]; NSError *error = nil; AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error]; [_session addInput:input]; _stillImageOutput = [[AVCaptureStillImageOutput alloc] init]; _stillImageOutput.outputSettings = @{AVVideoCodecKey:AVVideoCodecJPEG}; [_session addOutput:_stillImageOutput]; AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_session]; [captureVideoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill]; [captureVideoPreviewLayer setFrame:self.cameraImageView.bounds]; [self.cameraImageView.layer addSublayer:captureVideoPreviewLayer]; [_session startRunning]; } } // 獲取device - (AVCaptureDevice *)getCamera:(AVCaptureDevicePosition)cameraPostion{ NSArray *cameras = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; for (AVCaptureDevice *device in cameras) { if (device.position == cameraPostion) { return device; } } return [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; } |
利用AVFoundation拍照的步驟如下:
1)建立AVCaptureSession物件
2)使用AVCaptureDevice的靜態方法獲得需要使用的裝置。拍照和錄影需要使用攝像頭,錄音就需要使用麥克風裝置。
3)利用輸入裝置AVCaptureDevice初始化AVCaptureDeviceInput物件。
4)初始化輸出裝置管理物件,如果要拍照就初始化AVCaptureStillImageOutput物件;如果拍攝視訊就初始化AVCaptureMovieFileOutput物件。
5)將資料輸入物件AVCaptureDeviceInput和資料輸出物件AVCaptureOutput新增到AVCaptureSession中去。
6)建立視訊預覽圖層AVCaptureVideoPreviewLayer並指定媒體會話,新增圖層到顯示器中,呼叫AVCaptureSession中的stratRunning方法開始捕獲影象。
7)將捕獲的音視訊檔案輸出到指定檔案。
如此,一個拍照的功能就簡單實現了。下一篇我們將實現一些更復雜的邏輯。