1. 程式人生 > >AVFoundation Programming Guide 之 Media Capture

AVFoundation Programming Guide 之 Media Capture

AVFoundation框架可以用來自定義相機,看了別人的程式碼,有很多的不明白,看了文件,就大致翻譯下吧,怕以後忘記!

Media Capture

從相機or麥克風獲取資訊,至少需要以下幾個類:

1.一個 AVCaptureDevice 的例項,來代表輸入的裝置,例如:相機or麥克風

2.一個 AVCaptureInput 具體子類的例項,來配置輸入裝置的埠。

3.一個 AVCaptureOutput 具體子類的例項,來管理到movie 檔案or靜態圖片的輸出。

4.一個 AVCaptureSession 的例項,來協調從輸入到輸出的資料流。

為了向用戶展示相機正在錄取的圖形影象,可能會用到AVCaptureVideoPreviewLayer(CALayer的子類)

通過一個單獨的session,可以來配置多個輸入輸出,如下展示:


然而,對於某些操作,還有考慮輸入裝置的各種埠是怎樣表示的 和 這些埠是怎樣連線到輸出的。

在capture session中,capture input 和 capture output 之間的聯絡,是用 AVCaptureConnection 物件表示的。Capture inputs(AVCaptureInput的例項)擁有一個或者多個輸入埠(AVCaptureInputPort的例項)。Capture outputs(AVCaptureOutput的例項)能接收一個或多個來源的資料(例如,AVCaptureMovieFileOutput 物件既能接收視訊也能接收音訊)。

當把一個input 或者 一個output 加入到一個session中時,session就在所有相符的 inputs 埠 和 output之間,建立連線。


可以是用capture connection 來建立或者取消 一個input or output 的資料流。

注意:在iOS裝置中,Media capture 不支援同時捕捉前置攝像頭和後置攝像頭。

使用Capture Session 來協調資料流

AVCaptureSession 是用來管理資料流的中心協調物件。使用此物件的例項來協調AV inputs 到 outputs的輸出。把你想要的capture裝置和輸出加入到session中,用 startRunning 來開始資料流,用 stopRunning 來停止資料流。

AVCaptureSession *session = [[AVCaptureSession alloc] init];
// Add inputs and outputs.
[session startRunning];

配置Session

你可以使用session的preset來指定影象的質量和解析度。preset是一個常量,指定可能配置中某一個,在某些情況下,特定於裝置的實際配置:


如果你想設定媒體的frame size,你應該檢查它是否支援此種設定,如下:

if ([session canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
    session.sessionPreset = AVCaptureSessionPreset1280x720;
}
else {
    // Handle the failure.
}

如果你需要更精確的調整session引數 or 在session執行時做出調整,那麼你就需要在 beginConfiguration 和 commitConfiguration 方法之間來調整。beginConfiguration 和 commitConfiguration方法確保裝置作為一個群體變化, 減少可見性或不一致的狀態。在呼叫 beginConfiguration 之後,你可以增加 or 移除 outputs,改變 sessionPreset 屬性的值 ,或者配置個人capture輸入或輸出屬性。只有在你呼叫了commitConfiguration方法後,這些改變才真正的起作用:
[session beginConfiguration];
// Remove an existing capture device.
// Add a new capture device.
// Reset the preset.
[session commitConfiguration];

監視Capture Session的狀態

Capture Session 開始或者停止,或者中斷,capture session會發送通知。如果一個執行時錯誤發生,你將會收到AVCaptureSessionRuntimeErrorNotification 的通知。你可以通過查詢session的running 屬性來判斷它是否在執行,通過 interrupted 屬性來判斷是否被中斷。此外,running 和 interrupted 屬性都是符號KVO的,並且通知都是在主執行緒中傳送的。

AVCaptureDevice 代表Input裝置

AVCaptureDevice 抽象表示一個可以提供input 資料(例如視訊和音訊)給AVCaptureSession物件的物理capture裝置。例如,兩個視訊:一個前置攝像頭,一個後置攝像頭,一個音訊:麥克風。

可以使用 AVCaptureDevice 的類方法 devices 和 devicesWithMediaType: 來找出當前可以使用的 capture裝置。可使用的裝置也可能會改變,你應該註冊來接收 AVCaptureDeviceWasConnectedNotification 和 AVCaptureDeviceWasDisconnectedNotification 的通知。

裝置的特性

使用hasMediaType: 來測試裝置是否提供了特定的媒體型別,使用supportsAVCaptureSessionPreset: 來測試裝置是否支援給定的capture session的預設值。為了給使用者提供資訊,你可以得到capture 裝置的位置(前面or後面),以及它們的名稱。這在你提供一個capture列表給使用者選擇的時候,可能會有用。

下圖顯示了前置(AVCaptureDevicePositionFront)和後置(AVCaptureDevicePositionBack)攝像頭的位置。


下面的程式碼示例,遍歷所有可用的裝置,輸出它們的名字,對於視訊裝置還輸出它們的位置:

NSArray *devices = [AVCaptureDevice devices];
 
for (AVCaptureDevice *device in devices) {
 
    NSLog(@"Device name: %@", [device localizedName]);
 
    if ([device hasMediaType:AVMediaTypeVideo]) {
 
        if ([device position] == AVCaptureDevicePositionBack) {
            NSLog(@"Device position : back");
        }
        else {
            NSLog(@"Device position : front");
        }
    }
}

另外,你還可以得到裝置的 model ID 和 unique ID。

Capture裝置設定

不同的裝置有不同的功能,例如,有些支援不同的 focus or flash 模式......

下面的程式碼片段,展示了怎樣去發現一個視訊輸入裝置有手電筒模式,並且支援給定的capture session 預設值:

NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
NSMutableArray *torchDevices = [[NSMutableArray alloc] init];
 
for (AVCaptureDevice *device in devices) {
    [if ([device hasTorch] &&
         [device supportsAVCaptureSessionPreset:AVCaptureSessionPreset640x480]) {
        [torchDevices addObject:device];
    }
}

使用Capture Inputs 加入Capture Device 到Session

為了把一個capture裝置加入到capture session中,可以使用 AVCaptureDeviceInput 的一個例項(抽象類AVCaptureInput的具體類)。capture input 裝置管理裝置的埠:

NSError *error;
AVCaptureDeviceInput *input =
        [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (!input) {
    // Handle the error appropriately.
}

使用addInput: 把inputs 加入到session中。如果合適,你可以使用 canAddInput: 檢查是否相容現有的session。
AVCaptureSession *captureSession = <#Get a capture session#>;
AVCaptureDeviceInput *captureDeviceInput = <#Get a capture device input#>;
if ([captureSession canAddInput:captureDeviceInput]) {
    [captureSession addInput:captureDeviceInput];
}
else {
    // Handle the failure.
}
一個AVCaptureInput 提供一個或者多個流媒體資料。例如,input裝置既能提供音訊資料也能提供視訊資料。input提供的每一個媒體流用AVCaptureInputPort 物件表示。一個capture session使用AVCaptureConnection物件來決定一系列AVCaptureInputPort 和 當個AVCaptureOutput 之間的對映。

使用Capture Outputs 從 Session 處得到Output

要想從capture session處獲得output,需新增一個或多個outputs。output是AVCaptureOutput具體子類。如下:

  • AVCaptureMovieFileOutput to output to a movie file
  • AVCaptureVideoDataOutput
  • AVCaptureAudioDataOutput
  • AVCaptureStillImageOutput

用addOutput:方法把output加入到capture session中,使用canAddOutput:方法來檢查capture output是否與存在的session相容。可以在session正在執行的時候,來增加或者移除outputs:

AVCaptureSession *captureSession = <#Get a capture session#>;
AVCaptureMovieFileOutput *movieOutput = <#Create and configure a movie output#>;
if ([captureSession canAddOutput:movieOutput]) {
    [captureSession addOutput:movieOutput];
}
else {
    // Handle the failure.
}