AVFoundation
一.靜態圖像及視頻的采集
為了管理一個設備,如相機或者麥克風.你可以弄一些對象來描繪輸入設備
和輸出設備
.同時用一個AVCaptureSession的實例
來協調二者之間的數據流傳遞.你至少需要如下實例:
- AVCaptureDevice的實例
- 用來表示輸入設備.如相機或者麥克風
- AVCaptureInput具體子類的實例
- 用來配置輸入設備的端口
- AVCaptureOutput具體子類的實例
- 用來管理是輸出成一個視頻文件還是靜態圖片
- AVCaptureSession的實例
- 協調輸入設備和輸出設備之間數據流的傳遞
為了向用戶展示一個相機正在錄制什么,你可以使用AVCaptureVideoPreviewLayer
的實例.(它是CALayer
的子類),你可以配置多個輸入和輸出,由一個單例會話來協調.(如下圖1所示)
AVCaptureConnection
:在一個capture session
中,一個輸入采集
及輸出捕捉
之間的連接由 AVCaptureConnection對象來管理.
一個采集輸入(AVCaptureInput的實例)有一個或多個輸入端口(AVCaptureInputPort的實例).
一個輸出捕捉(AVCaptureOutput)可以接受一個或多個數據源的數據(如AVCaptureMovieFileOutput對象可以接收視頻和音頻數據)
當你將輸入和輸出添加到一個會話的時候,這個會話會把所有兼容的捕獲輸入端口和輸出捕捉之間形成連接.二者之間的連接用AVCaptureConnection
對象來表示.如圖2
你可以使用一個捕獲連接來啟用或禁用來自給定的輸入或者輸出的數據流.你也可以使用這個連接來監視音頻信道的平均峰值功率電平.
Note : 媒體捕獲不支持在 iOS 設備上同時捕捉正面和背面的攝像頭.
二.使用捕捉會話(Capture Session)來協調數據流
AVCaptureSession
對象是一個中央協調的對象,你可以用它來管理數據流的采集.你可以用一個實例來協調從AV輸入設備到輸出設備之間的數據流.您添加你想要的采集設備和輸出設備到會話.然后通過發送startRunning
消息來啟動數據流
,發送stopRunning
消息來停止數據流
.
AVCaptureSession *session = [[AVCaptureSession alloc] init];
// Add inputs and outputs.
[session startRunning];
配置會話
你可以在會話中使用一個預設
的配置參數來指定想要的圖像質量和分辨率
.預設
的是一個常數.它在許多可能的配置中標識了一個.在某些特定情況下.實際的配置是設備特定的.
配置信息:
在我們想要設置一個視頻的配置信息時,我們最好再設置之前對他做一層判斷.如
if ([session canSetSessionPreset:AVCaptureSessionPreset1280*720]) {
session.sessionPreset = AVCaptureSessionPreset1280*720;
} else {
// Handle the failure.
}
如果想要調整配置參數.那么就在[session beginConfiguration]
和[session commitConfiguration]
方法之間來調整.
[session beginConfiguration];
// Remove an existing capture device.
// Add a new capture device.
// Reset the preset.
[session commitConfiguration];
監視會話捕捉狀態
捕捉會話會發布通知,你可以觀察到通知.如當它開始或停止運行,或當它被中斷時,如果發生運行時錯誤,你可以通過注冊接受到一個AVCaptureSessionRuntimeErrorNotification
這樣的通知.你還可以詢問會話的運行屬性,來查明它是否正在運行.以及它中斷的屬性是否中斷.此外,running
和interrupted
遵從KVO並且發布通知在主線程.
三.一個 AVCaptureDevice對象代表一個輸入設備
一個AVCaptureDevice
對象抽象出一個物理捕獲設備到AVCaptureSession
對象.這個物理捕獲設備提供輸入數據(如音頻或者視頻).如.兩個視頻的輸入設備.一個是前置攝像頭.一個是后置攝像頭和一個音頻輸入的麥克風.
下面的代碼示例遍歷所有可用設備並打印出他們的名字.視頻設備.及位置
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");
}
}
}
此外,你還可以找到該設備的模型ID和唯一標識
設備捕獲設置
不同的設備,功能不同,如有些可能支持不同焦點或閃光模式,有的就可能集中在一個焦點上.
下面代碼演示了如何找到具有手電筒模式的視頻輸入設備,並支持給定的捕獲會話 預置.
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
NSMutableArray *torchDevices = [[NSMutableArray alloc] init];
for(AVCaptureDevice *device in devices) {
[if ([device hasTorch] && [device supportsAVCaptureSessionPreset:AVCaptureSessionPreset640*480]) {
[torchDevices addObject:device];
}]
}
對焦模式(3種)
1.AVCaptureFocusModeLocked
- 焦點固定
- 使用場景 : 當你想讓用戶組成一個場景,然后鎖定焦點
2.AVCaptureFocusModeAutoFocus
- 僅僅掃描聚焦然后恢復到鎖定焦點
- 使用場景 : 你想選擇一個特定的項目,然后聚焦,並且把焦點放在這個項目上,雖然這個項目不在場景的正中
3.AVCaptureFocusModeContinuousAutoFocus
- 相機持續自動聚焦模式
你可以使用adjustingFocus
這個屬性來確定設備是否是目前的焦點.當設備啟動和停止聚焦時,可以使用KVO來觀察屬性的變化.
如果更改焦點模式的設置.則可以將他們返回到默認配置:
if([currentDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {
CGPoint autofocusPoint = CGPointMake(0.5f,0.5f);
[currentDevice setFocusPointOfInterest:autofocusPoint];
[currentDevice setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
}
曝光模式(2種)
1.AVCaptureExposureModeContinuousAutoExposure
- 該設備根據需要自動調整曝光水平
2.AVCaptureExposureModeLocked
- 曝光水平固定在當前水平
你使用isExposureModeSupported:
方法確定設備是否支持給定的曝光模式,然后用exposureMode
這個屬性來設置曝光模式
同樣也可以使用KVO來觀察設備當啟動及停止更改其曝光設置時的改變狀態.
如果更改了曝光設置,則可以將它們返回到默認的配置:
if([currentDevice isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]){
CGPoint exposurePoint = CGPointMake(0.5f,0.5f);
[currentDevice setExposurePointOfInterest:exposurePoint];
[currentDevice setExposureMode:AVCaptureExposureModeContinuousAutoExposure];
}
閃光模式(3種)
1.AVCaptureFlashModeOff
- 永久關閉閃光模式
2.AVCaptureFlashModeOn
- 永久打開閃光模式
3.AVCaptureFlashModeAuto
- 閃光是否開啟取決於環境的光條件
你可以使用hasFlash
來確定該設備是否有閃光.如果這個方法返回 YES,那么使用isFlashModeSupported:
方法.傳遞所需的模式來確定這個設備是否支持給定的閃光模式.然后用flashMode
屬性來設置模式.
手電筒模式(3種)
在手電筒模式下,閃光燈是在一種低功耗照亮視頻捕獲情況下連續開啟的.
1.AVCaptureTorchModeOff
- 永久關閉手電筒
2.AVCaptureTorchModeOn
- 永久打開手電筒
3.AVCaptureTorchModeAuto
- 如果需要,自動打開和關閉
你使用hasTorch
來確定設備是否有閃光燈.你用isTorchModeSupported:
這個方法來確定設備是否支持給定的閃光模式,然后使用torchMode
屬性來設置這個模式.
視頻穩定
電影視頻穩定可用於連接的視頻操作,這取決於特定的設備硬件. 即便如此,也不是支持所有的源格式和視頻分辨率
啟用電影視頻穩定也可能引入額外的延遲到視頻捕獲管道.我們可以使用videoStabilizationEnabled
這個屬性來檢測何時使用視頻穩定
. 如果相機支持,enablesVideoStabilizationWhenAvailable
屬性允許應用程序自動使用視頻穩定
,所以,由於上面的限制,在默認的情況下,自動穩定被禁用.
白平衡(2種)
1.AVCaptureWhiteBalanceModeLocked
- 固定模式.
2.AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance
- 相機根據需要不斷調整白平衡
你可以用isWhiteBalanceModeSupported:
方法來確定設備是否支持白平衡模式.然后用whiteBalanceMode
屬性來設置模式
同樣的也可以使用KVO觀察屬性的改變
設置定位裝置
在一個AVCaptureConnection
上面你可以設置一個你想要的AVCaptureOutput
輸出的需求方向,是哪一個(AVCaptureMoviewFileOutput, AVCaptureStillImageOutput, AVCaptureVideoDataOutput)用來連接(connection)
AVCaptureConnection *captureConnection = <#A capture connection#>;
if ([captureConnection isVideoOrientationSupported])
{
AVCaptureVideoOrientation orientation = AVCaptureVideoOrientationLandscapeLeft;
[captureConnection setVideoOrientation:orientation];
}
配置設備
為了在一個設備上設置他的采集屬性,你必須首先用lockForConfiguration:
來獲得設備鎖.這樣就避免了可能與其他應用程序中設置不兼容的更改.
下面的代碼片段說明如何通過先確定模式是否被支持,然后嘗試鎖定設備重新配置來改變設備上的焦點模式。只有當獲得鎖時,焦點模式才會被改變,並且該鎖隨后被釋放.
if ([device isFocusModeSupported:AVCaptureFocusModeLocked]) {
NSError *error = nil;
if ([device lockForConfiguration:&error]) {
device.focusMode = AVCaptureFocusModeLocked;
[device unlockForConfiguration];
}
else {
// Respond to the failure as appropriate
切換裝置
有時,您可能希望允許用戶在輸入設備之間切換,例如,從使用前向后置攝像頭切換。為了避免停頓或卡頓,你可以配置會話在運行,但是你應該使用beginconfiguration
和commitconfiguration
支架配置變化
AVCaptureSession *session = <#A capture session#>;
[session beginConfiguration];
[session removeInput:frontFacingCameraDeviceInput];
[session addInput:backFacingCameraDeviceInput];
[session commitConfiguration];
當外面的commitconfiguration
被調用時,所有的改變都是一起做的。這確保了平穩過渡
四.使用 Capture Inputs 將一個捕捉設備添加到會話中
添加一個捕獲設備來捕捉一個會話.你可以使用AVCaptureDeviceInput
實例(AVCaptureInput類的具體的子類).這個捕獲設備輸入管理設備的端口
NSError *error;
AVCaptureDeviceInput *input =
[AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (!input) {
// Handle the error appropriately.
}
你可以使用addInput:
來將一個輸入添加到一個會話中.如果合適的話,你可以使用canAddInput:
來檢查輸入捕捉與現有會話中的使用是否兼容.
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
可以聲明一個或多個流媒體數據.比如,輸入設備可以同時提供音頻和視頻數據.每個流媒體的輸入提供了一個AVCaptureInputPort
表示.捕捉會話會使用AVCaptureConnection
對象來定義一個映射在一組AVCaptureInputPort
對象和一個AVCaptureOutput
對象之間.
五.使用 Capture Outputs 從一個會話中獲取輸出
要從捕獲會話中獲取輸出.請添加一個或多個輸出.輸出是AVCaptureOutput
的一個具體實例.
1.AVCaptureMovieFileOutput
- 輸出一個視頻文件
2.AVCaptureVideoDataOutput
- 如果想要從被捕獲的視頻中處理它的幀.可以用這個.比如可以創建自定義的視圖層
3.AVCaptureAudioDataOutput
- 如果想處理正在捕獲的音頻數據,可以使用這個
4.AVCaptureStillImageOutput
- 如果想要捕捉伴隨元數據的靜止圖像
你使用addOutput:
方法來把輸出添加到捕獲會話上.你可以通過canAddOutput:
這個方法來檢查一個捕獲輸出與現有的會話是否兼容.當會話運行時,你可以根據需要添加和刪除輸出.
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.
}
保存到電影文件
你可以通過AVCaptureMovieFileOutput
來保存電影數據到一個文件.(AVCaptureMovieFileOutput是AVCaptureFileOutput的一個具體的子類,它定義了大量的基本行為),你可以噢誒之電影文件輸出的各個方面,如錄制的最大時間,或它最大文件的大小.如果給定的磁盤空間不足,你也可以禁止錄音
AVCaptureMovieFileOutput *aMovieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
CMTime maxDuration = <#Create a CMTime to represent the maximum duration#>;
aMovieFileOutput.maxRecordedDuration = maxDuration;
aMovieFileOutput.minFreeDiskSpaceLimit = <#An appropriate minimum given the quality of the movie format and the duration#>
分辨率
和輸出比特率
取決於捕捉會話的sessionpreset
.視頻編碼通常都是H264
.音頻編碼通常都是AAC
.實際值要因設備而異.
開始錄制
你可以使用startRecordingToOutputFileURL:recordingDelegate:
開始錄制一個 QuickTime 電影
.你需要提供URL及delegate.這個URL不能表示現有文件.因為電影文件輸出不能覆蓋現有的資源,.你還要必須具有寫入指定位置的權限.代理必須要遵守AVCaptureFileOutputRecordingDelegate
協議.而且必須實現協議中的captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:
方法
AVCaptureMovieFileOutput *aMovieFileOutput = <#Get a movie file output#>;
NSURL *fileURL = <#A file URL that identifies the output location#>;
[aMovieFileOutput startRecordingToOutputFileURL:fileURL recordingDelegate:<#The delegate#>];
實現這個方法的時候,代理可以將生成的電影寫入到相冊中,他還應該檢查可能發生的任何錯誤.
確保文件被成功寫入
為了確定文件是否保存成功,在captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:
這個方法里你不僅僅應該檢查可能發生的錯誤,還要檢查AVErrorRecordingSuccessfullyFinishedKey
在這個錯誤信息中的用戶信息字典
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput
didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
fromConnections:(NSArray *)connections
error:(NSError *)error {
BOOL recordedSuccessfully = YES;
if ([error code] != noErr) {
// A problem occurred: Find out if the recording was successful.
id value = [[error userInfo] objectForKey:AVErrorRecordingSuccessfullyFinishedKey];
if (value) {
recordedSuccessfully = [value boolValue];
}
}
// Continue as appropriate...
你應該通過AVErrorRecordingSuccessfullyFinishedKey
這個key檢查用戶信息在錯誤信息中,因為該文件可能已成功保存,即使你有一個錯誤.這種錯誤可能表名你的一個錄制參數到了最大值,就是不能再繼續錄制了.如AVErrorMaximumDurationReached
或者AVErrorMaximumFileSizeReached
.記錄可能停止的其他原因:
1.AVErrorDiskFull
- 磁盤滿了
2.AVErrorDeviceWasDisconnected
- 錄制設備斷開了
3.AVErrorSessionWasInterrupted
- 會話被意外終端(如突然接個電話)
向一個文件添加 MetaData(元數據)
你可以在任何時候設置電影文件的元數據,即便你在錄制.這在你錄制開始,信息不可用時,作用就體現了.一個 輸出文件的 MetaData 是由AVMetadataItem
對象數組來表示的.你可以使用它的可變子類.AVMutableMetadataItem
.來創建屬於自己的元數據
AVCaptureMovieFileOutput *aMovieFileOutput = <#Get a movie file output#>;
NSArray *existingMetadataArray = aMovieFileOutput.metadata;
NSMutableArray *newMetadataArray = nil;
if (existingMetadataArray) {
newMetadataArray = [existingMetadataArray mutableCopy];
}
else {
newMetadataArray = [[NSMutableArray alloc] init];
}
AVMutableMetadataItem *item = [[AVMutableMetadataItem alloc] init];
item.keySpace = AVMetadataKeySpaceCommon;
item.key = AVMetadataCommonKeyLocation;
CLLocation *location - <#The location to set#>;
item.value = [NSString stringWithFormat:@"%+08.4lf%+09.4lf/"
location.coordinate.latitude, location.coordinate.longitude];
[newMetadataArray addObject:item];
aMovieFileOutput.metadata = newMetadataArray;
視頻處理幀
一個AVCaptureVideoDataOutput
對象使用代理來聲明視頻幀.你使用setSampleBufferDelegate:queue:
來設置代理.除了設置代理之外,還要指定一個串行隊列,在該隊列中調用代理方法.
必須使用串行隊列來確保幀以適當的順序傳遞給代理.您可以使用隊列修改傳送和處理視頻幀的優先級
在captureOutput:didOutputSampleBuffer:fromConnection:
這個代理方法中,幀被作為一個CMSampleBufferRef
隱式類型的實例被presented.默認情況下,buffers 在相機最有效的格式下被發出.
你可以使用videoSettings
屬性來自定義輸出格式.視頻的設置屬性是一個字典.目前唯一支持的key 是KCVPixelBufferPixelFormatTypeKey
.推薦的像素格式被availableVideoCVPixelFormatTypes
屬性給返回了.並且availableVideoCodecTypes
屬性返回支持的值.
AVCaptureVideoDataOutput *videoDataOutput = [AVCaptureVideoDataOutput new];
NSDictionary *newSettings =
@{ (NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA) };
videoDataOutput.videoSettings = newSettings;
// discard if the data output queue is blocked (as we process the still image
[videoDataOutput setAlwaysDiscardsLateVideoFrames:YES];)
// create a serial dispatch queue used for the sample buffer delegate as well as when a still image is captured
// a serial dispatch queue must be used to guarantee that video frames will be delivered in order
// see the header doc for setSampleBufferDelegate:queue: for more information
videoDataOutputQueue = dispatch_queue_create("VideoDataOutputQueue", DISPATCH_QUEUE_SERIAL);
[videoDataOutput setSampleBufferDelegate:self queue:videoDataOutputQueue];
AVCaptureSession *captureSession = <#The Capture Session#>;
if ( [captureSession canAddOutput:videoDataOutput] )
[captureSession addOutput:videoDataOutput];
視頻出來的性能考慮
您應該將會話輸出設置為應用程序的最低實用分辨率.將輸出設置為比必要的廢物處理周期和不必要的消耗功率更高的分辨率.
你必須確保captureoutput:didoutputsamplebuffer:fromconnection:
的實現能夠處理大量的時間分配給一個幀內的樣品緩沖液。如果時間太長,你抓住的視頻幀,AV 停止提供基礎幀,不僅對你的代理也對其他輸出如預覽層(preview layer).
你可以使用捕獲視頻數據輸出的minframeduration
屬性以確保您有足夠的時間來處理幀具有較低的幀速率比其他情況下的成本。你也可以確保alwaysdiscardslatevideoframes
屬性設置為Yes(默認)。這將確保任何遲到的視頻幀下降,而不是交給你處理。或者,如果你正在錄制,如果輸出的幀稍微晚一些沒有關系的話,你寧願都要了,這並不意味着不會掉幀(即幀仍可能下降),但他們可能不會過早被拋棄,或仍然有效.
捕獲靜止圖像
如果你想捕捉靜止圖像伴隨元數據可以使用Avcapturestillimageoutput
輸出。圖像的分辨率取決於會話的preset,以及設備
像素以及編碼格式
不同的設備支持不同的圖像格式。使用availableimagedatacvpixelformattypes
和availableimagedatacodectypes
你可以找到像素和編解碼器類型通過支持的設備。每個方法返回特定設備的支持值的數組。你可以通過設置outputsettings
詞典指定你想要的圖像格式
AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
NSDictionary *outputSettings = @{ AVVideoCodecKey : AVVideoCodecJPEG};
[stillImageOutput setOutputSettings:outputSettings];
如果你想捕捉JPEG圖像,你通常不應該指定自己的壓縮格式。相反,你應該讓靜止圖像輸出為你做壓縮,因為它的壓縮是硬件加速的。如果你需要一個數據表示的圖像,你可以使用jpegstillimagensdatarepresentation:
得到一個NSData對象沒有再壓縮數據的,即使你修改圖像的元數據
捕獲圖像
當你想要捕捉圖像時,給輸出發送一個captureStillImageAsynchronouslyFromConnection:completionHandler:
消息.第一個參數用來捕獲的連接.你需要查找輸入端口正在收集視頻的連接.
AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in stillImageOutput.connections) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo] ) {
videoConnection = connection;
break;
}
}
if (videoConnection) { break; }
}
第二個參數是一個block塊.它有兩個參數.一是包含圖像數據的隱式類型CMSampleBuffer.另一個是錯誤信息.sample buffer 它本身可能包含 metadata,如 EXIF字典.作為附件.如果你想你可以修改附件.但要注意JPEG圖像的優化.
[stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:
^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
CFDictionaryRef exifAttachments =
CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, NULL);
if (exifAttachments) {
// Do something with the attachments.
}
// Continue as appropriate.
}];
六.向用戶顯示正在錄制的內容
您可以為用戶提供相機錄制的預覽圖層preview layer
.或者麥克風(通過監聽音頻通道)
.
視頻預覽圖層
你可以通過使用AVCaptureVideoPreviewLayer
對象來給用戶提供一個正在錄制的預覽圖層.
AVCaptureVideoPreviewLayer
是CALayer的一個子類.你不需要任何輸出來顯示預覽圖層.
用AVCaptureVideoDataOutput
這個類.為客戶端應用程序提供一個能力,在視頻像素呈現給用戶之前,我們可以訪問這個視頻像素.
與捕獲輸出不同,視頻預覽層維護與其關聯的會話的強引用。這是為了確保會話沒有釋放而層試圖顯示視頻。這反映在您初始化預覽層的方式上
AVCaptureSession *captureSession = <#Get a capture session#>;
CALayer *viewLayer = <#Get a layer from the view in which you want to present the preview#>;
AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:captureSession];
[viewLayer addSublayer:captureVideoPreviewLayer];
一般情況下,預覽層就像渲染樹中其他任何的CALayer對象,您可以縮放圖像和執行轉換,旋轉,等等.一個區別是,您可能需要設置層的定位屬性,以指定它應該如何旋轉來自相機的圖像.此外,你可以通過查詢supportsVideoMirroring
屬性來為支持的設備的視頻鏡像做測試.你可以設置videoMirrored
屬性.但是當automaticallyAdjustsVideoMirroring
屬性被設置為YES 的時候.鏡像值會基於會話的配置來自動設置.
視頻重力模式
預覽層支持3種重力模式.你可以使用videoGravity:
來設置
1.AVLayerVideoGravityResizeAspect
- 保留縱橫比.視頻不填滿屏幕.有黑色條
2.AVLayerVideoGravityResizeAspectFill
- 保留縱橫比,視頻填滿屏幕.在必要時裁剪視頻
3.AVLayerVideoGravityResize
- 拉伸視頻填充可用屏幕區域,但是會扭曲圖像
使用"點擊聚焦"來預覽
您需要注意當實現TAP與預覽層一起集中。您必須解釋圖層的預覽方向和重力,以及預覽可能被鏡像的可能性。看示例代碼項目avcam iOS:利用AVFoundation捕捉到這一功能的實現圖像和電影
顯示音頻電平
使用AVCaptureAudioChannel
對象來監測平均峰值功率電平在捕獲連接中的音頻信道上.它不是KVO來監測的,所以如果要更新用戶界面.請經常更新(如1秒鍾10次)
AVCaptureAudioDataOutput *audioDataOutput = <#Get the audio data output#>;
NSArray *connections = audioDataOutput.connections;
if ([connections count] > 0) {
// There should be only one connection to an AVCaptureAudioDataOutput.
AVCaptureConnection *connection = [connections objectAtIndex:0];
NSArray *audioChannels = connection.audioChannels;
for (AVCaptureAudioChannel *channel in audioChannels) {
float avg = channel.averagePowerLevel;
float peak = channel.peakHoldLevel;
// Update the level meter user interface.
}
}
七.總而言之: 捕獲的視頻幀就是UIImage對象
這個簡短的代碼示例演示如何捕捉視頻並轉成你獲得的UIImage的對象幀.
- 創建一個
AVCaptureSession
對象來協調 AV輸入設備和輸出設備之間的數據傳輸 - 通過
AVCaptureDevice
對象找到你需要的輸入類型 - 創建一個
AVCaptureDeviceInput
輸入設備 - 創建一個
AVCaptureVideoDataOutput
對象來生成視頻幀 - 實現
AVCaptureVideoDataOutput
對象的代理來處理視頻幀 - 通過代理實現一個功能,將
CMSampleBuffeer
轉換成一個UIImage
對象
Note : 這個例子只是核心的代碼.省略了幾個方面.包括內存管理, 及
AVFoundation
的基本使用.希望你自己可以把剩余的補充完整
創建並配置捕捉會話
使用AVCaptureSession
對象來協調 AV輸入設備和輸出設備之間數據流的傳輸.創建一個session.配置它以生成一個中等分辨率的視頻幀.
AVCaptureSession *session = [[AVCaptureSession alloc] init];
session.sessionPreset = AVCaptureSessionPresetMedium;
創建並且配置設備和設備輸入
捕獲設備用AVCaptureDevice
對象來表示.類提供一個方法來獲取你想要的輸入類型.一個設備具有一個或多個端口,用AVCaptureInput
對象來配置.通常,使用默認配置
找到一個視頻捕捉設備,然后創建一個設備輸入並將其添加到會話.如果沒有找到合適的設備,之后會通過deviceInputWithDevice:error:
方法返回一個錯誤.
AVCaptureDevice *device =
[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error = nil;
AVCaptureDeviceInput *input =
[AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (!input) {
// Handle the error appropriately.
}
[session addInput:input];
創建和配置視頻數據輸出
你使用一個AVCaptureVideoDataOutput
對象來處理被捕獲視頻的未壓縮幀.通常配置輸出的幾個方面.對於視頻,你可以指定像素格式通過使用videoSettings
屬性和封頂的幀速率來設置minframeduration
屬性.
創建和配置視頻輸出數據並將其添加到會話.封頂的幀速率是15幀,設置minframeduration
屬性為 1/15
秒
AVCaptureVideoDataOutput *output = [[AVCaptureVideoDataOutput alloc] init];
[session addOutput:output];
output.videoSettings =
@{ (NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA) };
output.minFrameDuration = CMTimeMake(1, 15);
數據輸出對象使用代理
聲明視頻幀.代理必須遵守<AVCaptureVideoDataOutputSampleBufferDelegate>
協議.當你設置了數據輸出的代理.你還必須提供一個隊列來處理回調
dispatch_queue_t queue = dispatch_queue_create("MyQueue", NULL);
[output setSampleBufferDelegate:self queue:queue];
dispatch_release(queue);
你使用隊列來修改傳送和處理視頻幀的優先級
實現 Sample Buffer 代理方法
在代理類中,當一個 sample buffer (樣本緩沖區) 被寫入的時候,實現captureOutput:didOutputSampleBuffer:fromConnection:
這個方法.視頻數據輸出對象提供CMSampleBuffer
類型的對象.所以你需要從CMSampleBuffer
類型轉換到UIImage類型.這個操作的目的就是將CMSampleBuffer轉成UIImage
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection {
UIImage *image = imageFromSampleBuffer(sampleBuffer);
// Add your code here that uses the image.
}
記住,代理方法是指定在setSampleBufferDelegate:queue:
隊列調用:;如果你想更新UI,你必須調用任何相關代碼在主線程
開始和停止錄制
在配置捕獲會話之后,你要確保相機允許按照用戶的意願來錄制
NSString *mediaType = AVMediaTypeVideo;
[AVCaptureDevice requestAccessForMediaType:mediaType completionHandler:^(BOOL granted) {
if (granted)
{
//Granted access to mediaType
[self setDeviceAuthorized:YES];
}
else
{
//Not granted access to mediaType
dispatch_async(dispatch_get_main_queue(), ^{
[[[UIAlertView alloc] initWithTitle:@"AVCam!"
message:@"AVCam doesn't have permission to use Camera, please change privacy settings"
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil] show];
[self setDeviceAuthorized:NO];
});
}
}];
如果相機會話已經配置了,並且獲得用戶訪問攝像頭的權限了(如果需要,還有麥克風),那么就發送一個startRunning
消息來開始錄制.
注意:
startRunning
這個方法調用會需要一些時間.如果在主線程調用,那么就會阻塞主線程,造成卡頓.我們要在子線程中執行這個方法.
[session startRunning];
如果要停止錄制的話,那么就發送一個stopRunning
的消息
[session stopRunning];
高幀頻視頻采集
iOS 7 引入了高幀速率的視頻拍攝支持在選定的硬件設備上(也稱"SloMo"視頻).整個AVFoundation框架都支持高幀速率的內容.
使用AVCaptureDevieFormat
類來確定一個設備的捕捉能力.這個類有如下這些方法用來返回一些支持的媒體類型. 幀速率、視野、最大縮放因子、是否支持視頻穩定等.
- 捕捉支持每秒60幀,全720p(1280 * 720像素)的分辨率.包括視頻的穩定性和可刪除的P幀(H264對電影的特征編碼,使電影可以在又慢有老的硬件設備上都可以順暢的播放)
- 回放具有增加的音頻支持慢速和快速播放.允許音頻的時間間距可以保存在較慢或更快的速度.
- 編輯完全支持可變編輯的縮放編輯
- 當支持FPS 60的電影輸出有兩種選擇時,可變幀速率,慢或塊的運動,我們可以把它轉成慢幀速率,如每秒30幀
錄音重放
AVPlayer
的實例管理大部分的回放速度.回放速度通過設置setRate:
方法的值來自動設置.該值用作播放速度的乘數.值為1.0表示可以正常回放,0.5的話回放速度減半,5.0的話就是正常播放速度的5倍,等等
AVPlayerItem
對象支持audioTimePitchAlgorithm
屬性.當電影使用不同的幀速率通過使用Time Pitch Algoruthm Settings
常量正在播放,這個屬性允許你指定音頻.
下表顯示了支持的時間間距算法,質量,該算法是否導致音頻捕捉到特定幀速率,以及每個算法支持的幀速率范圍.
- AVAudioTimePitchAlgorithmLowQualityZeroLatency
- 質量低,適合快進,快退或低質量語音
- AVAudioTimePitchAlgoruthmTimeDomain
- 質量適中,計算成本較低,適合語音
- AVAudioTimePitchAlgorithmSpectral
- 最高質量,最昂貴的計算,保留了原來的項目間距
- AVAudioTimePitchAlgorithmVarispeed
- 高品質的播放沒有音高校正
編輯
當開始編輯時,你用AVMutableComposition
類來建立短暫的編輯
- 用
composition
類方法來創建一個AVMutableComposition
實例 - 用
insertTimeRange:ofAsset:atTime:error:
這個方法來插入你的視頻資源 - 用
scaleTimeRange:toDuration:
方法來設置組成部分的時間刻度.
輸出
使用AVAssetExportSession
類來輸出 FPS 60的視頻,使用兩種技術可以導出內容
- 使用
AVAssetExportPresetPassthrough
預先避免重新編碼的電影.隨着媒體的部分FPS 60,部分加速,部分放緩.它會重新為媒體定時 - 使用一個恆定的幀速率導出最大的回放兼容性,設置視頻合成的
frameDuration
屬性為30 fps,你也可以指定時間間距通過設置輸出會話的audioTimePitchAlgorithm
屬性.
錄制
使用AVCaptureMovieFileOutput
類來捕獲高幀率的視頻,它自動支持高幀率視頻的錄制,他會自動選擇正確的H264的音高和比特率
為了做自定義的錄制.你必須使用AVAssetWriter
類,它需要一些額外的設置
assetWriterInput.expectsMediaDataInRealTime=YES;
這個設置可以確保可以與傳入的數據保持一致.
翻譯了一部分,還沒有完全完成....