IOS音視頻(一)AVFoundation核心類

  • 做音視頻開發(fā)是個(gè)很復(fù)雜的工作攒读,需要我們理解很多有關(guān)素材的知識(shí):聲學(xué)和視覺相關(guān)的科學(xué)理論,數(shù)的程序開發(fā)技術(shù)和有AVFoundation框架而引出的其他框架的知識(shí),比如:Core Media, Core Video, Core Image, Core Audio, Media PlayerVideoToolbox 等等被盈。

  • 要做IOS音視頻相關(guān)的開發(fā),肯定要熟悉AVFoundation框架律歼。學(xué)習(xí)框架最好的方式就是研究蘋果官方文檔:蘋果官方AVFoundation框架介紹

  • AVFoundation 是 Objective-C 中創(chuàng)建及編輯視聽媒體文件的幾個(gè)框架之一,其提供了檢查啡专、創(chuàng)建险毁、編輯或重新編碼媒體文件的接口,也使得從設(shè)備獲取的視頻實(shí)時(shí)數(shù)據(jù)可操縱。但是畔况,通常情況鲸鹦,簡單的播放或者錄像,直接使用 AVKit 框架或者 UIImagePickerController 類即可跷跪。另外馋嗜,值得注意的是,在 AVFoundation 框架中使用的基本數(shù)據(jù)結(jié)構(gòu)吵瞻,如時(shí)間相關(guān)的或描述媒體數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)都聲明在 CoreMedia 框架中葛菇。

  • AVFoundation 是 OSX 系統(tǒng)和 iOS 系統(tǒng)中用于處理基于時(shí)間的媒體數(shù)據(jù)的高級(jí) objectivec 框架,其設(shè)計(jì)過程高度依賴多線程機(jī)制橡羞,充分利用了多核硬件優(yōu)勢眯停,大量使用 Block 和 GCD 機(jī)制。AVFoundation 能與高層級(jí)框架無縫銜接卿泽,也能提供低層級(jí)框架的功能和性能莺债。

1. AVFoundation框架架構(gòu)簡介

  • 引用蘋果官方文檔介紹圖如下:
iOS系統(tǒng)上的AVFoundation框架架構(gòu)
Mac OS X系統(tǒng)上的AVFoundation框架架構(gòu)

Core Audio是OS X和IOS系統(tǒng)上處理所有音頻 事件的框架。Core Audio是有多高框架整合在一起的總稱签夭,為音頻和MIDI內(nèi)容的錄制齐邦,播放和處理提供相應(yīng)的接口。Core Audio也提供高級(jí)的接口第租,比如通過Audio Queue Services框架所提供的那些接口措拇,主要處理基本的音頻播放和錄音相關(guān)功能。同時(shí)還會(huì)提供相對(duì)低層級(jí)的接口煌妈,尤其是Audio Units接口儡羔,它們提供了針對(duì)音頻信號(hào)進(jìn)行完全控制的功能,并通過Audio Units讓你能夠構(gòu)建一些復(fù)雜的音頻處理模式璧诵,就像通過蘋果公司的Logic Pro X和Avid's Pro Tolls工具所實(shí)現(xiàn)的功能一樣。

Core Video是OS X 和IOS系統(tǒng)上針對(duì)數(shù)字視頻所提供的管道模式仇冯。Core Video為其相對(duì)的Core Media提供圖片緩存和緩存支持之宿,提供了一個(gè)能夠?qū)?shù)字視頻逐幀訪問的接口。該框架通過像素格式之間的轉(zhuǎn)換并管理同步事項(xiàng)時(shí)的復(fù)雜的工作得到了有效簡化苛坚。

Core Media 是AV Foundation所用到的低層級(jí)媒體管道的一部分比被。它提供針對(duì)音頻樣本和視頻幀處理所需的低層級(jí)數(shù)據(jù)類型和接口。Core Media還提供了AV Foundation用的的基于CMTime數(shù)據(jù)類型的時(shí)間模型泼舱。CMTime及其相關(guān)數(shù)據(jù)類型一般在AV Foundation處理基于時(shí)間的操作時(shí)使用等缀。

Core Animation時(shí)OS X和 iOS 提供的合成及動(dòng)畫相關(guān)框架。主要功能就是提供蘋果平臺(tái)所具有的美觀娇昙,流暢的動(dòng)畫效果尺迂。提供了一個(gè)簡單,聲明行的編程模式,并已經(jīng)封裝了支持OpenGL 和OpenGL ES 功能的基于Object-C的各種類噪裕。使用Core Animation時(shí)蹲盘,對(duì)于食品內(nèi)容的播放和視頻捕獲這兩個(gè)動(dòng)作,AVFoundation 提供了硬件加速機(jī)制來對(duì)整個(gè)流程進(jìn)行優(yōu)化膳音。AVFoundation 還可以利用Core Animation讓開發(fā)者能夠在視頻編輯和播放過程中添加動(dòng)畫標(biāo)題和圖片效果召衔。

  • 蘋果提供了AVFoundation框架,可以用來檢測祭陷,編輯苍凛,創(chuàng)建,重新編碼媒體文件兵志,還可以實(shí)時(shí)獲取設(shè)備的流媒體數(shù)據(jù)毫深,實(shí)時(shí)操作這些被捕獲的視頻流數(shù)據(jù)。
  • 蘋果推薦我們盡可能的使用高度抽象的接口:
  1. 如果只是簡單播放視頻文件毒姨,使用AVKit框架即可哑蔫。
  2. 如果只是想簡單錄制視頻,使用UIKit框架里的UIImagePickerController既可以實(shí)現(xiàn)弧呐。

1.1 AVFoundation框架

AVFoundation 提供的核心功能如下所示

AVFoundation框架1
  • AVFoundation 框架中最基本的類是 AVAsset 鸠蚪,它是一個(gè)或者多個(gè)媒體數(shù)據(jù)的集合今阳,描述的是整個(gè)集合的屬性,如標(biāo)題茅信、時(shí)長盾舌、大小等,并且沒有特定的數(shù)據(jù)格式蘸鲸。集合的每一個(gè)媒體數(shù)據(jù)都是統(tǒng)一的數(shù)據(jù)類型妖谴,稱之為 track。簡單的情況是一種數(shù)據(jù)是音頻數(shù)據(jù)酌摇,一種是視頻數(shù)據(jù)膝舅,而較復(fù)雜的情況是一種數(shù)據(jù)交織著音頻和視頻數(shù)據(jù),并且 AVAsset 是可能有元數(shù)據(jù)的窑多。
    另外仍稀,需要明白的是在 AVFoundation 中,初始化了 asset 及 track 后埂息,并不意味著資源已經(jīng)可用技潘,因?yàn)槿糍Y源本身并不攜帶自身信息時(shí)遥巴,那么系統(tǒng)需要自己計(jì)算相關(guān)信息,這個(gè)過程會(huì)阻塞線程崭篡,所以應(yīng)該使用異步方式進(jìn)行獲取資源信息后的操作挪哄。

  • AVFoundation 中可以使用 compositions 將多個(gè)媒體數(shù)據(jù)(video/audio tracks)合成為一個(gè) asset ,這個(gè)過程中琉闪,可以添加或移除 tracks 迹炼,調(diào)整它們的順序,或者設(shè)置音頻的音量和變化坡度颠毙,視頻容量等屬性斯入。這些媒體數(shù)據(jù)的集合保存在內(nèi)存中,直到使用 export session 將它導(dǎo)出到本地文件中蛀蜜。另外刻两,還可以使用 asset writer 創(chuàng)建 asset 。

  • 使用 capture session 協(xié)調(diào)從設(shè)備(如相機(jī)滴某、麥克風(fēng))輸入的數(shù)據(jù)和輸出目標(biāo)(如視頻文件)磅摹。可以為 session 設(shè)置多個(gè)輸入和輸出霎奢,即使它正在工作户誓,還可以通過它停止數(shù)據(jù)的流動(dòng)。另外幕侠,還可以使用 preview layer 將相機(jī)記錄的影像實(shí)時(shí)展示給用戶帝美。

  • AVFoundation 中的回調(diào)處理并不保證回調(diào)任務(wù)在某個(gè)特定的線程或隊(duì)列中執(zhí)行,其遵循兩個(gè)原則晤硕,UI 相關(guān)的操作在主線程中執(zhí)行悼潭,其他回調(diào)需要為其指定調(diào)用的隊(duì)列。

1.2 AVFoundation 之 Assets

Assets
  • 參考蘋果官方介紹

  • AVAsset 是AVFoundation框架里的一個(gè)核心類舞箍,主要提供了一種形式獨(dú)立的基于時(shí)間的視聽數(shù)據(jù)抽象舰褪,例如電影文件或視頻流。

    AVAsset類繼承關(guān)系

  • AVAsset 包含需要一起呈現(xiàn)或處理的音軌集合创译,每個(gè)音軌都是統(tǒng)一的媒體類型抵知,包括(但不限于)音頻、視頻软族、文本、封閉字幕和字幕残制。asset對(duì)象提供關(guān)于整個(gè)資源的信息立砸,比如它的持續(xù)時(shí)間或標(biāo)題,以及表示的提示初茶,比如它的大小颗祝。AVAsset 也可以有元數(shù)據(jù),由AVMetadataItem的實(shí)例表示。

  • 跟蹤由AVAssetTrack的實(shí)例表示螺戳,在一個(gè)典型的簡單例子中搁宾,一個(gè)軌道表示音頻組件,另一個(gè)表示視頻組件;在一個(gè)復(fù)雜的組合中倔幼,音頻和視頻可能會(huì)有多個(gè)重疊的音軌盖腿。

AVAssetTrack結(jié)構(gòu)
  • 音軌具有許多屬性,例如其類型(視頻或音頻)损同、可視和/或可聽特征(視情況而定)翩腐、元數(shù)據(jù)和時(shí)間軸(以其父資產(chǎn)的形式表示)。磁道也有一組格式說明膏燃。數(shù)組包含CMFormatDescription對(duì)象(參見CMFormatDescriptionRef)茂卦,每個(gè)對(duì)象描述曲目引用的媒體樣本的格式。包含統(tǒng)一媒體的磁道(例如组哩,所有使用相同設(shè)置編碼的磁道)將提供一個(gè)計(jì)數(shù)為1的數(shù)組等龙。

  • 一個(gè)磁道本身可以被分割成段,用AVAssetTrackSegment的實(shí)例來表示伶贰。段是從源到資產(chǎn)跟蹤時(shí)間線的時(shí)間映射蛛砰。

  • CMTime是一個(gè)C結(jié)構(gòu),它將時(shí)間表示為一個(gè)有理數(shù)幕袱,具有一個(gè)分子(int64_t值)和一個(gè)分母(int32_t時(shí)間刻度)暴备。從概念上講,時(shí)間刻度指定了分子中每個(gè)單位所占的秒數(shù)们豌。因此涯捻,如果時(shí)間刻度是4,每個(gè)單元代表四分之一秒;如果時(shí)間刻度是10望迎,每個(gè)單元表示十分之一秒障癌,以此類推。您經(jīng)常使用600的時(shí)間刻度辩尊,因?yàn)檫@是幾種常用幀率的倍數(shù):24幀用于電影涛浙,30幀用于NTSC(用于北美和日本的電視),25幀用于PAL(用于歐洲的電視)摄欲。使用600的時(shí)間刻度轿亮,您可以精確地表示這些系統(tǒng)中的任意數(shù)量的幀。除了簡單的時(shí)間值之外胸墙,CMTime結(jié)構(gòu)還可以表示非數(shù)值:+∞我注、-∞和不定。它還可以指示時(shí)間是否在某個(gè)點(diǎn)被四舍五入迟隅,并保持一個(gè)歷元數(shù)但骨。

  • 您可以使用CMTimeMakeCMTimeMakeWithSeconds等相關(guān)函數(shù)之一創(chuàng)建時(shí)間(該函數(shù)允許您使用浮點(diǎn)值創(chuàng)建時(shí)間并指定首選時(shí)間刻度)励七。有幾個(gè)函數(shù)用于基于時(shí)間的算術(shù)和比較時(shí)間,如下例所示:

CMTime time1 = CMTimeMake(200, 2); // 200 half-seconds
CMTime time2 = CMTimeMake(400, 4); // 400 quarter-seconds
 
// time1 and time2 both represent 100 seconds, but using different timescales.
if (CMTimeCompare(time1, time2) == 0) {
    NSLog(@"time1 and time2 are the same");
}
 
Float64 float64Seconds = 200.0 / 3;
CMTime time3 = CMTimeMakeWithSeconds(float64Seconds , 3); // 66.66... third-seconds
time3 = CMTimeMultiply(time3, 3);
// time3 now represents 200 seconds; next subtract time1 (100 seconds).
time3 = CMTimeSubtract(time3, time1);
CMTimeShow(time3);
 
if (CMTIME_COMPARE_INLINE(time2, ==, time3)) {
    NSLog(@"time2 and time3 are the same");
}


  • AVFoundation 提供了多種方法來創(chuàng)建 asset 奔缠,可以簡單的重編碼已經(jīng)存在的 asset 掠抬,這個(gè)過程可以使用 export session 或者使用 asset reader 和 asset writer 。
  • 若要生成視頻的縮略圖校哎,可以使用 asset 初始化一個(gè) AVAssetImageGenerator 實(shí)例對(duì)象两波,它會(huì)使用默認(rèn)可用的視頻 tracks 來生成圖片。
  • 創(chuàng)建 AVAsset 或其子類 AVURLAsset 時(shí)贬蛙,需要提供資源的位置雨女,方法如下:
NSURL *url = <#視聽資源的 URL ,可以是本地文件地址阳准,也可以是網(wǎng)頁媒體鏈接#>;
AVURLAsset *anAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
  • 上述方法的第二個(gè)參數(shù)是創(chuàng)建對(duì)象時(shí)的選擇項(xiàng)氛堕,其中可能包含的選擇項(xiàng)如下:

AVURLAssetPreferPreciseDurationAndTimingKey 是否需要資源的準(zhǔn)確時(shí)長,及訪問資源各個(gè)準(zhǔn)確的時(shí)間點(diǎn)
AVURLAssetReferenceRestrictionsKey 鏈接其他資源的約束
AVURLAssetHTTPCookiesKey 添加資源能夠訪問的 HTTP cookies
AVURLAssetAllowsCellularAccessKey 是否能夠使用蜂窩網(wǎng)絡(luò)

  • 創(chuàng)建并初始化一個(gè) AVAsset 實(shí)例對(duì)象后野蝇,并不意味著該對(duì)象的所有屬性都可以獲取使用了讼稚,因?yàn)槠渲械囊恍傩孕枰~外的計(jì)算才能夠得到,那么當(dāng)獲取這些屬性時(shí)绕沈,可能會(huì)阻塞當(dāng)前線程锐想,所以需要異步獲取這些屬性。
  • AVAsset 與 AVAssetTrack 都遵循 AVAsynchronousKeyValueLoading 協(xié)議乍狐,這個(gè)協(xié)議中有以下兩個(gè)方法:
//獲取指定屬性的狀態(tài)
- (AVKeyValueStatus)statusOfValueForKey:(NSString *)key error:(NSError * _Nullable * _Nullable)outError;

//異步加載指定的屬性集合
- (void)loadValuesAsynchronouslyForKeys:(NSArray<NSString *> *)keys completionHandler:(nullable void (^)(void))handler;
  • 通常赠摇,我們使用上述第二個(gè)方法異步加載想要的屬性,而后在加載完成的回調(diào) block 中使用第一個(gè)方法判斷屬性是否加載成功浅蚪,然后訪問想要的屬性藕帜,執(zhí)行自己的操作,如下代碼:
NSURL *url = <#資源路徑#>;
AVURLAsset *anAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
NSArray *keys = @[@"duration",@"tracks"];

[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^() {

    NSError *error = nil;
    AVKeyValueStatus tracksStatus = [asset statusOfValueForKey:@"tracks" error:&error];
    //根據(jù)相應(yīng)的屬性狀態(tài)進(jìn)行對(duì)應(yīng)的處理
    switch (tracksStatus) {
        case AVKeyValueStatusUnknown:
                //TODO
            break;
        case AVKeyValueStatusLoading:
                //TODO
            break;
        case AVKeyValueStatusLoaded:
                //TODO
            break;
        case AVKeyValueStatusFailed:
                //TODO
            break;
        case AVKeyValueStatusCancelled:
                //TODO
            break;
   }
}];

1.3 AVFoundation 之 視頻播放

AVFoundation Player1

AVFoundation Player2

1.3.1 AVPlayer

  • 具體可以參考蘋果官方介紹的Playback章節(jié)

  • 要控制媒體資源的回放惜傲,可以使用AVPlayer對(duì)象洽故。在回放期間,您可以使用AVPlayerItem實(shí)例來管理整個(gè)Asset的表示狀態(tài)盗誊,使用AVPlayerItemTrack對(duì)象來管理單個(gè)曲目的表示狀態(tài)时甚。要顯示視頻,可以使用AVPlayerLayer對(duì)象哈踱。

  • player是一個(gè)控制器對(duì)象荒适,您可以使用它來管理資產(chǎn)的回放,例如啟動(dòng)和停止回放开镣,以及查找特定的時(shí)間吻贿。您使用AVPlayer實(shí)例來播放單個(gè)資產(chǎn)。您可以使用AVQueuePlayer對(duì)象按順序播放許多項(xiàng)(AVQueuePlayer是AVPlayer的子類)哑子。在OS X上,你可以選擇使用AVKit框架的AVPlayerView類來回放視圖中的內(nèi)容。

  • 播放器向您提供有關(guān)播放狀態(tài)的信息呜叫,因此侦香,如果需要,您可以將用戶界面與播放器的狀態(tài)同步弥奸。通常將播放器的輸出定向到特定的核心動(dòng)畫層(AVPlayerLayerAVSynchronizedLayer的實(shí)例)榨惠。有關(guān)層的更多信息,請(qǐng)參見Core Animation Programming Guide盛霎。

  • 盡管最終你想要播放資產(chǎn)赠橙,但你不能直接提供資產(chǎn)給AVPlayer 對(duì)象。而是提供AVPlayerItem的一個(gè)實(shí)例愤炸。播放器項(xiàng)管理與其相關(guān)聯(lián)的資產(chǎn)的表示狀態(tài)期揪。播放器項(xiàng)包含播放器項(xiàng)跟蹤—avplayeritemtrack的實(shí)例—對(duì)應(yīng)于資產(chǎn)中的跟蹤。各對(duì)象之間的關(guān)系如圖所示:

    AVAsset對(duì)象關(guān)系

  • 這種抽象意味著您可以同時(shí)使用不同的玩家來玩給定的資產(chǎn)规个,但是每個(gè)玩家呈現(xiàn)的方式不同凤薛。圖2-2顯示了一種可能性,即兩個(gè)不同的玩家使用不同的設(shè)置來玩相同的資產(chǎn)诞仓。例如缤苫,使用項(xiàng)曲目,您可以在回放期間禁用特定的曲目(例如墅拭,您可能不想播放聲音組件)活玲。


    圖2-2
  • 您可以使用現(xiàn)有資產(chǎn)初始化播放器項(xiàng),也可以直接從URL初始化播放器項(xiàng)谍婉,以便在特定位置播放資源(AVPlayerItem將隨后為資源創(chuàng)建和配置資產(chǎn))舒憾。不過,與AVAsset一樣屡萤,簡單地初始化播放器項(xiàng)并不一定意味著它可以立即播放珍剑。您可以觀察(使用鍵值觀察)一個(gè)項(xiàng)目的狀態(tài)屬性來確定它是否準(zhǔn)備好了,以及何時(shí)準(zhǔn)備好了死陆。

  • 使用一個(gè) AVPlayer 類實(shí)例可以管理一個(gè) asset 資源招拙,但是它的屬性 currentItem 才是 asset 的實(shí)際管理者。currentItem 是 AVPlayerItem 類的實(shí)例措译,而它的屬性 tracks 包含著的 AVPlayerItemTracker 實(shí)例對(duì)應(yīng)著 asset 中的各個(gè) track 别凤。

  • 那么,為了控制 asset 的播放领虹,可以使用 AVPlayer 類规哪,在播放的過程中,可以使用 AVPlayerItem 實(shí)例管理整個(gè) asset 的狀態(tài)塌衰,使用 AVPlayerItemTracker 對(duì)象管理 asset 中每個(gè) track 的狀態(tài)诉稍。另外蝠嘉,還可以使用 AVPlayerLayer 類來顯示播放的內(nèi)容。

  • 所以杯巨,在創(chuàng)建 AVPlayer 實(shí)例對(duì)象時(shí)蚤告,除了可以直接傳遞資源文件的路徑進(jìn)行創(chuàng)建外,還可以傳遞 AVPlayerItem 的實(shí)例對(duì)象服爷,如下方法:

+ (instancetype)playerWithURL:(NSURL *)URL;
+ (instancetype)playerWithPlayerItem:(nullable AVPlayerItem *)item;
- (instancetype)initWithURL:(NSURL *)URL;
- (instancetype)initWithPlayerItem:(nullable AVPlayerItem *)item;
  • 創(chuàng)建后杜恰,并不是可以直接使用,還要對(duì)它的狀態(tài)進(jìn)行檢查仍源,只有 status 的值為 AVPlayerStatusReadyToPlay 時(shí)心褐,才能進(jìn)行播放,所以這里需要使用 KVO 模式對(duì)該狀態(tài)進(jìn)行監(jiān)控笼踩,以決定何時(shí)可以進(jìn)行播放逗爹。
  • 若要管理多個(gè)資源的播放,則應(yīng)使用 AVPlayer 的子類 AVQueuePlayer 戳表,這個(gè)子類擁有的多個(gè) AVPlayerItem 同各個(gè)資源相對(duì)應(yīng)桶至。

1.3.2 播放不同類型的資源

  • 對(duì)于播放不同類型的資源,需要進(jìn)行的準(zhǔn)備工作有所不同匾旭,這主要取決于資源的來源镣屹。資源數(shù)據(jù)可能來自本地設(shè)備上文件的讀取,也可能來自網(wǎng)絡(luò)上數(shù)據(jù)流价涝。
  • 對(duì)于本地文件女蜈,可以使用文件地址創(chuàng)建 AVAsset 對(duì)象,而后使用該對(duì)象創(chuàng)建 AVPlayerItem 對(duì)象色瘩,最后將這個(gè) item 對(duì)象與 AVPlayer 對(duì)象相關(guān)聯(lián)伪窖。之后,便是等待 status 的狀態(tài)變?yōu)?AVPlayerStatusReadyToPlay 居兆,便可以進(jìn)行播放了覆山。
  • 對(duì)于網(wǎng)絡(luò)數(shù)據(jù)的播放,不能使用地址創(chuàng)建 AVAsset 對(duì)象了泥栖,而是直接創(chuàng)建 AVPlayerItem 對(duì)象簇宽,將其同 AVPlayer 對(duì)象相關(guān)聯(lián),當(dāng) status 狀態(tài)變?yōu)?AVPlayerStatusReadyToPlay 后吧享,AVAssetAVAssetTrack 對(duì)象將由 item 對(duì)象創(chuàng)建魏割。

1.3.3 播放控制

  • 通過調(diào)用 player 的 play 、pause 钢颂、setRate: 方法钞它,可以控制 item 的播放,這些方法都會(huì)改變 player 的屬性 rate 的值,該值為 1 表示 item 按正常速率播放遭垛,為 0 表示 item 暫停播放尼桶,0~1 表示低速播放,大于 1 表示高速播放耻卡,小于 0 表示從后向前播放疯汁。
  • item 的屬性 timeControlStatus 的值表示當(dāng)前 item 的狀態(tài),有下面 3 個(gè)值:
  1. AVPlayerTimeControlStatusPaused 暫停
  2. AVPlayerTimeControlStatusPlaying 播放
  3. AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate 等待按指定速率播放狀態(tài)卵酪,該狀態(tài)是當(dāng) rate 的值設(shè)置為非 0 值時(shí),而 item 因某些原因還無法播放的情況谤碳,而無法播放的原因溃卡,可依通過 item 的 reasonForWaitingToPlay 屬性值查看。
  • item 的屬性 actionAtItemEnd 的值表示當(dāng)前 item 播放結(jié)束后的動(dòng)作蜒简,有下面 3 個(gè)值:
  1. AVPlayerActionAtItemEndAdvance 只適用于 AVQueuePlayer 類瘸羡,表示播放隊(duì)列中的下一個(gè) item
  2. AVPlayerActionAtItemEndPause 表示暫停
  3. AVPlayerActionAtItemEndNone 表示無操作,當(dāng)前 item 的 currentTime 屬性值仍然按 rate 的值改變
    item 的 currentTime 屬性值表示當(dāng)前 item 的播放時(shí)間搓茬,可以調(diào)用下面的方法指定 item 從何處進(jìn)行播放犹赖。
//第二個(gè)方法能夠進(jìn)行更準(zhǔn)確的跳轉(zhuǎn),但是需要進(jìn)行額外的計(jì)算
- (void)seekToDate:(NSDate *)date;
- (void)seekToTime:(CMTime)time toleranceBefore:(CMTime)toleranceBefore toleranceAfter:(CMTime)toleranceAfter; (tolerance: 公差卷仑,前后公差)

//這兩個(gè)方法傳入了一個(gè)回調(diào)峻村,當(dāng)一個(gè)時(shí)間跳轉(zhuǎn)請(qǐng)求被新的請(qǐng)求或其他操作打斷時(shí),回調(diào)也會(huì)被執(zhí)行但是此時(shí) finished 參數(shù)值為 NO
- (void)seekToTime:(CMTime)time completionHandler:(void (^)(BOOL finished))completionHandler NS_AVAILABLE(10_7, 5_0);
- (void)seekToTime:(CMTime)time toleranceBefore:(CMTime)toleranceBefore toleranceAfter:(CMTime)toleranceAfter completionHandler:(void (^)(BOOL finished))completionHandler NS_AVAILABLE(10_7, 5_0);
  • 使用 AVQueuePlayer 管理多個(gè) item 的播放锡凝,仍然可以通過調(diào)用 play 開始依次播放 item粘昨,調(diào)用 advanceToNextItem 方法播放下一個(gè) item ,還可以通過下面的方法添加或移除 item 窜锯。
- (BOOL)canInsertItem:(AVPlayerItem *)item afterItem:(nullable AVPlayerItem *)afterItem;
- (void)insertItem:(AVPlayerItem *)item afterItem:(nullable AVPlayerItem *)afterItem;
- (void)removeItem:(AVPlayerItem *)item;
- (void)removeAllItems;
  • 可以使用下面的方法監(jiān)聽播放時(shí)間的變化张肾,需要強(qiáng)引用這兩個(gè)方法返回的監(jiān)聽者。
- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(nullable dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;
- (id)addBoundaryTimeObserverForTimes:(NSArray<NSValue *> *)times queue:(nullable dispatch_queue_t)queue usingBlock:(void (^)(void))block;
  • 用上面的方法每注冊(cè)一個(gè)監(jiān)聽者锚扎,就需要對(duì)應(yīng)的使用下面的方法進(jìn)行注銷吞瞪,并且在注銷之前,要確保沒有 block 被執(zhí)行驾孔。- (void)removeTimeObserver:(id)observer;
  • 當(dāng) item 播放結(jié)束后芍秆,再次調(diào)用 player 的方法 play 不會(huì)使 item 重新播放,要實(shí)現(xiàn)重播助币,可以注冊(cè)一個(gè) AVPlayerItemDidPlayToEndTimeNotification 通知浪听,當(dāng)接收到這個(gè)通知時(shí),可以調(diào) seekToTime: 方法眉菱,傳入 kCMTimeZero 參數(shù)迹栓,將 player 的播放時(shí)間重置。

1.3.4 自定義播放--音頻

  • 要在媒體資源播放的過程中實(shí)現(xiàn)音頻的自定義播放俭缓,需要用 AVMutableAudioMix 對(duì)不同的音頻進(jìn)行編輯克伊。這個(gè)類的實(shí)例對(duì)象的屬性 inputParameters 是音量描述對(duì)象的集合酥郭,每個(gè)對(duì)象都是對(duì)一個(gè) audio track 的音量變化的描述,如下:
AVMutableAudioMix *mutableAudioMix = [AVMutableAudioMix audioMix];

AVMutableAudioMixInputParameters *mixParameters1 = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:compositionAudioTrack1];
[mixParameters1 setVolumeRampFromStartVolume:1.f toEndVolume:0.f timeRange:CMTimeRangeMake(kCMTimeZero, mutableComposition.duration/2)];
[mixParameters1 setVolumeRampFromStartVolume:0.f toEndVolume:1.f timeRange:CMTimeRangeMake(mutableComposition.duration/2, mutableComposition.duration)];

AVMutableAudioMixInputParameters *mixParameters2 = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:compositionAudioTrack2];
[mixParameters2 setVolumeRampFromStartVolume:1.f toEndVolume:0.f timeRange:CMTimeRangeMake(kCMTimeZero, mutableComposition.duration)];

mutableAudioMix.inputParameters = @[mixParameters1, mixParameters2];

1.3.4.1 AVAudioMix

  • 該類中有一個(gè)屬性 inputParameters 愿吹,它是 AVAudioMixInputParameters 實(shí)例對(duì)象的集合不从,每個(gè)實(shí)例都是對(duì)音頻播放方式的描述±绻颍可見椿息,AVAudioMix 并不直接改變音頻播放的方式,其只是存儲(chǔ)了音頻播放的方式坷衍。

1.3.4.2 AVMutableAudioMix

  • AVMutableAudioMixAVAudioMix 的子類寝优,它的方法 audioMix 返回一個(gè) inputParameters 屬性為空的實(shí)例。

1.3.4.3 AVAudioMixInputParameters

  • 這個(gè)類是音量變化的描述類枫耳,它同一個(gè)音頻的 track 相關(guān)聯(lián)乏矾,并設(shè)置音量隨時(shí)間變化的算法,其獲取音量變化的方法如下:
//獲取的音量變化范圍 timeRange 應(yīng)包含指定的時(shí)刻 time 否則最終返回 NO
//startVolume 獲取音量開始變化時(shí)的初始音量
//endVolume 獲取音量變化結(jié)束時(shí)的音量
//timeRang 是實(shí)際音量變化的范圍迁杨,它應(yīng)該包含指定的 time
- (BOOL)getVolumeRampForTime:(CMTime)time startVolume:(nullable float *)startVolume endVolume:(nullable float *)endVolume timeRange:(nullable CMTimeRange *)timeRange;

1.3.4.4 AVMutableAudioMixInputParameters

  • AVMutableAudioMixInputParameters 是 AVAudioMixInputParameters 的子類钻心,它提供了直接設(shè)置某個(gè)時(shí)刻或時(shí)間段的音量的方法。
//根據(jù)提供的 track 創(chuàng)建一個(gè)實(shí)例铅协,此時(shí)的音量描述數(shù)據(jù)為空
+ (instancetype)audioMixInputParametersWithTrack:(nullable AVAssetTrack *)track;

//創(chuàng)建一個(gè)實(shí)例捷沸,此時(shí)的音量變化描述是空的,且 trackID 為 kCMPersistentTrackID_Invalid
+ (instancetype)audioMixInputParameters;

//設(shè)置某個(gè)時(shí)間范圍內(nèi)的初始音量及結(jié)束音量
- (void)setVolumeRampFromStartVolume:(float)startVolume toEndVolume:(float)endVolume timeRange:(CMTimeRange)timeRange;

//設(shè)置某個(gè)時(shí)刻的音量
- (void)setVolume:(float)volume atTime:(CMTime)time;

1.3.5 自定義播放--視頻

  • 同音頻的自定義播放一樣警医,要實(shí)現(xiàn)視頻的自定義播放亿胸,僅僅將視頻資源集合到一起是不夠的,需要使用 AVMutableVideoComposition 類來定義不同的視頻資源在不同的時(shí)間范圍內(nèi)的播放方式预皇。

1.3.5.1 AVVideoComposition

  • AVVideoComposition 是 AVMutableVideoComposition 的父類侈玄,它的主要屬性和方法如下:
//該類的構(gòu)造類,提供自定義的構(gòu)造類時(shí)吟温,提供的類要遵守 AVVideoCompositing 協(xié)議
@property (nonatomic, readonly, nullable) Class<AVVideoCompositing> customVideoCompositorClass NS_AVAILABLE(10_9, 7_0);

//視頻每一幀的刷新時(shí)間
@property (nonatomic, readonly) CMTime frameDuration;

//視頻顯示時(shí)的大小范圍
@property (nonatomic, readonly) CGSize renderSize;

//視頻顯示范圍大小的縮放比例(僅僅對(duì) iOS 有效)
@property (nonatomic, readonly) float renderScale;

//描述視頻集合中具體視頻播放方式信息的集合序仙,其是遵循 AVVideoCompositionInstruction 協(xié)議的類實(shí)例對(duì)象
//這些視頻播放信息構(gòu)成一個(gè)完整的時(shí)間線,不能重疊鲁豪,不能間斷潘悼,并且在數(shù)組中的順序即為相應(yīng)視頻的播放順序
@property (nonatomic, readonly, copy) NSArray<id <AVVideoCompositionInstruction>> *instructions;

//用于組合視頻幀與動(dòng)態(tài)圖層的 Core Animation 的工具對(duì)象,可以為 nil 
@property (nonatomic, readonly, retain, nullable) AVVideoCompositionCoreAnimationTool *animationTool;

//直接使用一個(gè) asset 創(chuàng)建一個(gè)實(shí)例爬橡,創(chuàng)建的實(shí)例的各個(gè)屬性會(huì)根據(jù) asset 中的所有的 video tracks 的屬性進(jìn)行計(jì)算并適配治唤,所以在調(diào)用該方法之前,確保 asset 中的屬性已經(jīng)加載
//返回的實(shí)例對(duì)象的屬性 instructions 中的對(duì)象會(huì)對(duì)應(yīng)每個(gè) asset 中的 track 中屬性要求
//返回的實(shí)例對(duì)象的屬性 frameDuration 的值是 asset 中 所有 track 的 nominalFrameRate 屬性值最大的糙申,如果這些值都為 0 宾添,默認(rèn)為 30fps
//返回的實(shí)例對(duì)象的屬性 renderSize 的值是 asset 的 naturalSize 屬性值,如果 asset 是 AVComposition 類的實(shí)例。否則缕陕,renderSize 的值將包含每個(gè) track 的 naturalSize 屬性值
+ (AVVideoComposition *)videoCompositionWithPropertiesOfAsset:(AVAsset *)asset NS_AVAILABLE(10_9, 6_0);

//這三個(gè)屬性設(shè)置了渲染幀時(shí)的顏色空間粱锐、矩陣、顏色轉(zhuǎn)換函數(shù)扛邑,可能的值都在 AVVideoSetting.h 文件中定義
@property (nonatomic, readonly, nullable) NSString *colorPrimaries NS_AVAILABLE(10_12, 10_0);
@property (nonatomic, readonly, nullable) NSString *colorYCbCrMatrix NS_AVAILABLE(10_12, 10_0);
@property (nonatomic, readonly, nullable) NSString *colorTransferFunction NS_AVAILABLE(10_12, 10_0);

//該方法返回一個(gè)實(shí)例怜浅,它指定的 block 會(huì)對(duì) asset 中每一個(gè)有效的 track 的每一幀進(jìn)行渲染得到 CIImage 實(shí)例對(duì)象
//在 block 中進(jìn)行每一幀的渲染,成功后應(yīng)調(diào)用 request 的方法 finishWithImage:context: 并將得到的 CIImage 對(duì)象作為參數(shù)
//若是渲染失敗蔬崩,則應(yīng)調(diào)用 finishWithError: 方法并傳遞錯(cuò)誤信息

+ (AVVideoComposition *)videoCompositionWithAsset:(AVAsset *)asset
             applyingCIFiltersWithHandler:(void (^)(AVAsynchronousCIImageFilteringRequest *request))applier NS_AVAILABLE(10_11, 9_0);

1.3.5.2 AVMutableVideoComposition

  • AVMutableVideoComposition 是 AVVideoComposition 的可變子類恶座,它繼承父類的屬性可以改變,并且新增了下面的創(chuàng)建方法舱殿。
//這個(gè)方法創(chuàng)建的實(shí)例對(duì)象的屬性的值都是 nil 或 0奥裸,但是它的屬性都是可以進(jìn)行修改的
+ (AVMutableVideoComposition *)videoComposition;

1.3.5.3 AVVideoCompositionInstruction

  • 在上述的兩個(gè)類中,真正包含有視頻播放方式信息的是 instructions 屬性沪袭,這個(gè)集合中的對(duì)象都遵循 AVVideoCompositionInstruction 協(xié)議,若不使用自定義的類樟氢,那么可以使用 AVFoundation 框架中的 AVVideoCompositionInstruction 類冈绊。
  • 該類的相關(guān)屬性如下:
//表示該 instruction 生效的時(shí)間范圍
@property (nonatomic, readonly) CMTimeRange timeRange;

//指定當(dāng)前時(shí)間段的 composition 的背景色
//如果沒有指定,那么使用默認(rèn)的黑色
//如果渲染的像素沒有透明度通道埠啃,那么這個(gè)顏色也會(huì)忽略透明度
@property (nonatomic, readonly, retain, nullable) __attribute__((NSObject)) CGColorRef backgroundColor;

//AVVideoCompositionLayerInstruction 類實(shí)例對(duì)象的集合死宣,描述各個(gè)視頻資源幀的層級(jí)及組合關(guān)系
//按這個(gè)數(shù)組的順序,第一個(gè)顯示在第一層碴开,第二個(gè)在第一層下面顯示毅该,以此類推
@property (nonatomic, readonly, copy) NSArray<AVVideoCompositionLayerInstruction *> *layerInstructions;

//表明該時(shí)間段的視頻幀是否需要后期處理
//若為 NO,后期圖層的處理將跳過該時(shí)間段潦牛,這樣能夠提高效率
//為 YES 則按默認(rèn)操作處理(參考 AVVideoCompositionCoreAnimationTool 類)
@property (nonatomic, readonly) BOOL enablePostProcessing;

//當(dāng)前 instruction 中需要進(jìn)行幀組合的所有的 track ID 的集合眶掌,由屬性 layerInstructions 計(jì)算得到
@property (nonatomic, readonly) NSArray<NSValue *> *requiredSourceTrackIDs NS_AVAILABLE(10_9, 7_0);

//如果當(dāng)前的 instruction 在該時(shí)間段內(nèi)的視頻幀組合后,實(shí)質(zhì)得到的是某個(gè)源視頻的幀巴碗,那么就返回這個(gè)視頻資源的 ID
@property (nonatomic, readonly) CMPersistentTrackID passthroughTrackID NS_AVAILABLE(10_9, 7_0); 

1.3.5.4 AVMutableVideoCompositionInstruction

  • AVMutableVideoCompositionInstruction 是 AVVideoCompositionInstruction 的子類朴爬,其繼承的父類的屬性可進(jìn)行修改,并且提供了創(chuàng)建屬性值為 nil 或無效的實(shí)例的方法橡淆。
+ (instancetype)videoCompositionInstruction;

1.3.5.5 AVVideoCompositionLayerInstruction

  • AVVideoCompositionLayerInstruction 是對(duì)給定的視頻資源的不同播放方式進(jìn)行描述的類召噩,通過下面的方法,可以獲取仿射變化逸爵、透明度變化具滴、裁剪區(qū)域變化的梯度信息。
//獲取包含指定時(shí)間的仿射變化梯度信息
//startTransform师倔、endTransform 用來接收變化過程的起始值與結(jié)束值
//timeRange 用來接收變化的持續(xù)時(shí)間范圍
//返回值表示指定的時(shí)間 time 是否在變化時(shí)間 timeRange 內(nèi)
- (BOOL)getTransformRampForTime:(CMTime)time startTransform:(nullable CGAffineTransform *)startTransform endTransform:(nullable CGAffineTransform *)endTransform timeRange:(nullable CMTimeRange *)timeRange;

//獲取包含指定時(shí)間的透明度變化梯度信息
//startOpacity构韵、endOpacity 用來接收透明度變化過程的起始值與結(jié)束值
//timeRange 用來接收變化的持續(xù)時(shí)間范圍
//返回值表示指定的時(shí)間 time 是否在變化時(shí)間 timeRange 內(nèi)
- (BOOL)getOpacityRampForTime:(CMTime)time startOpacity:(nullable float *)startOpacity endOpacity:(nullable float *)endOpacity timeRange:(nullable CMTimeRange *)timeRange;

//獲取包含指定時(shí)間的裁剪區(qū)域的變化梯度信息
//startCropRectangle、endCropRectangle 用來接收變化過程的起始值與結(jié)束值
//timeRange 用來接收變化的持續(xù)時(shí)間范圍
//返回值表示指定的時(shí)間 time 是否在變化時(shí)間 timeRange 內(nèi)
- (BOOL)getCropRectangleRampForTime:(CMTime)time startCropRectangle:(nullable CGRect *)startCropRectangle endCropRectangle:(nullable CGRect *)endCropRectangle timeRange:(nullable CMTimeRange *)timeRange NS_AVAILABLE(10_9, 7_0);

1.3.5.6 AVMutableVideoCompositionLayerInstruction

  • AVMutableVideoCompositionLayerInstruction 是 AVVideoCompositionLayerInstruction 的子類,它可以改變 composition 中的 track 資源播放時(shí)的仿射變化贞绳、裁剪區(qū)域谷醉、透明度等信息。

  • 相比于父類冈闭,該子類還提供了創(chuàng)建實(shí)例的方法:

//這兩個(gè)方法的區(qū)別在于俱尼,前者返回的實(shí)例對(duì)象的屬性 trackID 的值是 track 的 trackID 值
//而第二個(gè)方法的返回的實(shí)例對(duì)象的屬性 trackID 的值為 kCMPersistentTrackID_Invalid
+ (instancetype)videoCompositionLayerInstructionWithAssetTrack:(AVAssetTrack *)track;
+ (instancetype)videoCompositionLayerInstruction;

  • 該類的屬性表示 instruction 所作用的 track 的 ID:
@property (nonatomic, assign) CMPersistentTrackID trackID;
  • 設(shè)置了 trackID 后,通過下面的方法萎攒,進(jìn)行剃度信息的設(shè)置:
//設(shè)置視頻中幀的仿射變化信息
//指定了變化的時(shí)間范圍遇八、起始值和結(jié)束值,其中坐標(biāo)系的原點(diǎn)為左上角耍休,向下向右為正方向
- (void)setTransformRampFromStartTransform:(CGAffineTransform)startTransform toEndTransform:(CGAffineTransform)endTransform timeRange:(CMTimeRange)timeRange;

//設(shè)置 instruction 的 timeRange 范圍內(nèi)指定時(shí)間的仿射變換刃永,該值會(huì)一直保持,直到被再次設(shè)置
- (void)setTransform:(CGAffineTransform)transform atTime:(CMTime)time;

//設(shè)置透明度的梯度信息羊精,提供的透明度初始值和結(jié)束值應(yīng)在0~1之間
//變化的過程是線形的
- (void)setOpacityRampFromStartOpacity:(float)startOpacity toEndOpacity:(float)endOpacity timeRange:(CMTimeRange)timeRange;

//設(shè)置指定時(shí)間的透明度斯够,該透明度會(huì)一直持續(xù)到下一個(gè)值被設(shè)置
- (void)setOpacity:(float)opacity atTime:(CMTime)time;

//設(shè)置裁剪矩形的變化信息
- (void)setCropRectangleRampFromStartCropRectangle:(CGRect)startCropRectangle toEndCropRectangle:(CGRect)endCropRectangle timeRange:(CMTimeRange)timeRange NS_AVAILABLE(10_9, 7_0);

//設(shè)置指定時(shí)間的裁剪矩形
- (void)setCropRectangle:(CGRect)cropRectangle atTime:(CMTime)time NS_AVAILABLE(10_9, 7_0);

1.3.5.7 AVVideoCompositionCoreAnimationTool

  • 在自定義視頻播放時(shí),可能需要添加水印喧锦、標(biāo)題或者其他的動(dòng)畫效果读规,需要使用該類。該類通常用來協(xié)調(diào)離線視頻中圖層與動(dòng)畫圖層的組合(如使用 AVAssetExportSessionAVAssetReader 燃少、AVAssetReader 類導(dǎo)出視頻文件或讀取視頻文件時(shí))束亏,而若是在線實(shí)時(shí)的視頻播放,應(yīng)使用 AVSynchronizedLayer 類來同步視頻的播放與動(dòng)畫的效果阵具。

  • 在使用該類時(shí)碍遍,注意動(dòng)畫在整個(gè)視頻的時(shí)間線上均可以被修改,所以阳液,動(dòng)畫的開始時(shí)間應(yīng)該設(shè)置為 AVCoreAnimationBeginTimeAtZero 怕敬,這個(gè)值其實(shí)比 0 大,屬性值 removedOnCompletion 應(yīng)該置為 NO趁舀,以防當(dāng)動(dòng)畫執(zhí)行結(jié)束后被移除赖捌,并且不應(yīng)使用與任何的 UIView 相關(guān)聯(lián)的圖層。

  • 作為視頻組合的后期處理工具類矮烹,主要方法如下:

//向視頻組合中添加一個(gè)動(dòng)畫圖層越庇,這個(gè)圖層不能在任何圖層樹中
//提供的參數(shù) trackID 應(yīng)由方法 [AVAsset unusedTrackID] 得到,它不與任何視頻資源的 trackID 相關(guān)
//AVVideoCompositionInstruction 的屬性 layerInstructions 包含的 AVVideoCompositionLayerInstruction 實(shí)例對(duì)象中應(yīng)該有
//該 trackID 一致的 AVVideoCompositionLayerInstruction 實(shí)例對(duì)象奉狈,并且為性能考慮卤唉,不應(yīng)使用該對(duì)象設(shè)置 transform 的變化
//在 iOS 中,CALayer 作為 UIView 的背景圖層仁期,其內(nèi)容的是否能夠翻轉(zhuǎn)桑驱,由方法 contentsAreFlipped 決定(如果所有的圖層包括子圖層竭恬,該方法返回的值為 YES 的個(gè)數(shù)為奇數(shù)個(gè),表示可以圖層中內(nèi)容可以垂直翻轉(zhuǎn))
//所以這里的 layer 若用來設(shè)置 UIView 的 layer 屬性熬的,或作為其中的子圖層痊硕,其屬性值 geometryFlipped 應(yīng)設(shè)置為 YES ,這樣則能夠保持是否能夠翻轉(zhuǎn)的結(jié)果一致
+ (instancetype)videoCompositionCoreAnimationToolWithAdditionalLayer:(CALayer *)layer asTrackID:(CMPersistentTrackID)trackID;

//將放在圖層 videoLayer 中的組合視頻幀同動(dòng)畫圖層 animationLayer 中的內(nèi)容一起進(jìn)行渲染押框,得到最終的視頻幀
//通常岔绸,videoLayer 是 animationLayer 的子圖層,而 animationLayer 則不在任何圖層樹中
+ (instancetype)videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:(CALayer *)videoLayer inLayer:(CALayer *)animationLayer;

//復(fù)制 videoLayers 中的每一個(gè)圖層橡伞,與 animationLayer一起渲染得到最中的幀
////通常盒揉,videoLayers 中的圖層都在 animationLayer 的圖層樹中,而 animationLayer 則不屬于任何圖層樹
+ (instancetype)videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayers:(NSArray<CALayer *> *)videoLayers inLayer:(CALayer *)animationLayer NS_AVAILABLE(10_9, 7_0);

1.3.5.8 AVVideoCompositionValidationHandling

  • 當(dāng)我們經(jīng)過編輯后得到一個(gè)視頻資源 asset 兑徘,并且為該資源設(shè)置了自定義播放信息 video composition 刚盈,需要驗(yàn)證對(duì)于這個(gè) asset 而言,video composition 是否有效挂脑,可以調(diào)用 AVVideoComposition 的校驗(yàn)方法藕漱。
/*
@param asset 
設(shè)置第一個(gè)參數(shù)的校驗(yàn)內(nèi)容,設(shè)置 nil 忽略這些校驗(yàn)
1. 該方法可以校驗(yàn) AVVideoComposition 的屬性 instructions 是否符合要求
2. 校驗(yàn) instructions 中的每個(gè) AVVideoCompositionInstruction 對(duì)象的 layerInstructions 屬性中的
每一個(gè) AVVideoCompositionLayerInstruction 對(duì)象 trackID 值是否對(duì)應(yīng) asset 中 track 的 ID 
或 AVVideoComposition 的 animationTool 實(shí)例
3. 校驗(yàn)時(shí)間 asset 的時(shí)長是否與 instructions 中的時(shí)間范圍相悖

@param timeRange 
設(shè)置第二個(gè)參數(shù)的校驗(yàn)內(nèi)容
1. 校驗(yàn) instructions 的所有的時(shí)間范圍是否在提供的 timeRange 的范圍內(nèi),
若要忽略該校驗(yàn),可以傳參數(shù) CMTimeRangeMake(kCMTimeZero, kCMTimePositiveInfinity)

@param validationDelegate 
設(shè)置遵循 AVVideoCompositionValidationHandling 協(xié)議的代理類箫柳,用來處理校驗(yàn)過程中的報(bào)錯(cuò)苍碟,可以為 nil 
*/
- (BOOL)isValidForAsset:(nullable AVAsset *)asset timeRange:(CMTimeRange)timeRange validationDelegate:(nullable id<AVVideoCompositionValidationHandling>)validationDelegate NS_AVAILABLE(10_8, 5_0);
  • 設(shè)置的代理對(duì)象要遵循協(xié)議 AVVideoCompositionValidationHandling ,該對(duì)象在實(shí)現(xiàn)下面的協(xié)議方法時(shí)忘伞,若修改了傳遞的 composition 參數(shù)薄翅,上面的校驗(yàn)方法則會(huì)拋出異常。

  • 該協(xié)議提供了以下回調(diào)方法氓奈,所有方法的返回值用來確定是否繼續(xù)進(jìn)行校驗(yàn)以獲取更多的錯(cuò)誤翘魄。

//報(bào)告 videoComposition 中有無效的值
- (BOOL)videoComposition:(AVVideoComposition *)videoComposition shouldContinueValidatingAfterFindingInvalidValueForKey:(NSString *)key NS_AVAILABLE(10_8, 5_0);

//報(bào)告 videoComposition 中有時(shí)間段沒有相對(duì)應(yīng)的 instruction
- (BOOL)videoComposition:(AVVideoComposition *)videoComposition shouldContinueValidatingAfterFindingEmptyTimeRange:(CMTimeRange)timeRange NS_AVAILABLE(10_8, 5_0);

//報(bào)告 videoComposition 中的 instructions 中 timeRange 無效的實(shí)例對(duì)象
//可能是 timeRange 本身為 CMTIMERANGE_IS_INVALID 
//或者是該時(shí)間段同上一個(gè)的 instruction 的 timeRange 重疊
//也可能是其開始時(shí)間比上一個(gè)的 instruction 的 timeRange 的開始時(shí)間要早
- (BOOL)videoComposition:(AVVideoComposition *)videoComposition shouldContinueValidatingAfterFindingInvalidTimeRangeInInstruction:(id<AVVideoCompositionInstruction>)videoCompositionInstruction NS_AVAILABLE(10_8, 5_0);

//報(bào)告 videoComposition 中的 layer instruction 同調(diào)用校驗(yàn)方法時(shí)指定的 asset 中 track 的 trackID 不一致
//也不與 composition 使用的 animationTool 的trackID 一致
- (BOOL)videoComposition:(AVVideoComposition *)videoComposition shouldContinueValidatingAfterFindingInvalidTrackIDInInstruction:(id<AVVideoCompositionInstruction>)videoCompositionInstruction layerInstruction:(AVVideoCompositionLayerInstruction *)layerInstruction asset:(AVAsset *)asset NS_AVAILABLE(10_8, 5_0);

1.3.5.9 AVVideoCompositionValidationHandling

1.4 AVFoundation 之 視音頻編輯

AVFoundation 編輯視頻1
AVFoundation 編輯視2
  • 詳情可以參考蘋果官方文檔:Editing章節(jié)
  • AVFoundation使用組合從現(xiàn)有的媒體片段(通常是一個(gè)或多個(gè)視頻和音頻軌道)創(chuàng)建新資產(chǎn)。您可以使用可變組合來添加和刪除軌跡舀奶,并調(diào)整它們的時(shí)間順序暑竟。你也可以設(shè)置音軌的相對(duì)音量和傾斜;設(shè)置視頻軌跡的不透明度和不透明度坡道。合成是存儲(chǔ)在內(nèi)存中的媒體片段的集合育勺。當(dāng)您使用導(dǎo)出會(huì)話導(dǎo)出一個(gè)組合時(shí)但荤,它會(huì)折疊成一個(gè)文件。您還可以使用資產(chǎn)寫入器從媒體(例如示例緩沖區(qū)或靜態(tài)圖像)創(chuàng)建資產(chǎn)涧至。
  • AVFoundation 框架中提供了豐富的接口用于視聽資源的編輯腹躁,其中的關(guān)鍵是 composition ,它將不同的 asset 相結(jié)合并形成一個(gè)新的 asset 南蓬。使用 AVMutableComposition 類可以增刪 asset 來將指定的 asset 集合到一起纺非。除此之外哑了,若想將集合到一起的視聽資源以自定義的方式進(jìn)行播放,需要使用 AVMutableAudioMixAVMutableVideoComposition類對(duì)其中的資源進(jìn)行協(xié)調(diào)管理烧颖。最終要使用 AVAssetExportSession 類將編輯的內(nèi)容保存到文件中弱左。
  • AVFoundation框架提供了一組功能豐富的類,以方便編輯視聽資產(chǎn)炕淮。AVFoundation編輯API的核心是復(fù)合拆火。組合就是來自一個(gè)或多個(gè)不同媒體資產(chǎn)的音軌集合。AVMutableComposition類提供了一個(gè)接口鳖悠,用于插入和刪除軌跡榜掌,以及管理它們的時(shí)間順序。圖3-1顯示了如何將現(xiàn)有資產(chǎn)組合拼湊成新資產(chǎn)乘综。如果您想做的只是將多個(gè)資產(chǎn)按順序合并到一個(gè)文件中憎账,那么這就是您所需要的全部細(xì)節(jié)。如果你想在你的作曲中對(duì)音軌進(jìn)行任何自定義音頻或視頻處理卡辰,你需要分別合并一個(gè)音頻混合或一個(gè)視頻合成胞皱。
將現(xiàn)有資產(chǎn)組合拼湊成新資產(chǎn)
  • 使用AVMutableAudioMix類,您可以在組合中的音頻軌道上執(zhí)行自定義音頻處理九妈,如圖3-2所示反砌。目前,您可以為音軌指定最大音量或設(shè)置音量斜坡萌朱。


    音頻混合
  • 您可以使用AVMutableVideoComposition類來直接編輯合成中的視頻軌跡宴树,如圖3-3所示。對(duì)于單個(gè)視頻合成晶疼,您可以為輸出視頻指定所需的渲染大小和比例以及幀持續(xù)時(shí)間酒贬。通過視頻合成的指令(由AVMutableVideoCompositionInstruction類表示),您可以修改視頻的背景顏色并應(yīng)用層指令翠霍。這些層指令(由AVMutableVideoCompositionLayerInstruction類表示)可用于對(duì)組合中的視頻軌道應(yīng)用轉(zhuǎn)換锭吨、轉(zhuǎn)換坡道、不透明度和不透明度坡道寒匙。video composition類還允許您使用animationTool屬性將核心動(dòng)畫框架的效果引入到視頻中零如。

視頻合成
  • 要將組合與音頻和視頻組合組合在一起,可以使用AVAssetExportSession對(duì)象锄弱,如圖3-4所示考蕾。使用組合初始化導(dǎo)出會(huì)話,然后分別將音頻混合和視頻組合分配給audioMixvideoComposition屬性棵癣。
音視頻組合

1.4.1 AVAssetExportSession

  • 使用 AVAssetExportSession 類對(duì)視頻進(jìn)行裁剪及轉(zhuǎn)碼辕翰,即將一個(gè) AVAsset 類實(shí)例修改后保存為另一個(gè) AVAsset 類實(shí)例,最后保存到文件中狈谊。
  • 在修改資源之前喜命,為避免不兼容帶來的錯(cuò)誤沟沙,可以先調(diào)用下面的方法,檢查預(yù)設(shè)置是否合理壁榕。
//獲取與 asset 兼容的預(yù)設(shè)置
+ (NSArray<NSString *> *)exportPresetsCompatibleWithAsset:(AVAsset *)asset;

//判斷提供的預(yù)設(shè)置和輸出的文件類型是否與 asset 相兼容
+ (void)determineCompatibilityOfExportPreset:(NSString *)presetName withAsset:(AVAsset *)asset outputFileType:(nullable NSString *)outputFileType completionHandler:(void (^)(BOOL compatible))handler NS_AVAILABLE(10_9, 6_0);
  • 除了設(shè)置文件類型外矛紫,還可以設(shè)置文件的大小、時(shí)長牌里、范圍等屬性颊咬,一切準(zhǔn)備就緒后,調(diào)用方法:- (void)exportAsynchronouslyWithCompletionHandler:(void (^)(void))handler;

  • 進(jìn)行文件的導(dǎo)出牡辽,導(dǎo)出結(jié)束后喳篇,會(huì)調(diào)用 handler 回調(diào),在回調(diào)中應(yīng)該檢查 AVAssetExportSession 的 status 屬性查看導(dǎo)出是否成功态辛,若指定的文件保存地址在沙盒外麸澜,或在導(dǎo)出的過程中有電話打入都會(huì)導(dǎo)致文件保存失敗,如下:

- (void)exportVideo:(NSURL *)url {
    AVAsset *anAsset = [AVAsset assetWithURL:url];

    [AVAssetExportSession determineCompatibilityOfExportPreset:AVAssetExportPresetHighestQuality
                                                     withAsset:anAsset
                                                outputFileType:AVFileTypeMPEG4
                                             completionHandler:^(BOOL compatible) {
        if (compatible){
            AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:anAsset
                                                                                   presetName:AVAssetExportPresetHighestQuality];

            exportSession.outputFileType = AVFileTypeMPEG4;

            CMTime start = CMTimeMakeWithSeconds(1.0, 600);
            CMTime duration = CMTimeMakeWithSeconds(3.0, 600);
            CMTimeRange range = CMTimeRangeMake(start, duration);
            exportSession.timeRange = range;
            [exportSession exportAsynchronouslyWithCompletionHandler:^{

                switch ([exportSession status]) {
                    case AVAssetExportSessionStatusCompleted:
                        NSLog(@"completed");
                        break;
                    case AVAssetExportSessionStatusFailed:
                        NSLog(@"failed");
                        break;
                    case AVAssetExportSessionStatusCancelled:
                        NSLog(@"canceled");
                        break;
                    default:
                        break;
                }
            }];
        }
    }];
}

1.4.2 AVComposition

  • AVAsset 擁有多個(gè) AVAssetTrack 一樣奏黑,作為子類的 AVComposition 也擁有多個(gè) AVCompositionTrack 炊邦,而 AVCompositionTrackAVAssetTrack 的子類。所以熟史,AVComposition 實(shí)例對(duì)象是多個(gè) track 的集合馁害,真正描述媒體屬性的是 AVCompositionTrack 實(shí)例對(duì)象。而 AVCompositionTrack 又是媒體數(shù)據(jù)片段的集合蹂匹,這些數(shù)據(jù)片段由 AVCompositionTrackSegment 類進(jìn)行描述碘菜。

  • 該類的相關(guān)屬性和方法如下:

//獲取 composition 中包含的 tracks
@property (nonatomic, readonly) NSArray<AVCompositionTrack *> *tracks;

//獲取 composition 中可視媒體資源播放時(shí)在屏幕上顯示的大小
@property (nonatomic, readonly) CGSize naturalSize;

//獲取 composition 生成 asset 時(shí)的指定配置
@property (nonatomic, readonly, copy) NSDictionary<NSString *, id> *URLAssetInitializationOptions NS_AVAILABLE(10_11, 9_0);

//根據(jù)不同的參數(shù),獲取 composition 中的 track
- (nullable AVCompositionTrack *)trackWithTrackID:(CMPersistentTrackID)trackID;
- (NSArray<AVCompositionTrack *> *)tracksWithMediaType:(NSString *)mediaType;
- (NSArray<AVCompositionTrack *> *)tracksWithMediaCharacteristic:(NSString *)mediaCharacteristic;
  • 值得注意的是 AVComposition 類中并沒有提供初始化方法限寞,一般我們使用它的子類 AVMutableComposition 炉媒,進(jìn)行各種操作后,再生成 AVComposition 實(shí)例以供查詢昆烁,如下:
AVMutableComposition *mutableComposition = [AVMutableComposition composition];

//進(jìn)行添加資源等操作
<#····#>

//使用可變的 composition 生成一個(gè)不可變的 composition 以供使用
AVComposition *composition = [myMutableComposition copy];
AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithAsset:composition];

1.4.3 AVMutableComposition

  • AVMutableCompositionAVComposition 的子類,其包含的 tracks 則是 AVCompositionTrack 的子類 AVMutableCompositionTrack 缎岗。
  • AVMutableComposition 中提供了兩個(gè)類方法用來獲取一個(gè)空的 AVMutableComposition 實(shí)例對(duì)象静尼。
+ (instancetype)composition;
+ (instancetype)compositionWithURLAssetInitializationOptions:(nullable NSDictionary<NSString *, id> *)URLAssetInitializationOptions NS_AVAILABLE(10_11, 9_0);
  • 對(duì)整個(gè) composition 中的 tracks 的修改方法如下:
//將指定時(shí)間段的 asset 中的所有的 tracks 添加到 composition 中 startTime 處
//該方法可能會(huì)在 composition 中添加新的 track 以便 asset 中 timeRange 范圍中的所有 tracks 都添加到 composition 中
- (BOOL)insertTimeRange:(CMTimeRange)timeRange ofAsset:(AVAsset *)asset atTime:(CMTime)startTime error:(NSError * _Nullable * _Nullable)outError;

//向 composition 中的所有 tracks 添加空的時(shí)間范圍
- (void)insertEmptyTimeRange:(CMTimeRange)timeRange;

//從 composition 的所有 tracks 中刪除一段時(shí)間,該操作不會(huì)刪除 track 传泊,而是會(huì)刪除與該時(shí)間段相交的 track segment
- (void)removeTimeRange:(CMTimeRange)timeRange;

//改變 composition 中的所有的 tracks 的指定時(shí)間范圍的時(shí)長鼠渺,該操作會(huì)改變 asset 的播放速度
- (void)scaleTimeRange:(CMTimeRange)timeRange toDuration:(CMTime)duration;
  • 從 composition 中獲取 track 或向其中添加/移除 track 方法如下:
//向 composition 中添加一個(gè)空的 track ,并且指定媒體資源類型及 trackID 屬性值
//若提供的參數(shù) preferredTrackID 無效或?yàn)?kCMPersistentTrackID_Invalid 眷细,那么唯一的 trackID 會(huì)自動(dòng)生成
- (AVMutableCompositionTrack *)addMutableTrackWithMediaType:(NSString *)mediaType preferredTrackID:(CMPersistentTrackID)preferredTrackID;

//從 composition 中刪除一個(gè)指定的 track
- (void)removeTrack:(AVCompositionTrack *)track;

//獲取一個(gè)與 asset track 相兼容的 composition track 
//為了更好的性能拦盹,composition track 的數(shù)量應(yīng)保持最小,這個(gè)數(shù)量與必需并行播放的媒體數(shù)據(jù)段數(shù)量以及媒體數(shù)據(jù)的類型相關(guān)
//對(duì)于能夠線性執(zhí)行且類型相同的媒體數(shù)據(jù)應(yīng)使用同一個(gè) composition track 溪椎,即使這些數(shù)據(jù)來自不同的 asset
- (nullable AVMutableCompositionTrack *)mutableTrackCompatibleWithTrack:(AVAssetTrack *)track;
  • AVMutableComposition 中也提供了過濾AVMutableCompositionTrack 的接口:
- (nullable AVMutableCompositionTrack *)trackWithTrackID:(CMPersistentTrackID)trackID;
- (NSArray<AVMutableCompositionTrack *> *)tracksWithMediaType:(NSString *)mediaType;
- (NSArray<AVMutableCompositionTrack *> *)tracksWithMediaCharacteristic:(NSString *)mediaCharacteristic;

1.4.4 AVCompositionTrack

  • AVCompositionTrack 類同其父類 AVAssetTrack 一樣是媒體資源的管理者普舆,它實(shí)際是媒體資源數(shù)據(jù)的集合恬口,它的屬性 segments 是 AVCompositionTrackSegment 類的實(shí)例對(duì)象集合,每個(gè)對(duì)象描述一個(gè)媒體數(shù)據(jù)片段沼侣。類 AVCompositionTrack 并不常用祖能,通常使用的是它的子類 AVMutableCompositionTrack

1.4.5 AVMutableCompositionTrack

  • AVMutableCompositionTrack 中提供的屬性如下:
//沒有外部數(shù)值指定時(shí)蛾洛,媒體1秒鐘時(shí)間的粒度
@property (nonatomic) CMTimeScale naturalTimeScale;

//當(dāng)前 track 相關(guān)聯(lián)的語言編碼
@property (nonatomic, copy, nullable) NSString *languageCode;

//當(dāng)前 track 相關(guān)聯(lián)的額外語言編碼
@property (nonatomic, copy, nullable) NSString *extendedLanguageTag;

//對(duì)于可顯示的媒體數(shù)據(jù)應(yīng)優(yōu)先選擇的仿射變換設(shè)置养铸,默認(rèn)值為 CGAffineTransformIdentity
@property (nonatomic) CGAffineTransform preferredTransform;

//應(yīng)優(yōu)先選擇的音量,默認(rèn)值為 1
@property (nonatomic) float preferredVolume;

//當(dāng)前track 所包含的所有的媒體數(shù)據(jù)片段轧膘,對(duì)于這些片段钞螟,它們構(gòu)成了 track 的完整時(shí)間線,
//所以他們的時(shí)間線不可以重疊谎碍,并且第一個(gè)數(shù)據(jù)片段的時(shí)間從 kCMTimeZero 開始鳞滨,依次往后的時(shí)間必須連續(xù)不間斷、不重疊
@property (nonatomic, copy, null_resettable) NSArray<AVCompositionTrackSegment *> *segments;
  • 當(dāng)我們獲取了一個(gè) AVMutableCompositionTrack 實(shí)例對(duì)象后椿浓,便可以通過以下方法對(duì)其進(jìn)行添加或移除數(shù)據(jù)片段:
//將已存在的資源文件指定時(shí)間范圍的媒體數(shù)據(jù)插入到當(dāng)前 composition 的指定時(shí)間處
//如果 startTime 為 kCMTimeInvalid 值太援,那么數(shù)據(jù)被添加到 composition 的最后
- (BOOL)insertTimeRange:(CMTimeRange)timeRange ofTrack:(AVAssetTrack *)track atTime:(CMTime)startTime error:(NSError * _Nullable * _Nullable)outError;

//這個(gè)方法與上述方法類似,只是可以批量操作扳碍,但是注意提供的時(shí)間范圍不能重疊
- (BOOL)insertTimeRanges:(NSArray<NSValue *> *)timeRanges ofTracks:(NSArray<AVAssetTrack *> *)tracks atTime:(CMTime)startTime error:(NSError * _Nullable * _Nullable)outError NS_AVAILABLE(10_8, 5_0);

//插入一個(gè)沒有媒體數(shù)據(jù)的時(shí)間段提岔,當(dāng)這個(gè)范圍之前的媒體資源播放結(jié)束后,不會(huì)立刻播放之后的媒體數(shù)據(jù)笋敞,而是會(huì)靜默一段時(shí)間
- (void)insertEmptyTimeRange:(CMTimeRange)timeRange;

//移除一段時(shí)間范圍的媒體數(shù)據(jù)碱蒙,該方法不會(huì)導(dǎo)致該 track 從 composition 中移除,只是移除與時(shí)間范圍相交的數(shù)據(jù)片段
- (void)removeTimeRange:(CMTimeRange)timeRange;

//改變某個(gè)時(shí)間范圍內(nèi)的時(shí)間的時(shí)長夯巷,實(shí)質(zhì)是改變了媒體數(shù)據(jù)的播放速率
//其速率是原時(shí)長與現(xiàn)時(shí)長的比值赛惩,總之,媒體數(shù)據(jù)是要按時(shí)長播放的
- (void)scaleTimeRange:(CMTimeRange)timeRange toDuration:(CMTime)duration;

//判斷數(shù)據(jù)片段的時(shí)間線是否重疊
- (BOOL)validateTrackSegments:(NSArray<AVCompositionTrackSegment *> *)trackSegments error:(NSError * _Nullable * _Nullable)outError;

1.4.6 AVAssetTrackSegment

  • 媒體資源 AVAsset 中的集合 AVAssetTrack 管理著單條時(shí)間線上的媒體數(shù)據(jù)片段趁餐,而每個(gè)數(shù)據(jù)片段則由 AVAssetTrackSegment 類進(jìn)行描述喷兼。
  • AVAssetTrackSegment 有兩個(gè)屬性:
  1. timeMapping 描述的是數(shù)據(jù)片段在整個(gè)媒體文件中所處的時(shí)間范圍.timeMapping 是一個(gè)結(jié)構(gòu)體,擁有兩個(gè)成員后雷,對(duì)于編輯中的媒體數(shù)據(jù)片段季惯,它們分別表示數(shù)據(jù)在源文件中的位置和目標(biāo)文件中的位置.
  2. empty 描述該數(shù)據(jù)片段是否為空,如果為空臀突,其 timeMapping.source.start 為 kCMTimeInvalid

1.4.7 AVCompositionTrackSegment

  • 在編輯媒體文件時(shí)勉抓,在描述數(shù)據(jù)時(shí),使用的是 AVAssetTrackSegment 的子類 AVCompositionTrackSegment 候学,它的主要屬性和方法如下:
//判斷數(shù)據(jù)片段是否為空藕筋,若為空 timeMapping.target 可為有效值,其他為未定義值
@property (nonatomic, readonly, getter=isEmpty) BOOL empty;

//片段數(shù)據(jù)所處的文件的地址
@property (nonatomic, readonly, nullable) NSURL *sourceURL;

//片段數(shù)據(jù)所處文件的描述 asset track 的 ID
@property (nonatomic, readonly) CMPersistentTrackID sourceTrackID;

//創(chuàng)建對(duì)象梳码,提供了數(shù)據(jù)片段所在的文件隐圾、文件的描述 asset track 的 ID 伍掀、源文件中的數(shù)據(jù)時(shí)間范圍、目標(biāo)文件中所處的時(shí)間范圍
//sourceTimeRange 與 targetTimeRange 的時(shí)間長度如果不一致翎承,那么播放的速率會(huì)改變
+ (instancetype)compositionTrackSegmentWithURL:(NSURL *)URL trackID:(CMPersistentTrackID)trackID sourceTimeRange:(CMTimeRange)sourceTimeRange targetTimeRange:(CMTimeRange)targetTimeRange;
- (instancetype)initWithURL:(NSURL *)URL trackID:(CMPersistentTrackID)trackID sourceTimeRange:(CMTimeRange)sourceTimeRange targetTimeRange:(CMTimeRange)targetTimeRange NS_DESIGNATED_INITIALIZER;

//創(chuàng)建僅有時(shí)間范圍而無實(shí)際媒體數(shù)據(jù)的實(shí)例
+ (instancetype)compositionTrackSegmentWithTimeRange:(CMTimeRange)timeRange;
- (instancetype)initWithTimeRange:(CMTimeRange)timeRange NS_DESIGNATED_INITIALIZER; 

1.5 AVFoundation 之 視音頻媒體捕獲

AVFoundation 媒體捕捉1
AVFoundation 媒體捕捉2
AVFoundation 媒體捕捉3
  • 攝像機(jī)和麥克風(fēng)的記錄輸入由捕獲會(huì)話管理硕盹。捕獲會(huì)話協(xié)調(diào)從輸入設(shè)備到輸出(如電影文件)的數(shù)據(jù)流。您可以為單個(gè)會(huì)話配置多個(gè)輸入和輸出叨咖,甚至在會(huì)話運(yùn)行時(shí)也是如此瘩例。向會(huì)話發(fā)送消息以啟動(dòng)和停止數(shù)據(jù)流。此外甸各,您可以使用預(yù)覽層的實(shí)例向用戶顯示攝像機(jī)正在錄制的內(nèi)容垛贤。

  • 更多關(guān)于視頻捕獲的詳情可以參考蘋果官方文檔:Still and Video Media Capture章節(jié)

  • 要管理來自攝像機(jī)或麥克風(fēng)等設(shè)備的捕獲,您需要組裝對(duì)象來表示輸入和輸出趣倾,并使用AVCaptureSession實(shí)例來協(xié)調(diào)它們之間的數(shù)據(jù)流聘惦。你需要最低限度:

  1. 表示輸入設(shè)備的AVCaptureDevice實(shí)例,如攝像機(jī)或麥克風(fēng)
  2. AVCaptureInput的一個(gè)具體子類的實(shí)例儒恋,用于配置來自輸入設(shè)備的端口
  3. AVCaptureOutput的一個(gè)具體子類的實(shí)例善绎,用于管理電影文件或靜態(tài)圖像的輸出
  4. AVCaptureSession的一個(gè)實(shí)例,用于協(xié)調(diào)從輸入到輸出的數(shù)據(jù)流
  • 要向用戶顯示攝像機(jī)記錄內(nèi)容的預(yù)覽诫尽,可以使用AVCaptureVideoPreviewLayer的一個(gè)實(shí)例(CALayer的一個(gè)子類)禀酱。

  • 您可以配置多個(gè)輸入和輸出,由單個(gè)會(huì)話進(jìn)行協(xié)調(diào)牧嫉,如圖4-1所示:


    配置多個(gè)輸入和輸出剂跟,由單個(gè)會(huì)話進(jìn)行協(xié)調(diào)
  • 對(duì)于許多應(yīng)用程序,這是您需要的盡可能多的細(xì)節(jié)酣藻。但是曹洽,對(duì)于某些操作(例如,如果希望監(jiān)視音頻通道中的功率級(jí)別)辽剧,需要考慮如何表示輸入設(shè)備的各個(gè)端口送淆,以及如何將這些端口連接到輸出。

  • 捕獲會(huì)話中的捕獲輸入和捕獲輸出之間的連接由AVCaptureConnection對(duì)象表示怕轿。捕獲輸入(AVCaptureInput的實(shí)例)有一個(gè)或多個(gè)輸入端口(AVCaptureInputPort的實(shí)例)坊夫。捕獲輸出(AVCaptureOutput的實(shí)例)可以接受來自一個(gè)或多個(gè)源的數(shù)據(jù)(例如,AVCaptureMovieFileOutput對(duì)象同時(shí)接受視頻和音頻數(shù)據(jù))撤卢。

  • 當(dāng)您將輸入或輸出添加到會(huì)話時(shí),會(huì)話將在所有兼容的捕獲輸入端口和捕獲輸出之間形成連接梧兼,如圖4-2所示放吩。捕獲輸入和捕獲輸出之間的連接由AVCaptureConnection對(duì)象表示。

AVCaptureConnection表示輸入和輸出之間的連接
  • 您可以使用捕獲連接來啟用或禁用來自給定輸入或到給定輸出的數(shù)據(jù)流羽杰。您還可以使用連接來監(jiān)視音頻通道中的平均和峰值功率級(jí)別渡紫。

  • 通過麥克風(fēng)到推、攝像機(jī)等設(shè)備,可以捕獲外界的聲音和影像惕澎。要處理設(shè)備捕獲的數(shù)據(jù)莉测,需要使用 AVCaptureDevice 類描述設(shè)備,使用 AVCaptureInput 配置數(shù)據(jù)從設(shè)備的輸入唧喉,使用 AVCaptureOutput 類管理數(shù)據(jù)到文件的寫入捣卤,而數(shù)據(jù)的輸入到寫出,需要使用 AVCaptureSession 類進(jìn)行協(xié)調(diào)八孝。此外董朝,可以使用 AVCaptureVideoPreviewLayer 類顯示相機(jī)正在拍攝的畫面。

  • 一個(gè)設(shè)備可以有多個(gè)輸入干跛,使用 AVCaptureInputPort 類描述這些輸入子姜,用 AVCaptureConnection 類描述具體類型的輸入與輸出的關(guān)系,可以實(shí)現(xiàn)更精細(xì)的數(shù)據(jù)處理楼入。

1.5.1 AVCaptureSession

  • `AVCaptureSession 是捕獲視聽數(shù)據(jù)的核心類哥捕,它協(xié)調(diào)數(shù)據(jù)的輸入和輸出。創(chuàng)建一個(gè) AVCaptureSession 類的對(duì)象時(shí)嘉熊,可以指定最終得到的視聽數(shù)據(jù)的質(zhì)量遥赚,當(dāng)然這個(gè)質(zhì)量與設(shè)備也有關(guān)系,通常在設(shè)置之前记舆,可以調(diào)用方法判斷 session 是否支持要設(shè)置的質(zhì)量鸽捻。

  • AVCaptureSession 類實(shí)例可設(shè)置的數(shù)據(jù)質(zhì)量有 AVCaptureSessionPresetHighAVCaptureSessionPresetMedium 泽腮、AVCaptureSessionPresetLow 御蒲、AVCaptureSessionPreset320x240 等。在進(jìn)行設(shè)置之前诊赊,可以調(diào)用 AVCaptureSession 中的方法進(jìn)行校驗(yàn)厚满。

- (BOOL)canSetSessionPreset:(NSString*)preset;
  • 設(shè)置好對(duì)象后,可調(diào)用下面的方法碧磅,添加碘箍、移除輸入、輸出鲸郊。
- (BOOL)canAddInput:(AVCaptureInput *)input;
- (void)addInput:(AVCaptureInput *)input;
- (void)removeInput:(AVCaptureInput *)input;

- (BOOL)canAddOutput:(AVCaptureOutput *)output;
- (void)addOutput:(AVCaptureOutput *)output;
- (void)removeOutput:(AVCaptureOutput *)output;

- (void)addInputWithNoConnections:(AVCaptureInput *)input NS_AVAILABLE(10_7, 8_0);
- (void)addOutputWithNoConnections:(AVCaptureOutput *)output NS_AVAILABLE(10_7, 8_0);

- (BOOL)canAddConnection:(AVCaptureConnection *)connection NS_AVAILABLE(10_7, 8_0);
- (void)addConnection:(AVCaptureConnection *)connection NS_AVAILABLE(10_7, 8_0);
- (void)removeConnection:(AVCaptureConnection *)connection NS_AVAILABLE(10_7, 8_0);
  • 開始執(zhí)行 session 或者結(jié)束執(zhí)行丰榴,調(diào)用下面的方法:
- (void)startRunning;
- (void)stopRunning;
  • 對(duì)于正在執(zhí)行中的 session ,要對(duì)其進(jìn)行改變秆撮,所作出的改變四濒,應(yīng)放在下面兩個(gè)方法之間。
- (void)beginConfiguration;
- (void)commitConfiguration;
  • AVCaptureSession 開始執(zhí)行、結(jié)束執(zhí)行盗蟆、執(zhí)行過程中出錯(cuò)或被打斷時(shí)戈二,都會(huì)發(fā)出通知,通過注冊(cè)下面的通知喳资,可以獲取我們感興趣的信息觉吭。
  1. VCaptureSessionRuntimeErrorNotification 通過 AVCaptureSessionErrorKey 可以獲取出錯(cuò)的原因
  2. AVCaptureSessionDidStartRunningNotification 開始 session
  3. AVCaptureSessionDidStopRunningNotification 結(jié)束 session
  4. AVCaptureSessionWasInterruptedNotification 通過 AVCaptureSessionInterruptionReasonKey 可以獲取被打斷的原因
  5. AVCaptureSessionInterruptionEndedNotification 打斷結(jié)束,session 重新開始

1.5.2 AVCaptureDevice

  • AVCaptureDevice是用來描述設(shè)備屬性的類仆邓,要捕獲視聽數(shù)據(jù)鲜滩,需要獲取相應(yīng)的設(shè)備,使用該類獲取有效的設(shè)備資源宏赘。這個(gè)設(shè)備資源列表是隨時(shí)變動(dòng)的绒北,其在變動(dòng)時(shí),會(huì)發(fā)送AVCaptureDeviceWasConnectedNotificationAVCaptureDeviceWasDisconnectedNotification 通知察署,以告知有設(shè)備連接或斷開闷游。

  • 在獲取設(shè)備之前,要先確定要獲取的設(shè)備的類型 AVCaptureDeviceType 贴汪,設(shè)備的位置 AVCaptureDevicePosition 脐往,也可以通過要獲取的媒體數(shù)據(jù)類型進(jìn)行設(shè)備的選擇。

  • 獲取設(shè)備后扳埂,可以保存它的唯一標(biāo)識(shí)业簿、模型標(biāo)識(shí)、名稱等信息阳懂,以待下次用來獲取設(shè)備梅尤。

+ (NSArray *)devices;
+ (NSArray *)devicesWithMediaType:(NSString *)mediaType;
+ (AVCaptureDevice *)defaultDeviceWithMediaType:(NSString *)mediaType;
+ (AVCaptureDevice *)deviceWithUniqueID:(NSString *)deviceUniqueID;

@property(nonatomic, readonly) NSString *uniqueID;
@property(nonatomic, readonly) NSString *modelID;
@property(nonatomic, readonly) NSString *localizedName;

//校驗(yàn)獲得的設(shè)備能否提供相應(yīng)的媒體數(shù)據(jù)類型
- (BOOL)hasMediaType:(NSString *)mediaType;

//校驗(yàn)獲得的設(shè)備能否支持相應(yīng)的配置
- (BOOL)supportsAVCaptureSessionPreset:(NSString *)preset;

  • 獲取一個(gè)設(shè)備后,可以通過修改它的屬性來滿足自己的需要岩调。
  1. flashMode 閃光燈的模式(AVCaptureFlashModeOff 巷燥、AVCaptureFlashModeOn 、AVCaptureFlashModeAuto)
  2. torchMode 手電筒的模式(AVCaptureTorchModeOff 号枕、AVCaptureTorchModeOn 缰揪、AVCaptureTorchModeAuto)
    torchLevel 手電筒的亮度(0~1)
  3. focusMode 聚焦模式(AVCaptureFocusModeLocked 、AVCaptureFocusModeAutoFocus 葱淳、AVCaptureFocusModeContinuousAutoFocus)
  4. exposureMode 曝光模式(AVCaptureExposureModeLocked 钝腺、AVCaptureExposureModeAutoExpose 、AVCaptureExposureModeContinuousAutoExposure 赞厕、AVCaptureExposureModeCustom)
  5. whiteBalanceMode 白平衡模式(AVCaptureWhiteBalanceModeLocked 艳狐、AVCaptureWhiteBalanceModeAutoWhiteBalance 、AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance)
  • 在修改這些屬性時(shí)皿桑,應(yīng)先判斷當(dāng)前設(shè)備是否支持要設(shè)置的屬性值毫目,并且所有的屬性修改都要放在下面兩個(gè)方法之間喷斋,以保證屬性能夠被正確設(shè)置。
- (BOOL)lockForConfiguration:(NSError **)outError;
- (void)unlockForConfiguration;
  • 在調(diào)用硬件設(shè)備之前蒜茴,應(yīng)先判斷應(yīng)用是否擁有相應(yīng)的權(quán)限,其權(quán)限分為以下幾種:
  1. AVAuthorizationStatusNotDetermined 未定義
  2. AVAuthorizationStatusRestricted 無權(quán)限(因某些原因浆西,系統(tǒng)拒絕權(quán)限)
  3. AVAuthorizationStatusDenied 無權(quán)限(用戶拒絕)
  4. AVAuthorizationStatusAuthorized 有權(quán)限
//校驗(yàn)權(quán)限
+ (AVAuthorizationStatus)authorizationStatusForMediaType:(NSString *)mediaType NS_AVAILABLE_IOS(7_0);

//請(qǐng)求權(quán)限粉私,handler 處理會(huì)在任意線程中執(zhí)行,所以需要在主線程中執(zhí)行的處理由用戶負(fù)責(zé)指定
+ (void)requestAccessForMediaType:(NSString *)mediaType completionHandler:(void (^)(BOOL granted))handler NS_AVAILABLE_IOS(7_0);

1.5.3 AVCaptureDeviceInput

  • AVCaptureDeviceInputAVCaptureInput 的子類近零,使用一個(gè) AVCaptureDevice 類實(shí)例創(chuàng)建該類的實(shí)例诺核,其管理設(shè)備的輸入。
  • 在創(chuàng)建了實(shí)例對(duì)象后久信,將其添加到 session 中窖杀。
NSError *error;
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (input && [session canAddInput:input]) {
    [captureSession addInput:captureDeviceInput];
}

1.5.4 AVCaptureOutput

  • AVCaptureOutput 是一個(gè)抽象類,通常使用的是它的子類
  1. AVCaptureMovieFileOutput 用來生成一個(gè)影視文件
  2. AVCaptureVideoDataOutput 用來處理輸入的視頻的幀
  3. AVCaptureAudioDataOutput 用來處理音頻數(shù)據(jù)
  4. AVCaptureStillImageOutput 用來獲取圖片
  • 在創(chuàng)建了具體的子類后裙士,將它添加到 session 中
AVCaptureMovieFileOutput *movieOutput = [[AVCaptureMovieFileOutput alloc] init];
if ([session canAddOutput:movieOutput]) {
    [session addOutput:movieOutput];
}

1.5.5 AVCaptureFileOutput

  • AVCaptureFileOutputAVCaptureOutput 的子類入客,是 AVCaptureMovieFileOutputAVCaptureAudioFileOutput 的父類腿椎。這個(gè)類中定義了文件輸出時(shí)的地址桌硫、時(shí)長、容量等屬性啃炸。
//當(dāng)前記錄的數(shù)據(jù)的文件的地址
@property(nonatomic, readonly) NSURL *outputFileURL;

//開始文件的記錄铆隘,指定文件的地址,以及記錄過程中或結(jié)束時(shí)要通知的代理對(duì)象
//指定的 outputFileURL 必需是有效的且沒有文件占用
- (void)startRecordingToOutputFileURL:(NSURL*)outputFileURL recordingDelegate:(id<AVCaptureFileOutputRecordingDelegate>)delegate;

//該方法可以停止數(shù)據(jù)向文件中寫入
//如果要停止一個(gè)文件的寫入轉(zhuǎn)而指定另一個(gè)文件的寫入南用,不應(yīng)調(diào)用該方法膀钠,只需直接調(diào)用上面的方法
//當(dāng)因該方法的調(diào)用、出錯(cuò)裹虫、或?qū)懭胛募淖兏鼘?dǎo)致當(dāng)前文件開始停止寫入時(shí)肿嘲,最后傳入的緩存數(shù)據(jù)仍會(huì)在后臺(tái)被寫入
//無論何時(shí),要使用文件恒界,都需要等指定的代理對(duì)象被告知文件的寫入已經(jīng)結(jié)束之后進(jìn)行
- (void)stopRecording;

//判斷當(dāng)前是否有數(shù)據(jù)被寫入文件
@property(nonatomic, readonly, getter=isRecording) BOOL recording;

//表示到目前為止睦刃,當(dāng)前文件已經(jīng)記錄了多長時(shí)間
@property(nonatomic, readonly) CMTime recordedDuration;

//表示到目前為止,當(dāng)前文件已經(jīng)記錄了多少個(gè)字節(jié)
@property(nonatomic, readonly) int64_t recordedFileSize;    
/**
下面三個(gè)值對(duì)文件的記錄進(jìn)行了限制十酣,若果達(dá)到限制涩拙,則會(huì)在回調(diào)方法 captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error: 中傳遞相應(yīng)的錯(cuò)誤
*/
//表示當(dāng)前文件能夠記錄的最長時(shí)間,kCMTimeInvalid 表示無時(shí)間限制
@property(nonatomic) CMTime maxRecordedDuration;

//表示當(dāng)前文件能夠記錄的最大字節(jié)數(shù)耸采,0 表示無大小限制
@property(nonatomic) int64_t maxRecordedFileSize;

//表示記錄當(dāng)前文件時(shí)需要保留的最小字節(jié)數(shù)
@property(nonatomic) int64_t minFreeDiskSpaceLimit;

//在 Mac OS X 系統(tǒng)下兴泥,通過指定遵循 AVCaptureFileOutputDelegate 協(xié)議的代理對(duì)象,來實(shí)現(xiàn)緩存數(shù)據(jù)的精確記錄
@property(nonatomic, assign) id<AVCaptureFileOutputDelegate> delegate NS_AVAILABLE(10_7, NA);

/**
在 Mac OS X 系統(tǒng)下,這個(gè)屬性和方法可以判斷記錄是否停止,以及控制數(shù)據(jù)向文件中的停止寫入和重新開始寫入
*/
@property(nonatomic, readonly, getter=isRecordingPaused) BOOL recordingPaused NS_AVAILABLE(10_7, NA);
- (void)pauseRecording NS_AVAILABLE(10_7, NA);
- (void)resumeRecording NS_AVAILABLE(10_7, NA);

1.5.6 AVCaptureFileOutputRecordingDelegate

  • AVCaptureFileOutputRecordingDelegate 是文件記錄過程中需要用到的協(xié)議咏雌,它通常的作用是告知代理對(duì)象文件記錄結(jié)束了祭阀。
//這個(gè)代理方法是遵循該協(xié)議的代理對(duì)象必須要實(shí)現(xiàn)的方法
//每一個(gè)文件記錄請(qǐng)求谜疤,最終都會(huì)調(diào)用這個(gè)方法转锈,即使沒有數(shù)據(jù)成功寫入文件
//當(dāng) error 返回時(shí)锐涯,文件也可能成功保存了凹耙,應(yīng)檢查 error 中的 AVErrorRecordingSuccessfullyFinishedKey 信息稀轨,查看具體錯(cuò)誤
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error;

//當(dāng)數(shù)據(jù)寫入文件后調(diào)用扼脐,如果數(shù)據(jù)寫入失敗,該方法可能不會(huì)被調(diào)用
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections;

/**
在 Mac OS X 系統(tǒng)下奋刽,當(dāng)文件的記錄被暫屯呶辏或重新開始,會(huì)調(diào)用下面的方法佣谐,如果記錄被終止肚吏,不會(huì)調(diào)用下面的方法
*/
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didPauseRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections NS_AVAILABLE(10_7, NA);
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didResumeRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections NS_AVAILABLE(10_7, NA);

//在 Mac OS X 系統(tǒng)下,當(dāng)記錄將被停止狭魂,無論是主動(dòng)的還是被動(dòng)的罚攀,都會(huì)調(diào)用下面的方法
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput willFinishRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections error:(NSError *)error NS_AVAILABLE(10_7, NA);

1.5.7 AVCaptureFileOutputDelegate

  • AVCaptureFileOutputDelegate 這個(gè)協(xié)議只用于 Mac OS X 系統(tǒng)下,它給了客戶端精準(zhǔn)操控?cái)?shù)據(jù)的機(jī)會(huì)趁蕊。
/**
在 Mac OS X 10.8 系統(tǒng)之前坞生,實(shí)現(xiàn)代理方法 captureOutput:didOutputSampleBuffer:fromConnection:
后便可以在該方法中實(shí)現(xiàn)數(shù)據(jù)記錄的準(zhǔn)確開始或結(jié)束,而要實(shí)現(xiàn)在任一一個(gè)畫面幀處開始或停止數(shù)據(jù)的記錄掷伙,要對(duì)每收到的
幀數(shù)據(jù)進(jìn)行預(yù)先處理是己,這個(gè)過程消耗電能、產(chǎn)生熱量任柜、占用 CPU 資源卒废,所以在 Mac OS X 10.8 及其之后的系統(tǒng),提供了
下面的代理方法宙地,來確定客戶端需不需要隨時(shí)進(jìn)行記錄的開始或停止摔认。
如果這個(gè)方法返回 NO ,對(duì)數(shù)據(jù)記錄的設(shè)置將在開啟記錄之后進(jìn)行宅粥。
*/
- (BOOL)captureOutputShouldProvideSampleAccurateRecordingStart:(AVCaptureOutput *)captureOutput NS_AVAILABLE(10_8, NA);

/**
如果上面的方法返回了 YES 参袱,那么客戶端便可以使用下面的方法對(duì)每一個(gè)視頻幀數(shù)據(jù)或音頻數(shù)據(jù)進(jìn)行操作
為了提高性能,緩存池中的緩存變量的內(nèi)存通常會(huì)被復(fù)用秽梅,如果長時(shí)間使用緩存變量抹蚀,那么新的緩存數(shù)據(jù)無法復(fù)制到
相應(yīng)的內(nèi)存中便會(huì)被廢棄,所以若需要長時(shí)間使用緩存數(shù)據(jù) sampleBuffer 企垦,應(yīng)復(fù)制一份环壤,使其本身能夠被系統(tǒng)復(fù)用
*/
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection NS_AVAILABLE(10_7, NA);

1.5.8 AVCaptureAudioFileOutput

  • AVCaptureAudioFileOutput 是 AVCaptureFileOutput 的子類,該類用于將媒體數(shù)據(jù)記錄為一個(gè)音頻文件钞诡。
//返回該類支持的音頻文件類型
+ (NSArray *)availableOutputFileTypes;

//開始記錄音頻文件
- (void)startRecordingToOutputFileURL:(NSURL*)outputFileURL outputFileType:(NSString *)fileType recordingDelegate:(id<AVCaptureFileOutputRecordingDelegate>)delegate;

//要寫入音頻文件中的元數(shù)據(jù) AVMetadataItem 集合
@property(nonatomic, copy) NSArray *metadata; 

//寫入的音頻文件的設(shè)置 AVAudioSettings.h
@property(nonatomic, copy) NSDictionary *audioSettings;

1.5.9 AVCaptureVideoDataOutput

  • AVCaptureVideoDataOutputAVCaptureOutput 的子類郑现,該類可以用來處理捕獲的每一個(gè)視頻幀數(shù)據(jù)湃崩。創(chuàng)建一個(gè)該類的實(shí)例對(duì)象后,要調(diào)用下面的方法設(shè)置一個(gè)代理對(duì)象接箫,及調(diào)用代理對(duì)象所實(shí)現(xiàn)的協(xié)議方法的隊(duì)列攒读。
- (void)setSampleBufferDelegate:(id<AVCaptureVideoDataOutputSampleBufferDelegate>)sampleBufferDelegate queue:(dispatch_queue_t)sampleBufferCallbackQueue;
  • 指定的隊(duì)列 sampleBufferCallbackQueue 必需是串行隊(duì)列以保證傳遞的幀是按記錄時(shí)間先后傳遞的。
//設(shè)置輸出的視頻要進(jìn)行怎樣的格式處理
//設(shè)置為空([NSDictionary dictionary])表示不改變輸入時(shí)的視頻格式
//設(shè)置為 nil 表示未壓縮格式
@property(nonatomic, copy) NSDictionary *videoSettings;

//獲取 kCVPixelBufferPixelFormatTypeKey 的有效值
@property(nonatomic, readonly) NSArray *availableVideoCVPixelFormatTypes NS_AVAILABLE(10_7, 5_0);

//獲取 AVVideoCodecKey 的有效值
@property(nonatomic, readonly) NSArray *availableVideoCodecTypes NS_AVAILABLE(10_7, 5_0);

//表示當(dāng)回調(diào)隊(duì)列阻塞時(shí)辛友,是否立刻丟棄新接收的幀數(shù)據(jù)
@property(nonatomic) BOOL alwaysDiscardsLateVideoFrames;

1.5.10 AVCaptureVideoDataOutputSampleBufferDelegate

  • 該協(xié)議用來處理接收的每一個(gè)幀數(shù)據(jù)整陌,或者提示客戶端有幀數(shù)據(jù)被丟棄。
//接收到一個(gè)幀數(shù)據(jù)時(shí)瞎领,在指定的串行隊(duì)列中調(diào)用該方法,攜帶幀數(shù)據(jù)并包含有其他幀信息
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection;

//丟棄一個(gè)幀數(shù)據(jù)時(shí)随夸,在指定的串行隊(duì)列中調(diào)用該方法九默,sampleBuffer 只攜帶幀信息,具體幀數(shù)據(jù)并未攜帶
- (void)captureOutput:(AVCaptureOutput *)captureOutput didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection NS_AVAILABLE(10_7, 6_0);

1.5.11 AVCaptureVideoPreviewLayer

  • AVCaptureVideoPreviewLayerCALayer 的子類宾毒,使用該類可以實(shí)現(xiàn)捕獲視頻的顯示驼修。使用一個(gè) session 創(chuàng)建一個(gè)該類對(duì)象,而后將該類對(duì)象插入到圖層樹中诈铛,從而顯示捕獲的視頻乙各。
//創(chuàng)建方法
+ (instancetype)layerWithSession:(AVCaptureSession *)session;
- (instancetype)initWithSession:(AVCaptureSession *)session;
  • 修改 AVCaptureVideoPreviewLayer 的屬性 videoGravity 值,可以選擇顯示捕獲視頻時(shí)的界面大小變化方式幢竹,它有以下可選值:
  1. AVLayerVideoGravityResize 默認(rèn)值耳峦,直接鋪滿屏幕,及時(shí)畫面變形
  2. AVLayerVideoGravityResizeAspect 保持畫面的橫縱比焕毫,不鋪滿屏幕蹲坷,多余的空間顯示黑色
  3. AVLayerVideoGravityResizeAspectFill 保持畫面的橫縱比,鋪滿屏幕邑飒,多余的畫面進(jìn)行裁剪

1.5.12 AVCaptureAudioDataOutput

  • AVCaptureAudioDataOutputAVCaptureOutput 的子類循签,該類可以處理接收到的音頻數(shù)據(jù)。同 AVCaptureVideoDataOutput 類似疙咸,該類也提供了一個(gè)方法县匠,用于設(shè)置代理對(duì)象,以及調(diào)用代理對(duì)象實(shí)現(xiàn)的協(xié)議方法時(shí)的隊(duì)列撒轮。
- (void)setSampleBufferDelegate:(id<AVCaptureAudioDataOutputSampleBufferDelegate>)sampleBufferDelegate queue:(dispatch_queue_t)sampleBufferCallbackQueue;

1.5.13 AVCaptureAudioDataOutputSampleBufferDelegate

  • 該協(xié)議提供了一個(gè)方法乞旦,用來實(shí)現(xiàn)對(duì)音頻數(shù)據(jù)的接收處理。
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection;

1.5.14 AVAssetImageGenerator

  • 使用 AVAssetImageGenerator 生成視頻資源的縮略圖腔召,使用 AVAsset 對(duì)象創(chuàng)建 AVAssetImageGenerator 對(duì)象杆查,可以使用類方法或?qū)嵗椒ǎ缦拢?/li>
+ (instancetype)assetImageGeneratorWithAsset:(AVAsset *)asset;
- (instancetype)initWithAsset:(AVAsset *)asset NS_DESIGNATED_INITIALIZER;

  • 當(dāng)然臀蛛,在此之前亲桦,最好調(diào)用 AVAsset 中的方法 - (NSArray<AVAssetTrack *> *)tracksWithMediaCharacteristic:(NSString *)mediaCharacteristic; 來判斷 asset 中是否有可視媒體數(shù)據(jù)崖蜜。如果有,那么再創(chuàng)建 AVAssetImageGenerator 對(duì)象客峭,而后再調(diào)用下面的方法豫领,來獲取一張或多張圖片。
//獲取一張圖片舔琅,requestedTime 指定要獲取視頻中哪個(gè)時(shí)刻的圖片等恐,actualTime 返回圖片實(shí)際是視頻的哪個(gè)時(shí)刻,outError 返回錯(cuò)誤信息
- (nullable CGImageRef)copyCGImageAtTime:(CMTime)requestedTime actualTime:(nullable CMTime *)actualTime error:(NSError * _Nullable * _Nullable)outError CF_RETURNS_RETAINED;

//獲取多張圖片备蚓,每一次圖片生成后课蔬,都會(huì)調(diào)用一次 handler
- (void)generateCGImagesAsynchronouslyForTimes:(NSArray<NSValue *> *)requestedTimes completionHandler:(AVAssetImageGeneratorCompletionHandler)handler;

//上述 handler 的類型如下,回調(diào)中的參數(shù)有圖片的請(qǐng)求時(shí)刻和實(shí)際時(shí)刻郊尝,圖片二跋,狀態(tài)(成功、失敗流昏、取消)扎即,錯(cuò)誤信息
typedef void (^AVAssetImageGeneratorCompletionHandler)(CMTime requestedTime, CGImageRef _Nullable image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * _Nullable error);

1.6 AVFoundation 之媒體流輸出

AVFoundation 視頻音頻輸出
  • 對(duì)媒體數(shù)據(jù)資源進(jìn)行簡單的轉(zhuǎn)碼或裁剪,使用 AVAssetExportSession 類便足夠了况凉,但是更深層次的修改媒體資源谚鄙,便需要用到 AVAssetReader 類和 AVAssetWriter 類。
  • AVAssetReader 只能與一個(gè)資源 asset 相關(guān)聯(lián)刁绒,且不能用來讀取實(shí)時(shí)數(shù)據(jù)闷营,在開始讀取數(shù)據(jù)之前,需要為 reader 添加 AVAssetReaderOutput 的實(shí)例對(duì)象知市。這個(gè)實(shí)例對(duì)象描述的是待讀取的數(shù)據(jù)資源來源類型粮坞,通常使用 AVAssetReaderAudioMixOutputAVAssetReaderTrackOutput 初狰、AVAssetReaderVideoCompositionOutput 三種子類莫杈。
  • AVAssetWriter 可以將來自多個(gè)數(shù)據(jù)源的數(shù)據(jù)以指定的格式寫入到一個(gè)指定的文件中,且其只能對(duì)應(yīng)一個(gè)文件奢入。在寫文件之前筝闹,需要用每一個(gè) AVAssetWriterInput 類實(shí)例對(duì)象來描述相應(yīng)的數(shù)據(jù)源。每一個(gè) AVAssetWriterInput 實(shí)例對(duì)象接收的數(shù)據(jù)都應(yīng)是 CMSampleBufferRef 類型的變量腥光。如果使用 AVAssetWriterInputPixelBufferAdaptor 類也可以直接將 CVPixelBufferRef 類型的變量數(shù)據(jù)添加到 writer input 中关顷。
  • AVAssetReaderAVAssetWriter 結(jié)合起來使用,便可以對(duì)讀取的數(shù)據(jù)進(jìn)行相應(yīng)的編輯修改武福,而后寫入到一個(gè)文件中并保存议双。

1.6.1 AVAssetReader

  • 使用該類讀取媒體資源,其提供的初始化方法與一個(gè) asset 相關(guān)聯(lián)捉片。
//對(duì)于提供的參數(shù) asset 平痰,如果是可被修改的汞舱,那么在開始讀取操作后,對(duì)其進(jìn)行了修改宗雇,之后的讀取操作都是無效的
+ (nullable instancetype)assetReaderWithAsset:(AVAsset *)asset error:(NSError * _Nullable * _Nullable)outError;
- (nullable instancetype)initWithAsset:(AVAsset *)asset error:(NSError * _Nullable * _Nullable)outError NS_DESIGNATED_INITIALIZER;

//當(dāng)前讀取操作的狀態(tài)昂芜,可取值有 AVAssetReaderStatusUnknown 、AVAssetReaderStatusReading 赔蒲、
AVAssetReaderStatusCompleted 泌神、AVAssetReaderStatusFailed 、AVAssetReaderStatusCancelled
@property (readonly) AVAssetReaderStatus status;
//當(dāng) status 的值為 AVAssetReaderStatusFailed 時(shí)舞虱,描述錯(cuò)誤信息
@property (readonly, nullable) NSError *error;


//限制可讀取的資源的時(shí)間范圍
@property (nonatomic) CMTimeRange timeRange;

//判斷能否添加該數(shù)據(jù)源
- (BOOL)canAddOutput:(AVAssetReaderOutput *)output;
//添加數(shù)據(jù)源
- (void)addOutput:(AVAssetReaderOutput *)output;

//開始讀取
- (BOOL)startReading;
//結(jié)束讀取
- (void)cancelReading;

1.6.2 AVAssetReaderOutput

  • AVAssetReaderOutput 是用來描述待讀取的數(shù)據(jù)的抽象類欢际,讀取資源時(shí),應(yīng)創(chuàng)建該類的對(duì)象矾兜,并添加到相應(yīng)的 AVAssetReader 實(shí)例對(duì)象中去幼苛。
//獲取的媒體數(shù)據(jù)的類型
@property (nonatomic, readonly) NSString *mediaType;

//是否拷貝緩存中的數(shù)據(jù)到客戶端,默認(rèn) YES 焕刮,客戶端可以隨意修改數(shù)據(jù),但是為優(yōu)化性能墙杯,通常設(shè)為 NO
@property (nonatomic) BOOL alwaysCopiesSampleData NS_AVAILABLE(10_8, 5_0);

//同步獲取下一個(gè)緩存數(shù)據(jù)配并,使用返回的數(shù)據(jù)結(jié)束后,應(yīng)使用 CFRelease 函數(shù)將其釋放
//當(dāng)錯(cuò)誤或沒有數(shù)據(jù)可讀取時(shí)高镐,返回 NULL 溉旋,返回空后,應(yīng)檢查相關(guān)聯(lián)的 reader 的狀態(tài)
- (nullable CMSampleBufferRef)copyNextSampleBuffer CF_RETURNS_RETAINED;

//是否支持重新設(shè)置數(shù)據(jù)的讀取時(shí)間范圍嫉髓,即能否修改 reader 的 timeRange 屬性
@property (nonatomic) BOOL supportsRandomAccess NS_AVAILABLE(10_10, 8_0);
//設(shè)置重新讀取的時(shí)間范圍观腊,這個(gè)時(shí)間范圍集合中的每一個(gè)時(shí)間范圍的開始時(shí)間必需是增長的且各個(gè)時(shí)間范圍不能重疊
//應(yīng)在 reader 調(diào)用 copyNextSampleBuffer 方法返回 NULL 之后才可調(diào)用
- (void)resetForReadingTimeRanges:(NSArray<NSValue *> *)timeRanges NS_AVAILABLE(10_10, 8_0);
//該方法調(diào)用后,上面的方法即不可再調(diào)用算行,同時(shí) reader 的狀態(tài)也不會(huì)被阻止變?yōu)?AVAssetReaderStatusCompleted 了
- (void)markConfigurationAsFinal NS_AVAILABLE(10_10, 8_0);

1.6.3 AVAssetReaderTrackOutput

  • AVAssetReaderTrackOutputAVAssetReaderOutput 的子類梧油,它用來描述待讀取的數(shù)據(jù)來自 asset track ,在讀取前州邢,還可以對(duì)數(shù)據(jù)的格式進(jìn)行修改儡陨。
//初始化方法,參數(shù)中指定了 track 和 媒體的格式
//指定的 track 應(yīng)在 reader 的 asset 中
+ (instancetype)assetReaderTrackOutputWithTrack:(AVAssetTrack *)track outputSettings:(nullable NSDictionary<NSString *, id> *)outputSettings;
- (instancetype)initWithTrack:(AVAssetTrack *)track outputSettings:(nullable NSDictionary<NSString *, id> *)outputSettings NS_DESIGNATED_INITIALIZER;

//指定音頻處理時(shí)的算法
@property (nonatomic, copy) NSString *audioTimePitchAlgorithm NS_AVAILABLE(10_9, 7_0);

1.6.4 AVAssetReaderAudioMixOutput

  • AVAssetReaderAudioMixOutputAVAssetReaderOutput 的子類量淌,它用來描述待讀取的數(shù)據(jù)來自音頻組合數(shù)據(jù)骗村。創(chuàng)建該類實(shí)例對(duì)象提供的參數(shù) audioTracks 集合中的每一個(gè) asset track 都屬于相應(yīng)的 reader 中的 asset 實(shí)例對(duì)象,且類型為 AVMediaTypeAudio 呀枢。
  • 參數(shù) audioSettings 給出了音頻數(shù)據(jù)的格式設(shè)置胚股。
+ (instancetype)assetReaderAudioMixOutputWithAudioTracks:(NSArray<AVAssetTrack *> *)audioTracks audioSettings:(nullable NSDictionary<NSString *, id> *)audioSettings;
- (instancetype)initWithAudioTracks:(NSArray<AVAssetTrack *> *)audioTracks audioSettings:(nullable NSDictionary<NSString *, id> *)audioSettings NS_DESIGNATED_INITIALIZER
  • 此外,該類的 audioMix 屬性裙秋,描述了從多個(gè) track 中讀取的音頻的音量變化情況:@property (nonatomic, copy, nullable) AVAudioMix *audioMix;

1.6.5 AVAssetReaderVideoCompositionOutput

  • AVAssetReaderVideoCompositionOutputAVAssetReaderOutput 的子類琅拌,該類用來表示要讀取的類是組合的視頻數(shù)據(jù)缨伊。
    AVAssetReaderAudioMixOutput 類似,該類也提供了兩個(gè)創(chuàng)建實(shí)例的方法财忽,需要提供的參數(shù)的 videoTracks 集合中每一個(gè) track 都是 與 reader 相關(guān)聯(lián)的 asset 中的 track 倘核。
+ (instancetype)assetReaderVideoCompositionOutputWithVideoTracks:(NSArray<AVAssetTrack *> *)videoTracks videoSettings:(nullable NSDictionary<NSString *, id> *)videoSettings;
- (instancetype)initWithVideoTracks:(NSArray<AVAssetTrack *> *)videoTracks videoSettings:(nullable NSDictionary<NSString *, id> *)videoSettings NS_DESIGNATED_INITIALIZER;
  • 該類的屬性 videoComposition 同樣描述了每個(gè) track 的幀的顯示方式。
@property (nonatomic, copy, nullable) AVVideoComposition *videoComposition;

1.7 AVFoundation 之媒體的時(shí)間和數(shù)據(jù)

AVFoundation 媒體的時(shí)間與數(shù)據(jù)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末即彪,一起剝皮案震驚了整個(gè)濱河市紧唱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌隶校,老刑警劉巖漏益,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異深胳,居然都是意外死亡绰疤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門舞终,熙熙樓的掌柜王于貴愁眉苦臉地迎上來轻庆,“玉大人,你說我怎么就攤上這事敛劝∮啾” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵夸盟,是天一觀的道長蛾方。 經(jīng)常有香客問我,道長上陕,這世上最難降的妖魔是什么桩砰? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮释簿,結(jié)果婚禮上亚隅,老公的妹妹穿的比我還像新娘。我一直安慰自己庶溶,他們只是感情好枢步,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著渐尿,像睡著了一般醉途。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上砖茸,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天隘擎,我揣著相機(jī)與錄音,去河邊找鬼凉夯。 笑死货葬,一個(gè)胖子當(dāng)著我的面吹牛采幌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播震桶,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼休傍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蹲姐?” 一聲冷哼從身側(cè)響起磨取,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎柴墩,沒想到半個(gè)月后忙厌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡江咳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年逢净,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片歼指。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡爹土,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出踩身,到底是詐尸還是另有隱情胀茵,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布惰赋,位于F島的核電站,受9級(jí)特大地震影響呵哨,放射性物質(zhì)發(fā)生泄漏赁濒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一孟害、第九天 我趴在偏房一處隱蔽的房頂上張望拒炎。 院中可真熱鬧,春花似錦挨务、人聲如沸击你。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丁侄。三九已至,卻和暖如春朝巫,著一層夾襖步出監(jiān)牢的瞬間鸿摇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國打工劈猿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拙吉,地道東北人潮孽。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像筷黔,于是被迫代替她去往敵國和親往史。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348