iPhone 手機(jī)在圖片拍照和視頻錄制方面有很強(qiáng)大的功能,小編認(rèn)為如果很好使用 iPhone 拍攝出很好照片 & 錄制很有趣的視頻。本章將詳細(xì)講解 AVCaptureSession ,并最后給出 FYCameraKit 項(xiàng)目Demo。
下面小編為大家講解 iOS 拍照和視頻錄制功能實(shí)現(xiàn),下圖是鏡頭采集需要的類:

總體介紹
在整個鏡頭采集過程小編把整個過程比作我們常見發(fā)電過程:均是通過特定的步驟實(shí)現(xiàn)得到最后的產(chǎn)物。下面??做詳細(xì)解釋:
AVCaptureSession (發(fā)電機(jī))
AVCaptureSession :作為音視頻捕捉會話,把鏡頭和麥克風(fēng)捕捉到的音視頻源輸出到設(shè)備中。
提示:可以有多個輸入和輸出。
AVCaptureDevice (發(fā)電設(shè)備)
AVCaptureDevice:輸入設(shè)備,包括:攝像頭和麥克風(fēng)??梢酝ㄟ^設(shè)置一些參數(shù)來調(diào)節(jié)設(shè)備采集效果(例如:曝光,白平衡和聚焦等)。
AVCaptureInput (水風(fēng)能源)
AVCaptureInput:輸入數(shù)據(jù)管理對象,經(jīng)過 AVCaptureDevice 實(shí)現(xiàn)初始化,然后添加到 AVCaptureSession (發(fā)電機(jī)) 中進(jìn)行相應(yīng)的輸出。
子類:AVCaptureDeviceInput、AVCaptureScreenInput和AVCaptureMetadataInput。
AVCaptureOutput (電力)
AVCaptureOut:數(shù)據(jù)輸出管理,通過 AVCaptureSession 中輸出??梢酝ㄟ^相關(guān)的協(xié)議實(shí)對應(yīng)的數(shù)據(jù)輸出。
子類:AVCaptureFileOutput、AVCapturePhotoOutput、AVCaptureStillImageOutput、AVCaptureVideoDataOutput、AVCaptureAudioDataOutput、AVCaptureAudioPreviewOutput、AVCaptureDepthDataOutput和AVCaptureMetadataOutput。
AVCaptureVideoPreviewLayer (發(fā)電預(yù)覽)
AVCaptureVideoPreviewLayer:可以支持在拍攝過程中進(jìn)行相關(guān)的預(yù)覽,只需要在初始時實(shí)現(xiàn)對應(yīng)的 AVCaptureSession 即可。
視頻錄制
下面展示在蘋果官方開發(fā)文檔給出的圖:

視頻錄制總概
- 創(chuàng)建
AVCaptureSession對象 - 使用
AVCaptureDevice靜態(tài)方法獲取設(shè)備常使用設(shè)備,例如:拍照和錄像需要的攝像頭,錄音所需的麥克風(fēng) - 利用輸入設(shè)備
AVCaptureDevice初始化AVCaptureDeviceInput對象 - 初始化輸出數(shù)據(jù)管理對象,拍照進(jìn)行初始化
AVCaptureStillImageOutput對象,拍照初始化AVCaptureMovieFileOutput對象 - 將數(shù)據(jù)輸入對象
AVCaptureDeviceInput和數(shù)據(jù)輸出對象AVCaptureDeviceOutput添加到媒體會話管理對象AVCaptureSession中 - 創(chuàng)建預(yù)覽的圖層
AVCaptureVideoPreviewLayer指定媒體會話,添加圖層到容器,調(diào)用AVCaptureSession中的StartRunning方法開始捕捉 - 將捕捉到內(nèi)容保存到指定文件中
詳解鏡頭采集類
AVCaptureSession
小編查看 AVCaptureSession.h文件看到,在鏡頭采集的過程中有兩種實(shí)現(xiàn)方式。
- 使用系統(tǒng)
AVCaptureSession自動配置輸入和輸出- 手動配置輸入和輸出之間的對應(yīng)關(guān)系
(1) AVCaptureSession 初始化
- 使用
AVCaptureSession自動配置輸入和輸出之間對應(yīng)關(guān)系
AVCaptureSession *session = [[AVCaptureSession alloc] init];
AVCaptureDevice *audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
NSError *error = nil;
AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioCaptureDevice error:&error];
[session beginConfiguration];
session.sessionPreset = AVCaptureSessionPresetPhoto;
if (audioInput) {
}else {
//// Handle the failure.
[session commitConfiguration];
}
if ([session canAddInput:audioInput]) {
[session addInput:audioInput];
}else {
// Handle the failure.
[session commitConfiguration];
}
上面代碼是 AVCaptureSession 進(jìn)行初始化并且實(shí)現(xiàn)初始化麥克風(fēng)進(jìn)行相關(guān)音頻錄制,并添加到 AVCaptureSession中。
beginConfiguration & commitConfiguration 在進(jìn)行配置 AVCaptureSession 的相關(guān)屬性值時需要對這兩個函數(shù)調(diào)用,并且這兩個函數(shù)是成對出現(xiàn)。
- 手動配置
AVCaptureSession輸入和輸出之間對應(yīng)關(guān)系
AVCaptureSession *session = [[AVCaptureSession alloc] init];
[session beginConfiguration];
NSError *error = nil;
AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
if (!videoInput) {
//handle configuration video device
}
AVCaptureInputPort *videoPort = videoInput.ports[0];
error = nil;
AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];
if (!videoInput) {
//handle configuration audio device
}
AVCaptureInputPort *audioPort = audioInput.ports[0];
NSArray<AVCaptureInputPort *> *inputPorts = @[videoPort, audioPort];
AVCaptureVideoDataOutput *videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
AVCaptureConnection *connection = [AVCaptureConnection connectionWithInputPorts:inputPorts output:videoDataOutput];
if ([session canAddConnection:connection]) {
[session addConnection:connection];
}else {
//handle session can not add AVCaptureConnection
[session commitConfiguration];
return;
}
[session commitConfiguration];
上面??代碼是使用 AVCaptureConnection實(shí)現(xiàn)在 AVCaptureSession 使輸入和輸出進(jìn)行自己配置。
詳細(xì)的細(xì)節(jié)會在 FYCameraKit 進(jìn)行詳細(xì)的講解。
注釋:
1)只有在調(diào)用beginConfiguration時我們對AVCaptureSession配置才會被真正開始修改。
(2) AVCaptureSession 中斷
在音視頻錄制過程中可能對因?yàn)殡娫拰?dǎo)致中斷,開發(fā)過程中提供中斷結(jié)束后獲取中斷產(chǎn)生的原因。
- 注冊中斷監(jiān)聽 & 刪除監(jiān)聽
//監(jiān)聽注冊
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleCaptureSession:) name:AVCaptureSessionInterruptionEndedNotification object:_session];
//監(jiān)聽清除
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureSessionInterruptionEndedNotification object:_session];
- 從傳遞的
userInfo通過關(guān)鍵key獲取原因:
AVCaptureSessionInterruptionReasonKey
- 獲取具體的中斷原因:
typedef NS_ENUM(NSInteger, AVCaptureSessionInterruptionReason) {
AVCaptureSessionInterruptionReasonVideoDeviceNotAvailableInBackground = 1,//從后臺運(yùn)行開啟 camera,不夠 iOS 9.0 之后不提供中斷
AVCaptureSessionInterruptionReasonAudioDeviceInUseByAnotherClient = 2,//音頻軟軟件被占用
AVCaptureSessionInterruptionReasonVideoDeviceInUseByAnotherClient = 3,//視頻軟件被占用
AVCaptureSessionInterruptionReasonVideoDeviceNotAvailableWithMultipleForegroundApps = 4,//全屏或者是錄制屏幕變化
}
- 監(jiān)聽事件的處理
- (void)handleCaptureSession:(NSNotification *)notification {
AVCaptureSessionInterruptionReason reason = [[notification.userInfo objectForKey:AVCaptureSessionInterruptionReasonKey] unsignedIntegerValue];
switch (reason) {
case AVCaptureSessionInterruptionReasonVideoDeviceNotAvailableInBackground:
{
//handle device not available background
break;
}
case AVCaptureSessionInterruptionReasonAudioDeviceInUseByAnotherClient:
{
//handle that audio was occupied
break;
}
case AVCaptureSessionInterruptionReasonVideoDeviceInUseByAnotherClient:
{
//handle that video was occupied
break;
}
case AVCaptureSessionInterruptionReasonVideoDeviceNotAvailableWithMultipleForegroundApps:
{
//handle that UI was multiple
break;
}
}
}
實(shí)現(xiàn)拍照和視頻錄制的 FYCameraKit 的下載地址: FYCameraKit
最后給出 AVFoundation API 的總結(jié):

參考資料:
AVCaptureSession
AVCaptureDevice
AVCaptureConnection
第一次發(fā)布:2017/8/10 20:49:21 星期四
第二次發(fā)布:2017/8/10 23:36:34 星期四