IOS音視頻(一)AVFoundation核心類

IOS音視頻(一)AVFoundation核心類html

IOS音視頻(二)AVFoundation視頻捕捉ios

IOS音視頻(三)AVFoundation 播放和錄音算法

IOS音視頻(四十三)AVFoundation 之 Audio Session編程

IOS音視頻(四十四)AVFoundation 之 Audio Queue Servicesswift

IOS音視頻(四十五)HTTPS 自簽名證書 實現邊下邊播數組

IOS音視頻(四十六)離線在線語音識別方案緩存

IOS音視頻(一)AVFoundation核心類cookie

  • 作音視頻開發是個很複雜的工做,須要咱們理解不少有關素材的知識:聲學和視覺相關的科學理論,數的程序開發技術和有AVFoundation框架而引出的其餘框架的知識,好比:Core Media, Core Video, Core Image, Core Audio, Media PlayerVideoToolbox 等等。網絡

  • 要作IOS音視頻相關的開發,確定要熟悉AVFoundation框架。學習框架最好的方式就是研究蘋果官方文檔:蘋果官方AVFoundation框架介紹session

  • AVFoundation 是 Objective-C 中建立及編輯視聽媒體文件的幾個框架之一,其提供了檢查、建立、編輯或從新編碼媒體文件的接口,也使得從設備獲取的視頻實時數據可操縱。可是,一般狀況,簡單的播放或者錄像,直接使用 AVKit 框架或者 UIImagePickerController 類便可。另外,值得注意的是,在 AVFoundation 框架中使用的基本數據結構,如時間相關的或描述媒體數據的數據結構都聲明在 CoreMedia 框架中。

  • AVFoundation 是 OSX 系統和 iOS 系統中用於處理基於時間的媒體數據的高級 objectivec 框架,其設計過程高度依賴多線程機制,充分利用了多核硬件優點,大量使用 Block 和 GCD 機制。AVFoundation 能與高層級框架無縫銜接,也能提供低層級框架的功能和性能。

1. AVFoundation框架架構簡介

  • 引用蘋果官方文檔介紹圖以下:

iOS系統上的AVFoundation框架架構

Mac OS X系統上的AVFoundation框架架構

Core Audio是OS X和IOS系統上處理全部音頻 事件的框架。Core Audio是有多高框架整合在一塊兒的總稱,爲音頻和MIDI內容的錄製,播放和處理提供相應的接口。Core Audio也提供高級的接口,好比經過Audio Queue Services框架所提供的那些接口,主要處理基本的音頻播放和錄音相關功能。同時還會提供相對低層級的接口,尤爲是Audio Units接口,它們提供了針對音頻信號進行徹底控制的功能,並經過Audio Units讓你可以構建一些複雜的音頻處理模式,就像經過蘋果公司的Logic Pro X和Avid's Pro Tolls工具所實現的功能同樣。

Core Video是OS X 和IOS系統上針對數字視頻所提供的管道模式。Core Video爲其相對的Core Media提供圖片緩存和緩存支持,提供了一個可以對數字視頻逐幀訪問的接口。該框架經過像素格式之間的轉換並管理同步事項時的複雜的工做獲得了有效簡化。

Core Media 是AV Foundation所用到的低層級媒體管道的一部分。它提供針對音頻樣本和視頻幀處理所需的低層級數據類型和接口。Core Media還提供了AV Foundation用的的基於CMTime數據類型的時間模型。CMTime及其相關數據類型通常在AV Foundation處理基於時間的操做時使用。

Core Animation時OS X和 iOS 提供的合成及動畫相關框架。主要功能就是提供蘋果平臺所具備的美觀,流暢的動畫效果。提供了一個簡單,聲明行的編程模式,並已經封裝了支持OpenGL 和OpenGL ES 功能的基於Object-C的各類類。使用Core Animation時,對於食品內容的播放和視頻捕獲這兩個動做,AVFoundation 提供了硬件加速機制來對整個流程進行優化。AVFoundation 還能夠利用Core Animation讓開發者可以在視頻編輯和播放過程當中添加動畫標題和圖片效果。

  • 蘋果提供了AVFoundation框架,能夠用來檢測,編輯,建立,從新編碼媒體文件,還能夠實時獲取設備的流媒體數據,實時操做這些被捕獲的視頻流數據。
  • 蘋果推薦咱們儘量的使用高度抽象的接口:
  1. 若是隻是簡單播放視頻文件,使用AVKit框架便可。
  2. 若是隻是想簡單錄製視頻,使用UIKit框架裏的UIImagePickerController既能夠實現。

1.1 AVFoundation框架

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

AVFoundation框架1

  • AVFoundation 框架中最基本的類是 AVAsset ,它是一個或者多個媒體數據的集合,描述的是整個集合的屬性,如標題、時長、大小等,而且沒有特定的數據格式。集合的每個媒體數據都是統一的數據類型,稱之爲 track。簡單的狀況是一種數據是音頻數據,一種是視頻數據,而較複雜的狀況是一種數據交織着音頻和視頻數據,而且 AVAsset 是可能有元數據的。 另外,須要明白的是在 AVFoundation 中,初始化了 asset 及 track 後,並不意味着資源已經可用,由於若資源自己並不攜帶自身信息時,那麼系統須要本身計算相關信息,這個過程會阻塞線程,因此應該使用異步方式進行獲取資源信息後的操做。

  • AVFoundation 中可使用 compositions 將多個媒體數據(video/audio tracks)合成爲一個 asset ,這個過程當中,能夠添加或移除 tracks ,調整它們的順序,或者設置音頻的音量和變化坡度,視頻容量等屬性。這些媒體數據的集合保存在內存中,直到使用 export session 將它導出到本地文件中。另外,還可使用 asset writer 建立 asset 。

  • 使用 capture session 協調從設備(如相機、麥克風)輸入的數據和輸出目標(如視頻文件)。能夠爲 session 設置多個輸入和輸出,即便它正在工做,還能夠經過它中止數據的流動。另外,還可使用 preview layer 將相機記錄的影像實時展現給用戶。

  • AVFoundation 中的回調處理並不保證回調任務在某個特定的線程或隊列中執行,其遵循兩個原則,UI 相關的操做在主線程中執行,其餘回調須要爲其指定調用的隊列。

1.2 AVFoundation 之 Assets

Assets

  • 參考蘋果官方介紹

  • AVAsset 是AVFoundation框架裏的一個核心類,主要提供了一種形式獨立的基於時間的視聽數據抽象,例如電影文件或視頻流。

    AVAsset類繼承關係

  • AVAsset 包含須要一塊兒呈現或處理的音軌集合,每一個音軌都是統一的媒體類型,包括(但不限於)音頻、視頻、文本、封閉字幕和字幕。asset對象提供關於整個資源的信息,好比它的持續時間或標題,以及表示的提示,好比它的大小。AVAsset 也能夠有元數據,由AVMetadataItem的實例表示。

  • 跟蹤由AVAssetTrack的實例表示,在一個典型的簡單例子中,一個軌道表示音頻組件,另外一個表示視頻組件;在一個複雜的組合中,音頻和視頻可能會有多個重疊的音軌。

AVAssetTrack結構

  • 音軌具備許多屬性,例如其類型(視頻或音頻)、可視和/或可聽特徵(視狀況而定)、元數據和時間軸(以其父資產的形式表示)。磁道也有一組格式說明。數組包含CMFormatDescription對象(參見CMFormatDescriptionRef),每一個對象描述曲目引用的媒體樣本的格式。包含統一媒體的磁道(例如,全部使用相同設置編碼的磁道)將提供一個計數爲1的數組。

  • 一個磁道自己能夠被分割成段,用AVAssetTrackSegment的實例來表示。段是從源到資產跟蹤時間線的時間映射。

  • CMTime是一個C結構,它將時間表示爲一個有理數,具備一個分子(int64_t值)和一個分母(int32_t時間刻度)。從概念上講,時間刻度指定了分子中每一個單位所佔的秒數。所以,若是時間刻度是4,每一個單元表明四分之一秒;若是時間刻度是10,每一個單元表示十分之一秒,以此類推。您常用600的時間刻度,由於這是幾種經常使用幀率的倍數:24幀用於電影,30幀用於NTSC(用於北美和日本的電視),25幀用於PAL(用於歐洲的電視)。使用600的時間刻度,您能夠精確地表示這些系統中的任意數量的幀。除了簡單的時間值以外,CMTime結構還能夠表示非數值:+∞、-∞和不定。它還能夠指示時間是否在某個點被四捨五入,並保持一個曆元數。

  • 您可使用CMTimeMakeCMTimeMakeWithSeconds等相關函數之一建立時間(該函數容許您使用浮點值建立時間並指定首選時間刻度)。有幾個函數用於基於時間的算術和比較時間,以下例所示:

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 提供了多種方法來建立 asset ,能夠簡單的重編碼已經存在的 asset ,這個過程可使用 export session 或者使用 asset reader 和 asset writer 。
  • 若要生成視頻的縮略圖,可使用 asset 初始化一個 AVAssetImageGenerator 實例對象,它會使用默承認用的視頻 tracks 來生成圖片。
  • 建立 AVAsset 或其子類 AVURLAsset 時,須要提供資源的位置,方法以下:
NSURL *url = <#視聽資源的 URL ,能夠是本地文件地址,也能夠是網頁媒體連接#>;
AVURLAsset *anAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
複製代碼
  • 上述方法的第二個參數是建立對象時的選擇項,其中可能包含的選擇項以下:

AVURLAssetPreferPreciseDurationAndTimingKey 是否須要資源的準確時長,及訪問資源各個準確的時間點 AVURLAssetReferenceRestrictionsKey 連接其餘資源的約束 AVURLAssetHTTPCookiesKey 添加資源可以訪問的 HTTP cookies AVURLAssetAllowsCellularAccessKey 是否可以使用蜂窩網絡

  • 建立並初始化一個 AVAsset 實例對象後,並不意味着該對象的全部屬性均可以獲取使用了,由於其中的一些屬性須要額外的計算纔可以獲得,那麼當獲取這些屬性時,可能會阻塞當前線程,因此須要異步獲取這些屬性。
  • AVAsset 與 AVAssetTrack 都遵循 AVAsynchronousKeyValueLoading 協議,這個協議中有如下兩個方法:
//獲取指定屬性的狀態
- (AVKeyValueStatus)statusOfValueForKey:(NSString *)key error:(NSError * _Nullable * _Nullable)outError;

//異步加載指定的屬性集合
- (void)loadValuesAsynchronouslyForKeys:(NSArray<NSString *> *)keys completionHandler:(nullable void (^)(void))handler;
複製代碼
  • 一般,咱們使用上述第二個方法異步加載想要的屬性,然後在加載完成的回調 block 中使用第一個方法判斷屬性是否加載成功,而後訪問想要的屬性,執行本身的操做,以下代碼:
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];
    //根據相應的屬性狀態進行對應的處理
    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章節

  • 要控制媒體資源的回放,可使用AVPlayer對象。在回放期間,您可使用AVPlayerItem實例來管理整個Asset的表示狀態,使用AVPlayerItemTrack對象來管理單個曲目的表示狀態。要顯示視頻,可使用AVPlayerLayer對象。

  • player是一個控制器對象,您可使用它來管理資產的回放,例如啓動和中止回放,以及查找特定的時間。您使用AVPlayer實例來播放單個資產。您可使用AVQueuePlayer對象按順序播放許多項(AVQueuePlayer是AVPlayer的子類)。在OS X上,你能夠選擇使用AVKit框架的AVPlayerView類來回放視圖中的內容。

  • 播放器向您提供有關播放狀態的信息,所以,若是須要,您能夠將用戶界面與播放器的狀態同步。一般將播放器的輸出定向到特定的核心動畫層(AVPlayerLayerAVSynchronizedLayer的實例)。有關層的更多信息,請參見Core Animation Programming Guide

  • 儘管最終你想要播放資產,但你不能直接提供資產給AVPlayer 對象。而是提供AVPlayerItem的一個實例。播放器項管理與其相關聯的資產的表示狀態。播放器項包含播放器項跟蹤—avplayeritemtrack的實例—對應於資產中的跟蹤。各對象之間的關係如圖所示:

    AVAsset對象關係

  • 這種抽象意味着您能夠同時使用不一樣的玩家來玩給定的資產,可是每一個玩家呈現的方式不一樣。圖2-2顯示了一種可能性,即兩個不一樣的玩家使用不一樣的設置來玩相同的資產。例如,使用項曲目,您能夠在回放期間禁用特定的曲目(例如,您可能不想播放聲音組件)。

    圖2-2

  • 您可使用現有資產初始化播放器項,也能夠直接從URL初始化播放器項,以便在特定位置播放資源(AVPlayerItem將隨後爲資源建立和配置資產)。不過,與AVAsset同樣,簡單地初始化播放器項並不必定意味着它能夠當即播放。您能夠觀察(使用鍵值觀察)一個項目的狀態屬性來肯定它是否準備好了,以及什麼時候準備好了。

  • 使用一個 AVPlayer 類實例能夠管理一個 asset 資源,可是它的屬性 currentItem 纔是 asset 的實際管理者。currentItem 是 AVPlayerItem 類的實例,而它的屬性 tracks 包含着的 AVPlayerItemTracker 實例對應着 asset 中的各個 track 。

  • 那麼,爲了控制 asset 的播放,可使用 AVPlayer 類,在播放的過程當中,可使用 AVPlayerItem 實例管理整個 asset 的狀態,使用 AVPlayerItemTracker 對象管理 asset 中每一個 track 的狀態。另外,還可使用 AVPlayerLayer 類來顯示播放的內容。

  • 因此,在建立 AVPlayer 實例對象時,除了能夠直接傳遞資源文件的路徑進行建立外,還能夠傳遞 AVPlayerItem 的實例對象,以下方法:

+ (instancetype)playerWithURL:(NSURL *)URL;
+ (instancetype)playerWithPlayerItem:(nullable AVPlayerItem *)item;
- (instancetype)initWithURL:(NSURL *)URL;
- (instancetype)initWithPlayerItem:(nullable AVPlayerItem *)item;
複製代碼
  • 建立後,並非能夠直接使用,還要對它的狀態進行檢查,只有 status 的值爲 AVPlayerStatusReadyToPlay 時,才能進行播放,因此這裏須要使用 KVO 模式對該狀態進行監控,以決定什麼時候能夠進行播放。
  • 若要管理多個資源的播放,則應使用 AVPlayer 的子類 AVQueuePlayer ,這個子類擁有的多個 AVPlayerItem 同各個資源相對應。

1.3.2 播放不一樣類型的資源

  • 對於播放不一樣類型的資源,須要進行的準備工做有所不一樣,這主要取決於資源的來源。資源數據可能來自本地設備上文件的讀取,也可能來自網絡上數據流。
  • 對於本地文件,可使用文件地址建立 AVAsset 對象,然後使用該對象建立 AVPlayerItem 對象,最後將這個 item 對象與 AVPlayer 對象相關聯。以後,即是等待 status 的狀態變爲 AVPlayerStatusReadyToPlay ,即可以進行播放了。
  • 對於網絡數據的播放,不能使用地址建立 AVAsset 對象了,而是直接建立 AVPlayerItem 對象,將其同 AVPlayer 對象相關聯,當 status 狀態變爲 AVPlayerStatusReadyToPlay 後,AVAssetAVAssetTrack 對象將由 item 對象建立。

1.3.3 播放控制

  • 經過調用 player 的 play 、pause 、setRate: 方法,能夠控制 item 的播放,這些方法都會改變 player 的屬性 rate 的值,該值爲 1 表示 item 按正常速率播放,爲 0 表示 item 暫停播放,0~1 表示低速播放,大於 1 表示高速播放,小於 0 表示從後向前播放。
  • item 的屬性 timeControlStatus 的值表示當前 item 的狀態,有下面 3 個值:
  1. AVPlayerTimeControlStatusPaused 暫停
  2. AVPlayerTimeControlStatusPlaying 播放
  3. AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate 等待按指定速率播放狀態,該狀態是當 rate 的值設置爲非 0 值時,而 item 因某些緣由還沒法播放的狀況,而沒法播放的緣由,可依經過 item 的 reasonForWaitingToPlay 屬性值查看。
  • item 的屬性 actionAtItemEnd 的值表示當前 item 播放結束後的動做,有下面 3 個值:
  1. AVPlayerActionAtItemEndAdvance 只適用於 AVQueuePlayer 類,表示播放隊列中的下一個 item
  2. AVPlayerActionAtItemEndPause 表示暫停
  3. AVPlayerActionAtItemEndNone 表示無操做,當前 item 的 currentTime 屬性值仍然按 rate 的值改變 item 的 currentTime 屬性值表示當前 item 的播放時間,能夠調用下面的方法指定 item 從何處進行播放。
//第二個方法可以進行更準確的跳轉,可是須要進行額外的計算
- (void)seekToDate:(NSDate *)date;
- (void)seekToTime:(CMTime)time toleranceBefore:(CMTime)toleranceBefore toleranceAfter:(CMTime)toleranceAfter; (tolerance: 公差,先後公差)

//這兩個方法傳入了一個回調,當一個時間跳轉請求被新的請求或其餘操做打斷時,回調也會被執行可是此時 finished 參數值爲 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 管理多個 item 的播放,仍然能夠經過調用 play 開始依次播放 item,調用 advanceToNextItem 方法播放下一個 item ,還能夠經過下面的方法添加或移除 item 。
- (BOOL)canInsertItem:(AVPlayerItem *)item afterItem:(nullable AVPlayerItem *)afterItem;
- (void)insertItem:(AVPlayerItem *)item afterItem:(nullable AVPlayerItem *)afterItem;
- (void)removeItem:(AVPlayerItem *)item;
- (void)removeAllItems;
複製代碼
  • 可使用下面的方法監聽播放時間的變化,須要強引用這兩個方法返回的監聽者。
- (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;
複製代碼
  • 用上面的方法每註冊一個監聽者,就須要對應的使用下面的方法進行註銷,而且在註銷以前,要確保沒有 block 被執行。- (void)removeTimeObserver:(id)observer;
  • 當 item 播放結束後,再次調用 player 的方法 play 不會使 item 從新播放,要實現重播,能夠註冊一個 AVPlayerItemDidPlayToEndTimeNotification 通知,當接收到這個通知時,能夠調 seekToTime: 方法,傳入 kCMTimeZero 參數,將 player 的播放時間重置。

1.3.4 自定義播放--音頻

  • 要在媒體資源播放的過程當中實現音頻的自定義播放,須要用 AVMutableAudioMix 對不一樣的音頻進行編輯。這個類的實例對象的屬性 inputParameters 是音量描述對象的集合,每一個對象都是對一個 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

  • 該類中有一個屬性 inputParameters ,它是 AVAudioMixInputParameters 實例對象的集合,每一個實例都是對音頻播放方式的描述。可見,AVAudioMix 並不直接改變音頻播放的方式,其只是存儲了音頻播放的方式。

1.3.4.2 AVMutableAudioMix

  • AVMutableAudioMixAVAudioMix 的子類,它的方法 audioMix 返回一個 inputParameters 屬性爲空的實例。

1.3.4.3 AVAudioMixInputParameters

  • 這個類是音量變化的描述類,它同一個音頻的 track 相關聯,並設置音量隨時間變化的算法,其獲取音量變化的方法以下:
//獲取的音量變化範圍 timeRange 應包含指定的時刻 time 不然最終返回 NO
//startVolume 獲取音量開始變化時的初始音量
//endVolume 獲取音量變化結束時的音量
//timeRang 是實際音量變化的範圍,它應該包含指定的 time
- (BOOL)getVolumeRampForTime:(CMTime)time startVolume:(nullable float *)startVolume endVolume:(nullable float *)endVolume timeRange:(nullable CMTimeRange *)timeRange;
複製代碼

1.3.4.4 AVMutableAudioMixInputParameters

  • AVMutableAudioMixInputParameters 是 AVAudioMixInputParameters 的子類,它提供了直接設置某個時刻或時間段的音量的方法。
//根據提供的 track 建立一個實例,此時的音量描述數據爲空
+ (instancetype)audioMixInputParametersWithTrack:(nullable AVAssetTrack *)track;

//建立一個實例,此時的音量變化描述是空的,且 trackID 爲 kCMPersistentTrackID_Invalid
+ (instancetype)audioMixInputParameters;

//設置某個時間範圍內的初始音量及結束音量
- (void)setVolumeRampFromStartVolume:(float)startVolume toEndVolume:(float)endVolume timeRange:(CMTimeRange)timeRange;

//設置某個時刻的音量
- (void)setVolume:(float)volume atTime:(CMTime)time;
複製代碼

1.3.5 自定義播放--視頻

  • 同音頻的自定義播放同樣,要實現視頻的自定義播放,僅僅將視頻資源集合到一塊兒是不夠的,須要使用 AVMutableVideoComposition 類來定義不一樣的視頻資源在不一樣的時間範圍內的播放方式。

1.3.5.1 AVVideoComposition

  • AVVideoComposition 是 AVMutableVideoComposition 的父類,它的主要屬性和方法以下:
//該類的構造類,提供自定義的構造類時,提供的類要遵照 AVVideoCompositing 協議
@property (nonatomic, readonly, nullable) Class<AVVideoCompositing> customVideoCompositorClass NS_AVAILABLE(10_9, 7_0);

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

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

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

//描述視頻集合中具體視頻播放方式信息的集合,其是遵循 AVVideoCompositionInstruction 協議的類實例對象
//這些視頻播放信息構成一個完整的時間線,不能重疊,不能間斷,而且在數組中的順序即爲相應視頻的播放順序
@property (nonatomic, readonly, copy) NSArray<id <AVVideoCompositionInstruction>> *instructions;

//用於組合視頻幀與動態圖層的 Core Animation 的工具對象,能夠爲 nil 
@property (nonatomic, readonly, retain, nullable) AVVideoCompositionCoreAnimationTool *animationTool;

//直接使用一個 asset 建立一個實例,建立的實例的各個屬性會根據 asset 中的全部的 video tracks 的屬性進行計算並適配,因此在調用該方法以前,確保 asset 中的屬性已經加載
//返回的實例對象的屬性 instructions 中的對象會對應每一個 asset 中的 track 中屬性要求
//返回的實例對象的屬性 frameDuration 的值是 asset 中 全部 track 的 nominalFrameRate 屬性值最大的,若是這些值都爲 0 ,默認爲 30fps
//返回的實例對象的屬性 renderSize 的值是 asset 的 naturalSize 屬性值,若是 asset 是 AVComposition 類的實例。不然,renderSize 的值將包含每一個 track 的 naturalSize 屬性值
+ (AVVideoComposition *)videoCompositionWithPropertiesOfAsset:(AVAsset *)asset NS_AVAILABLE(10_9, 6_0);

//這三個屬性設置了渲染幀時的顏色空間、矩陣、顏色轉換函數,可能的值都在 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);

//該方法返回一個實例,它指定的 block 會對 asset 中每個有效的 track 的每一幀進行渲染獲得 CIImage 實例對象
//在 block 中進行每一幀的渲染,成功後應調用 request 的方法 finishWithImage:context: 並將獲得的 CIImage 對象做爲參數
//如果渲染失敗,則應調用 finishWithError: 方法並傳遞錯誤信息

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

1.3.5.2 AVMutableVideoComposition

  • AVMutableVideoComposition 是 AVVideoComposition 的可變子類,它繼承父類的屬性能夠改變,而且新增了下面的建立方法。
//這個方法建立的實例對象的屬性的值都是 nil 或 0,可是它的屬性都是能夠進行修改的
+ (AVMutableVideoComposition *)videoComposition;
複製代碼

1.3.5.3 AVVideoCompositionInstruction

  • 在上述的兩個類中,真正包含有視頻播放方式信息的是 instructions 屬性,這個集合中的對象都遵循 AVVideoCompositionInstruction 協議,若不使用自定義的類,那麼可使用 AVFoundation 框架中的 AVVideoCompositionInstruction 類。
  • 該類的相關屬性以下:
//表示該 instruction 生效的時間範圍
@property (nonatomic, readonly) CMTimeRange timeRange;

//指定當前時間段的 composition 的背景色
//若是沒有指定,那麼使用默認的黑色
//若是渲染的像素沒有透明度通道,那麼這個顏色也會忽略透明度
@property (nonatomic, readonly, retain, nullable) __attribute__((NSObject)) CGColorRef backgroundColor;

//AVVideoCompositionLayerInstruction 類實例對象的集合,描述各個視頻資源幀的層級及組合關係
//按這個數組的順序,第一個顯示在第一層,第二個在第一層下面顯示,以此類推
@property (nonatomic, readonly, copy) NSArray<AVVideoCompositionLayerInstruction *> *layerInstructions;

//代表該時間段的視頻幀是否須要後期處理
//若爲 NO,後期圖層的處理將跳過該時間段,這樣可以提升效率
//爲 YES 則按默認操做處理(參考 AVVideoCompositionCoreAnimationTool 類)
@property (nonatomic, readonly) BOOL enablePostProcessing;

//當前 instruction 中須要進行幀組合的全部的 track ID 的集合,由屬性 layerInstructions 計算獲得
@property (nonatomic, readonly) NSArray<NSValue *> *requiredSourceTrackIDs NS_AVAILABLE(10_9, 7_0);

//若是當前的 instruction 在該時間段內的視頻幀組合後,實質獲得的是某個源視頻的幀,那麼就返回這個視頻資源的 ID
@property (nonatomic, readonly) CMPersistentTrackID passthroughTrackID NS_AVAILABLE(10_9, 7_0); 
複製代碼

1.3.5.4 AVMutableVideoCompositionInstruction

  • AVMutableVideoCompositionInstruction 是 AVVideoCompositionInstruction 的子類,其繼承的父類的屬性可進行修改,而且提供了建立屬性值爲 nil 或無效的實例的方法。
+ (instancetype)videoCompositionInstruction;
複製代碼

1.3.5.5 AVVideoCompositionLayerInstruction

  • AVVideoCompositionLayerInstruction 是對給定的視頻資源的不一樣播放方式進行描述的類,經過下面的方法,能夠獲取仿射變化、透明度變化、裁剪區域變化的梯度信息。
//獲取包含指定時間的仿射變化梯度信息
//startTransform、endTransform 用來接收變化過程的起始值與結束值
//timeRange 用來接收變化的持續時間範圍
//返回值表示指定的時間 time 是否在變化時間 timeRange 內
- (BOOL)getTransformRampForTime:(CMTime)time startTransform:(nullable CGAffineTransform *)startTransform endTransform:(nullable CGAffineTransform *)endTransform timeRange:(nullable CMTimeRange *)timeRange;

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

//獲取包含指定時間的裁剪區域的變化梯度信息
//startCropRectangle、endCropRectangle 用來接收變化過程的起始值與結束值
//timeRange 用來接收變化的持續時間範圍
//返回值表示指定的時間 time 是否在變化時間 timeRange 內
- (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 資源播放時的仿射變化、裁剪區域、透明度等信息。

  • 相比於父類,該子類還提供了建立實例的方法:

//這兩個方法的區別在於,前者返回的實例對象的屬性 trackID 的值是 track 的 trackID 值
//而第二個方法的返回的實例對象的屬性 trackID 的值爲 kCMPersistentTrackID_Invalid
+ (instancetype)videoCompositionLayerInstructionWithAssetTrack:(AVAssetTrack *)track;
+ (instancetype)videoCompositionLayerInstruction;

複製代碼
  • 該類的屬性表示 instruction 所做用的 track 的 ID:
@property (nonatomic, assign) CMPersistentTrackID trackID;
複製代碼
  • 設置了 trackID 後,經過下面的方法,進行剃度信息的設置:
//設置視頻中幀的仿射變化信息
//指定了變化的時間範圍、起始值和結束值,其中座標系的原點爲左上角,向下向右爲正方向
- (void)setTransformRampFromStartTransform:(CGAffineTransform)startTransform toEndTransform:(CGAffineTransform)endTransform timeRange:(CMTimeRange)timeRange;

//設置 instruction 的 timeRange 範圍內指定時間的仿射變換,該值會一直保持,直到被再次設置
- (void)setTransform:(CGAffineTransform)transform atTime:(CMTime)time;

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

//設置指定時間的透明度,該透明度會一直持續到下一個值被設置
- (void)setOpacity:(float)opacity atTime:(CMTime)time;

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

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

1.3.5.7 AVVideoCompositionCoreAnimationTool

  • 在自定義視頻播放時,可能須要添加水印、標題或者其餘的動畫效果,須要使用該類。該類一般用來協調離線視頻中圖層與動畫圖層的組合(如使用 AVAssetExportSessionAVAssetReaderAVAssetReader 類導出視頻文件或讀取視頻文件時),而如果在線實時的視頻播放,應使用 AVSynchronizedLayer 類來同步視頻的播放與動畫的效果。

  • 在使用該類時,注意動畫在整個視頻的時間線上都可以被修改,因此,動畫的開始時間應該設置爲 AVCoreAnimationBeginTimeAtZero ,這個值其實比 0 大,屬性值 removedOnCompletion 應該置爲 NO,以防當動畫執行結束後被移除,而且不該使用與任何的 UIView 相關聯的圖層。

  • 做爲視頻組合的後期處理工具類,主要方法以下:

//向視頻組合中添加一個動畫圖層,這個圖層不能在任何圖層樹中
//提供的參數 trackID 應由方法 [AVAsset unusedTrackID] 獲得,它不與任何視頻資源的 trackID 相關
//AVVideoCompositionInstruction 的屬性 layerInstructions 包含的 AVVideoCompositionLayerInstruction 實例對象中應該有
//該 trackID 一致的 AVVideoCompositionLayerInstruction 實例對象,而且爲性能考慮,不該使用該對象設置 transform 的變化
//在 iOS 中,CALayer 做爲 UIView 的背景圖層,其內容的是否可以翻轉,由方法 contentsAreFlipped 決定(若是全部的圖層包括子圖層,該方法返回的值爲 YES 的個數爲奇數個,表示能夠圖層中內容能夠垂直翻轉)
//因此這裏的 layer 若用來設置 UIView 的 layer 屬性,或做爲其中的子圖層,其屬性值 geometryFlipped 應設置爲 YES ,這樣則可以保持是否可以翻轉的結果一致
+ (instancetype)videoCompositionCoreAnimationToolWithAdditionalLayer:(CALayer *)layer asTrackID:(CMPersistentTrackID)trackID;

//將放在圖層 videoLayer 中的組合視頻幀同動畫圖層 animationLayer 中的內容一塊兒進行渲染,獲得最終的視頻幀
//一般,videoLayer 是 animationLayer 的子圖層,而 animationLayer 則不在任何圖層樹中
+ (instancetype)videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:(CALayer *)videoLayer inLayer:(CALayer *)animationLayer;

//複製 videoLayers 中的每個圖層,與 animationLayer一塊兒渲染獲得最中的幀
////一般,videoLayers 中的圖層都在 animationLayer 的圖層樹中,而 animationLayer 則不屬於任何圖層樹
+ (instancetype)videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayers:(NSArray<CALayer *> *)videoLayers inLayer:(CALayer *)animationLayer NS_AVAILABLE(10_9, 7_0);
複製代碼

1.3.5.8 AVVideoCompositionValidationHandling

  • 當咱們通過編輯後獲得一個視頻資源 asset ,而且爲該資源設置了自定義播放信息 video composition ,須要驗證對於這個 asset 而言,video composition 是否有效,能夠調用 AVVideoComposition 的校驗方法。
/* @param asset 設置第一個參數的校驗內容,設置 nil 忽略這些校驗 1. 該方法能夠校驗 AVVideoComposition 的屬性 instructions 是否符合要求 2. 校驗 instructions 中的每一個 AVVideoCompositionInstruction 對象的 layerInstructions 屬性中的 每個 AVVideoCompositionLayerInstruction 對象 trackID 值是否對應 asset 中 track 的 ID 或 AVVideoComposition 的 animationTool 實例 3. 校驗時間 asset 的時長是否與 instructions 中的時間範圍相悖 @param timeRange 設置第二個參數的校驗內容 1. 校驗 instructions 的全部的時間範圍是否在提供的 timeRange 的範圍內, 若要忽略該校驗,能夠傳參數 CMTimeRangeMake(kCMTimeZero, kCMTimePositiveInfinity) @param validationDelegate 設置遵循 AVVideoCompositionValidationHandling 協議的代理類,用來處理校驗過程當中的報錯,能夠爲 nil */
- (BOOL)isValidForAsset:(nullable AVAsset *)asset timeRange:(CMTimeRange)timeRange validationDelegate:(nullable id<AVVideoCompositionValidationHandling>)validationDelegate NS_AVAILABLE(10_8, 5_0);
複製代碼
  • 設置的代理對象要遵循協議 AVVideoCompositionValidationHandling ,該對象在實現下面的協議方法時,若修改了傳遞的 composition 參數,上面的校驗方法則會拋出異常。

  • 該協議提供瞭如下回調方法,全部方法的返回值用來肯定是否繼續進行校驗以獲取更多的錯誤。

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

//報告 videoComposition 中有時間段沒有相對應的 instruction
- (BOOL)videoComposition:(AVVideoComposition *)videoComposition shouldContinueValidatingAfterFindingEmptyTimeRange:(CMTimeRange)timeRange NS_AVAILABLE(10_8, 5_0);

//報告 videoComposition 中的 instructions 中 timeRange 無效的實例對象
//多是 timeRange 自己爲 CMTIMERANGE_IS_INVALID 
//或者是該時間段同上一個的 instruction 的 timeRange 重疊
//也多是其開始時間比上一個的 instruction 的 timeRange 的開始時間要早
- (BOOL)videoComposition:(AVVideoComposition *)videoComposition shouldContinueValidatingAfterFindingInvalidTimeRangeInInstruction:(id<AVVideoCompositionInstruction>)videoCompositionInstruction NS_AVAILABLE(10_8, 5_0);

//報告 videoComposition 中的 layer instruction 同調用校驗方法時指定的 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章節
  • AVFoundation使用組合從現有的媒體片斷(一般是一個或多個視頻和音頻軌道)建立新資產。您可使用可變組合來添加和刪除軌跡,並調整它們的時間順序。你也能夠設置音軌的相對音量和傾斜;設置視頻軌跡的不透明度和不透明度坡道。合成是存儲在內存中的媒體片斷的集合。當您使用導出會話導出一個組合時,它會摺疊成一個文件。您還可使用資產寫入器從媒體(例如示例緩衝區或靜態圖像)建立資產。
  • AVFoundation 框架中提供了豐富的接口用於視聽資源的編輯,其中的關鍵是 composition ,它將不一樣的 asset 相結合並造成一個新的 asset 。使用 AVMutableComposition 類能夠增刪 asset 來將指定的 asset 集合到一塊兒。除此以外,若想將集合到一塊兒的視聽資源以自定義的方式進行播放,須要使用 AVMutableAudioMixAVMutableVideoComposition類對其中的資源進行協調管理。最終要使用 AVAssetExportSession 類將編輯的內容保存到文件中。
  • AVFoundation框架提供了一組功能豐富的類,以方便編輯視聽資產。AVFoundation編輯API的核心是複合。組合就是來自一個或多個不一樣媒體資產的音軌集合。AVMutableComposition類提供了一個接口,用於插入和刪除軌跡,以及管理它們的時間順序。圖3-1顯示瞭如何將現有資產組合拼湊成新資產。若是您想作的只是將多個資產按順序合併到一個文件中,那麼這就是您所須要的所有細節。若是你想在你的做曲中對音軌進行任何自定義音頻或視頻處理,你須要分別合併一個音頻混合或一個視頻合成。

將現有資產組合拼湊成新資產

  • 使用AVMutableAudioMix類,您能夠在組合中的音頻軌道上執行自定義音頻處理,如圖3-2所示。目前,您能夠爲音軌指定最大音量或設置音量斜坡。

    音頻混合

  • 您可使用AVMutableVideoComposition類來直接編輯合成中的視頻軌跡,如圖3-3所示。對於單個視頻合成,您能夠爲輸出視頻指定所需的渲染大小和比例以及幀持續時間。經過視頻合成的指令(由AVMutableVideoCompositionInstruction類表示),您能夠修改視頻的背景顏色並應用層指令。這些層指令(由AVMutableVideoCompositionLayerInstruction類表示)可用於對組合中的視頻軌道應用轉換、轉換坡道、不透明度和不透明度坡道。video composition類還容許您使用animationTool屬性將核心動畫框架的效果引入到視頻中。

視頻合成

  • 要將組合與音頻和視頻組合組合在一塊兒,可使用AVAssetExportSession對象,如圖3-4所示。使用組合初始化導出會話,而後分別將音頻混合和視頻組合分配給audioMixvideoComposition屬性。

音視頻組合

1.4.1 AVAssetExportSession

  • 使用 AVAssetExportSession 類對視頻進行裁剪及轉碼,即將一個 AVAsset 類實例修改後保存爲另外一個 AVAsset 類實例,最後保存到文件中。
  • 在修改資源以前,爲避免不兼容帶來的錯誤,能夠先調用下面的方法,檢查預設置是否合理。
//獲取與 asset 兼容的預設置
+ (NSArray<NSString *> *)exportPresetsCompatibleWithAsset:(AVAsset *)asset;

//判斷提供的預設置和輸出的文件類型是否與 asset 相兼容
+ (void)determineCompatibilityOfExportPreset:(NSString *)presetName withAsset:(AVAsset *)asset outputFileType:(nullable NSString *)outputFileType completionHandler:(void (^)(BOOL compatible))handler NS_AVAILABLE(10_9, 6_0);
複製代碼
  • 除了設置文件類型外,還能夠設置文件的大小、時長、範圍等屬性,一切準備就緒後,調用方法:- (void)exportAsynchronouslyWithCompletionHandler:(void (^)(void))handler;

  • 進行文件的導出,導出結束後,會調用 handler 回調,在回調中應該檢查 AVAssetExportSession 的 status 屬性查看導出是否成功,若指定的文件保存地址在沙盒外,或在導出的過程當中有電話打入都會致使文件保存失敗,以下:

- (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 擁有多個 AVAssetTrack 同樣,做爲子類的 AVComposition 也擁有多個 AVCompositionTrack ,而 AVCompositionTrackAVAssetTrack 的子類。因此,AVComposition 實例對象是多個 track 的集合,真正描述媒體屬性的是 AVCompositionTrack 實例對象。而 AVCompositionTrack 又是媒體數據片斷的集合,這些數據片斷由 AVCompositionTrackSegment 類進行描述。

  • 該類的相關屬性和方法以下:

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

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

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

//根據不一樣的參數,獲取 composition 中的 track
- (nullable AVCompositionTrack *)trackWithTrackID:(CMPersistentTrackID)trackID;
- (NSArray<AVCompositionTrack *> *)tracksWithMediaType:(NSString *)mediaType;
- (NSArray<AVCompositionTrack *> *)tracksWithMediaCharacteristic:(NSString *)mediaCharacteristic;
複製代碼
  • 值得注意的是 AVComposition 類中並無提供初始化方法,通常咱們使用它的子類 AVMutableComposition ,進行各類操做後,再生成 AVComposition 實例以供查詢,以下:
AVMutableComposition *mutableComposition = [AVMutableComposition composition];

//進行添加資源等操做
<#····#>

//使用可變的 composition 生成一個不可變的 composition 以供使用
AVComposition *composition = [myMutableComposition copy];
AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithAsset:composition];
複製代碼

1.4.3 AVMutableComposition

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

//向 composition 中的全部 tracks 添加空的時間範圍
- (void)insertEmptyTimeRange:(CMTimeRange)timeRange;

//從 composition 的全部 tracks 中刪除一段時間,該操做不會刪除 track ,而是會刪除與該時間段相交的 track segment
- (void)removeTimeRange:(CMTimeRange)timeRange;

//改變 composition 中的全部的 tracks 的指定時間範圍的時長,該操做會改變 asset 的播放速度
- (void)scaleTimeRange:(CMTimeRange)timeRange toDuration:(CMTime)duration;
複製代碼
  • 從 composition 中獲取 track 或向其中添加/移除 track 方法以下:
//向 composition 中添加一個空的 track ,而且指定媒體資源類型及 trackID 屬性值
//若提供的參數 preferredTrackID 無效或爲 kCMPersistentTrackID_Invalid ,那麼惟一的 trackID 會自動生成
- (AVMutableCompositionTrack *)addMutableTrackWithMediaType:(NSString *)mediaType preferredTrackID:(CMPersistentTrackID)preferredTrackID;

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

//獲取一個與 asset track 相兼容的 composition track 
//爲了更好的性能,composition track 的數量應保持最小,這個數量與必需並行播放的媒體數據段數量以及媒體數據的類型相關
//對於可以線性執行且類型相同的媒體數據應使用同一個 composition track ,即便這些數據來自不一樣的 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 同樣是媒體資源的管理者,它實際是媒體資源數據的集合,它的屬性 segments 是 AVCompositionTrackSegment 類的實例對象集合,每一個對象描述一個媒體數據片斷。類 AVCompositionTrack 並不經常使用,一般使用的是它的子類 AVMutableCompositionTrack

1.4.5 AVMutableCompositionTrack

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

//當前 track 相關聯的語言編碼
@property (nonatomic, copy, nullable) NSString *languageCode;

//當前 track 相關聯的額外語言編碼
@property (nonatomic, copy, nullable) NSString *extendedLanguageTag;

//對於可顯示的媒體數據應優先選擇的仿射變換設置,默認值爲 CGAffineTransformIdentity
@property (nonatomic) CGAffineTransform preferredTransform;

//應優先選擇的音量,默認值爲 1
@property (nonatomic) float preferredVolume;

//當前track 所包含的全部的媒體數據片斷,對於這些片斷,它們構成了 track 的完整時間線,
//因此他們的時間線不能夠重疊,而且第一個數據片斷的時間從 kCMTimeZero 開始,依次日後的時間必須連續不間斷、不重疊
@property (nonatomic, copy, null_resettable) NSArray<AVCompositionTrackSegment *> *segments;
複製代碼
  • 當咱們獲取了一個 AVMutableCompositionTrack 實例對象後,即可以經過如下方法對其進行添加或移除數據片斷:
//將已存在的資源文件指定時間範圍的媒體數據插入到當前 composition 的指定時間處
//若是 startTime 爲 kCMTimeInvalid 值,那麼數據被添加到 composition 的最後
- (BOOL)insertTimeRange:(CMTimeRange)timeRange ofTrack:(AVAssetTrack *)track atTime:(CMTime)startTime error:(NSError * _Nullable * _Nullable)outError;

//這個方法與上述方法相似,只是能夠批量操做,可是注意提供的時間範圍不能重疊
- (BOOL)insertTimeRanges:(NSArray<NSValue *> *)timeRanges ofTracks:(NSArray<AVAssetTrack *> *)tracks atTime:(CMTime)startTime error:(NSError * _Nullable * _Nullable)outError NS_AVAILABLE(10_8, 5_0);

//插入一個沒有媒體數據的時間段,當這個範圍以前的媒體資源播放結束後,不會馬上播放以後的媒體數據,而是會靜默一段時間
- (void)insertEmptyTimeRange:(CMTimeRange)timeRange;

//移除一段時間範圍的媒體數據,該方法不會致使該 track 從 composition 中移除,只是移除與時間範圍相交的數據片斷
- (void)removeTimeRange:(CMTimeRange)timeRange;

//改變某個時間範圍內的時間的時長,實質是改變了媒體數據的播放速率
//其速率是原時長與現時長的比值,總之,媒體數據是要按時長播放的
- (void)scaleTimeRange:(CMTimeRange)timeRange toDuration:(CMTime)duration;

//判斷數據片斷的時間線是否重疊
- (BOOL)validateTrackSegments:(NSArray<AVCompositionTrackSegment *> *)trackSegments error:(NSError * _Nullable * _Nullable)outError;
複製代碼

1.4.6 AVAssetTrackSegment

  • 媒體資源 AVAsset 中的集合 AVAssetTrack 管理着單條時間線上的媒體數據片斷,而每一個數據片斷則由 AVAssetTrackSegment 類進行描述。
  • AVAssetTrackSegment 有兩個屬性:
  1. timeMapping 描述的是數據片斷在整個媒體文件中所處的時間範圍.timeMapping 是一個結構體,擁有兩個成員,對於編輯中的媒體數據片斷,它們分別表示數據在源文件中的位置和目標文件中的位置.
  2. empty 描述該數據片斷是否爲空,若是爲空,其 timeMapping.source.start 爲 kCMTimeInvalid

1.4.7 AVCompositionTrackSegment

  • 在編輯媒體文件時,在描述數據時,使用的是 AVAssetTrackSegment 的子類 AVCompositionTrackSegment ,它的主要屬性和方法以下:
//判斷數據片斷是否爲空,若爲空 timeMapping.target 可爲有效值,其餘爲未定義值
@property (nonatomic, readonly, getter=isEmpty) BOOL empty;

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

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

//建立對象,提供了數據片斷所在的文件、文件的描述 asset track 的 ID 、源文件中的數據時間範圍、目標文件中所處的時間範圍
//sourceTimeRange 與 targetTimeRange 的時間長度若是不一致,那麼播放的速率會改變
+ (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;

//建立僅有時間範圍而無實際媒體數據的實例
+ (instancetype)compositionTrackSegmentWithTimeRange:(CMTimeRange)timeRange;
- (instancetype)initWithTimeRange:(CMTimeRange)timeRange NS_DESIGNATED_INITIALIZER; 
複製代碼

1.5 AVFoundation 之 視音頻媒體捕獲

AVFoundation 媒體捕捉1

AVFoundation 媒體捕捉2

AVFoundation 媒體捕捉3

  • 攝像機和麥克風的記錄輸入由捕獲會話管理。捕獲會話協調從輸入設備到輸出(如電影文件)的數據流。您能夠爲單個會話配置多個輸入和輸出,甚至在會話運行時也是如此。向會話發送消息以啓動和中止數據流。此外,您可使用預覽層的實例向用戶顯示攝像機正在錄製的內容。

  • 更多關於視頻捕獲的詳情能夠參考蘋果官方文檔:Still and Video Media Capture章節

  • 要管理來自攝像機或麥克風等設備的捕獲,您須要組裝對象來表示輸入和輸出,並使用AVCaptureSession實例來協調它們之間的數據流。你須要最低限度:

  1. 表示輸入設備的AVCaptureDevice實例,如攝像機或麥克風
  2. AVCaptureInput的一個具體子類的實例,用於配置來自輸入設備的端口
  3. AVCaptureOutput的一個具體子類的實例,用於管理電影文件或靜態圖像的輸出
  4. AVCaptureSession的一個實例,用於協調從輸入到輸出的數據流
  • 要向用戶顯示攝像機記錄內容的預覽,可使用AVCaptureVideoPreviewLayer的一個實例(CALayer的一個子類)。

  • 您能夠配置多個輸入和輸出,由單個會話進行協調,如圖4-1所示:

    配置多個輸入和輸出,由單個會話進行協調

  • 對於許多應用程序,這是您須要的儘量多的細節。可是,對於某些操做(例如,若是但願監視音頻通道中的功率級別),須要考慮如何表示輸入設備的各個端口,以及如何將這些端口鏈接到輸出。

  • 捕獲會話中的捕獲輸入和捕獲輸出之間的鏈接由AVCaptureConnection對象表示。捕獲輸入(AVCaptureInput的實例)有一個或多個輸入端口(AVCaptureInputPort的實例)。捕獲輸出(AVCaptureOutput的實例)能夠接受來自一個或多個源的數據(例如,AVCaptureMovieFileOutput對象同時接受視頻和音頻數據)。

  • 當您將輸入或輸出添加到會話時,會話將在全部兼容的捕獲輸入端口和捕獲輸出之間造成鏈接,如圖4-2所示。捕獲輸入和捕獲輸出之間的鏈接由AVCaptureConnection對象表示。

AVCaptureConnection表示輸入和輸出之間的鏈接

  • 您可使用捕獲鏈接來啓用或禁用來自給定輸入或到給定輸出的數據流。您還可使用鏈接來監視音頻通道中的平均和峯值功率級別。

  • 經過麥克風、攝像機等設備,能夠捕獲外界的聲音和影像。要處理設備捕獲的數據,須要使用 AVCaptureDevice 類描述設備,使用 AVCaptureInput 配置數據從設備的輸入,使用 AVCaptureOutput 類管理數據到文件的寫入,而數據的輸入到寫出,須要使用 AVCaptureSession 類進行協調。此外,可使用 AVCaptureVideoPreviewLayer 類顯示相機正在拍攝的畫面。

  • 一個設備能夠有多個輸入,使用 AVCaptureInputPort 類描述這些輸入,用 AVCaptureConnection 類描述具體類型的輸入與輸出的關係,能夠實現更精細的數據處理。

1.5.1 AVCaptureSession

  • `AVCaptureSession 是捕獲視聽數據的核心類,它協調數據的輸入和輸出。建立一個 AVCaptureSession 類的對象時,能夠指定最終獲得的視聽數據的質量,固然這個質量與設備也有關係,一般在設置以前,能夠調用方法判斷 session 是否支持要設置的質量。

  • AVCaptureSession 類實例可設置的數據質量有 AVCaptureSessionPresetHighAVCaptureSessionPresetMediumAVCaptureSessionPresetLowAVCaptureSessionPreset320x240 等。在進行設置以前,能夠調用 AVCaptureSession 中的方法進行校驗。

- (BOOL)canSetSessionPreset:(NSString*)preset;
複製代碼
  • 設置好對象後,可調用下面的方法,添加、移除輸入、輸出。
- (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);
複製代碼
  • 開始執行 session 或者結束執行,調用下面的方法:
- (void)startRunning;
- (void)stopRunning;
複製代碼
  • 對於正在執行中的 session ,要對其進行改變,所做出的改變,應放在下面兩個方法之間。
- (void)beginConfiguration;
- (void)commitConfiguration;
複製代碼
  • AVCaptureSession 開始執行、結束執行、執行過程當中出錯或被打斷時,都會發出通知,經過註冊下面的通知,能夠獲取咱們感興趣的信息。
  1. VCaptureSessionRuntimeErrorNotification 經過 AVCaptureSessionErrorKey 能夠獲取出錯的緣由
  2. AVCaptureSessionDidStartRunningNotification 開始 session
  3. AVCaptureSessionDidStopRunningNotification 結束 session
  4. AVCaptureSessionWasInterruptedNotification 經過 AVCaptureSessionInterruptionReasonKey 能夠獲取被打斷的緣由
  5. AVCaptureSessionInterruptionEndedNotification 打斷結束,session 從新開始

1.5.2 AVCaptureDevice

  • AVCaptureDevice是用來描述設備屬性的類,要捕獲視聽數據,須要獲取相應的設備,使用該類獲取有效的設備資源。這個設備資源列表是隨時變更的,其在變更時,會發送AVCaptureDeviceWasConnectedNotificationAVCaptureDeviceWasDisconnectedNotification 通知,以告知有設備鏈接或斷開。

  • 在獲取設備以前,要先肯定要獲取的設備的類型 AVCaptureDeviceType ,設備的位置 AVCaptureDevicePosition ,也能夠經過要獲取的媒體數據類型進行設備的選擇。

  • 獲取設備後,能夠保存它的惟一標識、模型標識、名稱等信息,以待下次用來獲取設備。

+ (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;

//校驗得到的設備可否提供相應的媒體數據類型
- (BOOL)hasMediaType:(NSString *)mediaType;

//校驗得到的設備可否支持相應的配置
- (BOOL)supportsAVCaptureSessionPreset:(NSString *)preset;

複製代碼
  • 獲取一個設備後,能夠經過修改它的屬性來知足本身的須要。
  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)
  • 在修改這些屬性時,應先判斷當前設備是否支持要設置的屬性值,而且全部的屬性修改都要放在下面兩個方法之間,以保證屬性可以被正確設置。
- (BOOL)lockForConfiguration:(NSError **)outError;
- (void)unlockForConfiguration;
複製代碼
  • 在調用硬件設備以前,應先判斷應用是否擁有相應的權限,其權限分爲如下幾種:
  1. AVAuthorizationStatusNotDetermined 未定義
  2. AVAuthorizationStatusRestricted 無權限(因某些緣由,系統拒絕權限)
  3. AVAuthorizationStatusDenied 無權限(用戶拒絕)
  4. AVAuthorizationStatusAuthorized 有權限
//校驗權限
+ (AVAuthorizationStatus)authorizationStatusForMediaType:(NSString *)mediaType NS_AVAILABLE_IOS(7_0);

//請求權限,handler 處理會在任意線程中執行,因此須要在主線程中執行的處理由用戶負責指定
+ (void)requestAccessForMediaType:(NSString *)mediaType completionHandler:(void (^)(BOOL granted))handler NS_AVAILABLE_IOS(7_0);
複製代碼

1.5.3 AVCaptureDeviceInput

  • AVCaptureDeviceInputAVCaptureInput 的子類,使用一個 AVCaptureDevice 類實例建立該類的實例,其管理設備的輸入。
  • 在建立了實例對象後,將其添加到 session 中。
NSError *error;
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (input && [session canAddInput:input]) {
    [captureSession addInput:captureDeviceInput];
}
複製代碼

1.5.4 AVCaptureOutput

  • AVCaptureOutput 是一個抽象類,一般使用的是它的子類
  1. AVCaptureMovieFileOutput 用來生成一個影視文件
  2. AVCaptureVideoDataOutput 用來處理輸入的視頻的幀
  3. AVCaptureAudioDataOutput 用來處理音頻數據
  4. AVCaptureStillImageOutput 用來獲取圖片
  • 在建立了具體的子類後,將它添加到 session 中
AVCaptureMovieFileOutput *movieOutput = [[AVCaptureMovieFileOutput alloc] init];
if ([session canAddOutput:movieOutput]) {
    [session addOutput:movieOutput];
}
複製代碼

1.5.5 AVCaptureFileOutput

  • AVCaptureFileOutputAVCaptureOutput 的子類,是 AVCaptureMovieFileOutputAVCaptureAudioFileOutput 的父類。這個類中定義了文件輸出時的地址、時長、容量等屬性。
//當前記錄的數據的文件的地址
@property(nonatomic, readonly) NSURL *outputFileURL;

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

//該方法能夠中止數據向文件中寫入
//若是要中止一個文件的寫入轉而指定另外一個文件的寫入,不該調用該方法,只需直接調用上面的方法
//當因該方法的調用、出錯、或寫入文件的變動致使當前文件開始中止寫入時,最後傳入的緩存數據仍會在後臺被寫入
//不管什麼時候,要使用文件,都須要等指定的代理對象被告知文件的寫入已經結束以後進行
- (void)stopRecording;

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

//表示到目前爲止,當前文件已經記錄了多長時間
@property(nonatomic, readonly) CMTime recordedDuration;

//表示到目前爲止,當前文件已經記錄了多少個字節
@property(nonatomic, readonly) int64_t recordedFileSize;    
/** 下面三個值對文件的記錄進行了限制,若果達到限制,則會在回調方法 captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error: 中傳遞相應的錯誤 */
//表示當前文件可以記錄的最長時間,kCMTimeInvalid 表示無時間限制
@property(nonatomic) CMTime maxRecordedDuration;

//表示當前文件可以記錄的最大字節數,0 表示無大小限制
@property(nonatomic) int64_t maxRecordedFileSize;

//表示記錄當前文件時須要保留的最小字節數
@property(nonatomic) int64_t minFreeDiskSpaceLimit;

//在 Mac OS X 系統下,經過指定遵循 AVCaptureFileOutputDelegate 協議的代理對象,來實現緩存數據的精確記錄
@property(nonatomic, assign) id<AVCaptureFileOutputDelegate> delegate NS_AVAILABLE(10_7, NA);

/** 在 Mac OS X 系統下,這個屬性和方法能夠判斷記錄是否中止,以及控制數據向文件中的中止寫入和從新開始寫入 */
@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 是文件記錄過程當中須要用到的協議,它一般的做用是告知代理對象文件記錄結束了。
//這個代理方法是遵循該協議的代理對象必需要實現的方法
//每個文件記錄請求,最終都會調用這個方法,即便沒有數據成功寫入文件
//當 error 返回時,文件也可能成功保存了,應檢查 error 中的 AVErrorRecordingSuccessfullyFinishedKey 信息,查看具體錯誤
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error;

//當數據寫入文件後調用,若是數據寫入失敗,該方法可能不會被調用
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections;

/** 在 Mac OS X 系統下,當文件的記錄被暫停或從新開始,會調用下面的方法,若是記錄被終止,不會調用下面的方法 */
- (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 系統下,當記錄將被中止,不管是主動的仍是被動的,都會調用下面的方法
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput willFinishRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections error:(NSError *)error NS_AVAILABLE(10_7, NA);
複製代碼

1.5.7 AVCaptureFileOutputDelegate

  • AVCaptureFileOutputDelegate 這個協議只用於 Mac OS X 系統下,它給了客戶端精準操控數據的機會。
/** 在 Mac OS X 10.8 系統以前,實現代理方法 captureOutput:didOutputSampleBuffer:fromConnection: 後即可以在該方法中實現數據記錄的準確開始或結束,而要實如今任一一個畫面幀處開始或中止數據的記錄,要對每收到的 幀數據進行預先處理,這個過程消耗電能、產生熱量、佔用 CPU 資源,因此在 Mac OS X 10.8 及其以後的系統,提供了 下面的代理方法,來肯定客戶端需不須要隨時進行記錄的開始或中止。 若是這個方法返回 NO ,對數據記錄的設置將在開啓記錄以後進行。 */
- (BOOL)captureOutputShouldProvideSampleAccurateRecordingStart:(AVCaptureOutput *)captureOutput NS_AVAILABLE(10_8, NA);

/** 若是上面的方法返回了 YES ,那麼客戶端即可以使用下面的方法對每個視頻幀數據或音頻數據進行操做 爲了提升性能,緩存池中的緩存變量的內存一般會被複用,若是長時間使用緩存變量,那麼新的緩存數據沒法複製到 相應的內存中便會被廢棄,因此若須要長時間使用緩存數據 sampleBuffer ,應複製一份,使其自己可以被系統複用 */
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection NS_AVAILABLE(10_7, NA);
複製代碼

1.5.8 AVCaptureAudioFileOutput

  • AVCaptureAudioFileOutput 是 AVCaptureFileOutput 的子類,該類用於將媒體數據記錄爲一個音頻文件。
//返回該類支持的音頻文件類型
+ (NSArray *)availableOutputFileTypes;

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

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

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

1.5.9 AVCaptureVideoDataOutput

  • AVCaptureVideoDataOutputAVCaptureOutput 的子類,該類能夠用來處理捕獲的每個視頻幀數據。建立一個該類的實例對象後,要調用下面的方法設置一個代理對象,及調用代理對象所實現的協議方法的隊列。
- (void)setSampleBufferDelegate:(id<AVCaptureVideoDataOutputSampleBufferDelegate>)sampleBufferDelegate queue:(dispatch_queue_t)sampleBufferCallbackQueue;
複製代碼
  • 指定的隊列 sampleBufferCallbackQueue 必需是串行隊列以保證傳遞的幀是按記錄時間前後傳遞的。
//設置輸出的視頻要進行怎樣的格式處理
//設置爲空([NSDictionary dictionary])表示不改變輸入時的視頻格式
//設置爲 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);

//表示當回調隊列阻塞時,是否馬上丟棄新接收的幀數據
@property(nonatomic) BOOL alwaysDiscardsLateVideoFrames;
複製代碼

1.5.10 AVCaptureVideoDataOutputSampleBufferDelegate

  • 該協議用來處理接收的每個幀數據,或者提示客戶端有幀數據被丟棄。
//接收到一個幀數據時,在指定的串行隊列中調用該方法,攜帶幀數據幷包含有其餘幀信息
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection;

//丟棄一個幀數據時,在指定的串行隊列中調用該方法,sampleBuffer 只攜帶幀信息,具體幀數據並未攜帶
- (void)captureOutput:(AVCaptureOutput *)captureOutput didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection NS_AVAILABLE(10_7, 6_0);
複製代碼

1.5.11 AVCaptureVideoPreviewLayer

  • AVCaptureVideoPreviewLayerCALayer 的子類,使用該類能夠實現捕獲視頻的顯示。使用一個 session 建立一個該類對象,然後將該類對象插入到圖層樹中,從而顯示捕獲的視頻。
//建立方法
+ (instancetype)layerWithSession:(AVCaptureSession *)session;
- (instancetype)initWithSession:(AVCaptureSession *)session;
複製代碼
  • 修改 AVCaptureVideoPreviewLayer 的屬性 videoGravity 值,能夠選擇顯示捕獲視頻時的界面大小變化方式,它有如下可選值:
  1. AVLayerVideoGravityResize 默認值,直接鋪滿屏幕,及時畫面變形
  2. AVLayerVideoGravityResizeAspect 保持畫面的橫縱比,不鋪滿屏幕,多餘的空間顯示黑色
  3. AVLayerVideoGravityResizeAspectFill 保持畫面的橫縱比,鋪滿屏幕,多餘的畫面進行裁剪

1.5.12 AVCaptureAudioDataOutput

  • AVCaptureAudioDataOutputAVCaptureOutput 的子類,該類能夠處理接收到的音頻數據。同 AVCaptureVideoDataOutput 相似,該類也提供了一個方法,用於設置代理對象,以及調用代理對象實現的協議方法時的隊列。
- (void)setSampleBufferDelegate:(id<AVCaptureAudioDataOutputSampleBufferDelegate>)sampleBufferDelegate queue:(dispatch_queue_t)sampleBufferCallbackQueue;
複製代碼

1.5.13 AVCaptureAudioDataOutputSampleBufferDelegate

  • 該協議提供了一個方法,用來實現對音頻數據的接收處理。
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection;

複製代碼

1.5.14 AVAssetImageGenerator

  • 使用 AVAssetImageGenerator 生成視頻資源的縮略圖,使用 AVAsset 對象建立 AVAssetImageGenerator 對象,可使用類方法或實例方法,以下:
+ (instancetype)assetImageGeneratorWithAsset:(AVAsset *)asset;
- (instancetype)initWithAsset:(AVAsset *)asset NS_DESIGNATED_INITIALIZER;

複製代碼
  • 固然,在此以前,最好調用 AVAsset 中的方法 - (NSArray<AVAssetTrack *> *)tracksWithMediaCharacteristic:(NSString *)mediaCharacteristic; 來判斷 asset 中是否有可視媒體數據。若是有,那麼再建立 AVAssetImageGenerator 對象,然後再調用下面的方法,來獲取一張或多張圖片。
//獲取一張圖片,requestedTime 指定要獲取視頻中哪一個時刻的圖片,actualTime 返回圖片實際是視頻的哪一個時刻,outError 返回錯誤信息
- (nullable CGImageRef)copyCGImageAtTime:(CMTime)requestedTime actualTime:(nullable CMTime *)actualTime error:(NSError * _Nullable * _Nullable)outError CF_RETURNS_RETAINED;

//獲取多張圖片,每一次圖片生成後,都會調用一次 handler
- (void)generateCGImagesAsynchronouslyForTimes:(NSArray<NSValue *> *)requestedTimes completionHandler:(AVAssetImageGeneratorCompletionHandler)handler;

//上述 handler 的類型以下,回調中的參數有圖片的請求時刻和實際時刻,圖片,狀態(成功、失敗、取消),錯誤信息
typedef void (^AVAssetImageGeneratorCompletionHandler)(CMTime requestedTime, CGImageRef _Nullable image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * _Nullable error);
複製代碼

1.6 AVFoundation 之媒體流輸出

AVFoundation 視頻音頻輸出

  • 對媒體數據資源進行簡單的轉碼或裁剪,使用 AVAssetExportSession 類便足夠了,可是更深層次的修改媒體資源,便須要用到 AVAssetReader 類和 AVAssetWriter 類。
  • AVAssetReader 只能與一個資源 asset 相關聯,且不能用來讀取實時數據,在開始讀取數據以前,須要爲 reader 添加 AVAssetReaderOutput 的實例對象。這個實例對象描述的是待讀取的數據資源來源類型,一般使用 AVAssetReaderAudioMixOutputAVAssetReaderTrackOutputAVAssetReaderVideoCompositionOutput 三種子類。
  • AVAssetWriter 能夠未來自多個數據源的數據以指定的格式寫入到一個指定的文件中,且其只能對應一個文件。在寫文件以前,須要用每個 AVAssetWriterInput 類實例對象來描述相應的數據源。每個 AVAssetWriterInput 實例對象接收的數據都應是 CMSampleBufferRef 類型的變量。若是使用 AVAssetWriterInputPixelBufferAdaptor 類也能夠直接將 CVPixelBufferRef 類型的變量數據添加到 writer input 中。
  • AVAssetReaderAVAssetWriter 結合起來使用,即可以對讀取的數據進行相應的編輯修改,然後寫入到一個文件中並保存。

1.6.1 AVAssetReader

  • 使用該類讀取媒體資源,其提供的初始化方法與一個 asset 相關聯。
//對於提供的參數 asset ,若是是可被修改的,那麼在開始讀取操做後,對其進行了修改,以後的讀取操做都是無效的
+ (nullable instancetype)assetReaderWithAsset:(AVAsset *)asset error:(NSError * _Nullable * _Nullable)outError;
- (nullable instancetype)initWithAsset:(AVAsset *)asset error:(NSError * _Nullable * _Nullable)outError NS_DESIGNATED_INITIALIZER;

//當前讀取操做的狀態,可取值有 AVAssetReaderStatusUnknown 、AVAssetReaderStatusReading 、
AVAssetReaderStatusCompletedAVAssetReaderStatusFailedAVAssetReaderStatusCancelled
@property (readonly) AVAssetReaderStatus status;
//當 status 的值爲 AVAssetReaderStatusFailed 時,描述錯誤信息
@property (readonly, nullable) NSError *error;


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

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

//開始讀取
- (BOOL)startReading;
//結束讀取
- (void)cancelReading;
複製代碼

1.6.2 AVAssetReaderOutput

  • AVAssetReaderOutput 是用來描述待讀取的數據的抽象類,讀取資源時,應建立該類的對象,並添加到相應的 AVAssetReader 實例對象中去。
//獲取的媒體數據的類型
@property (nonatomic, readonly) NSString *mediaType;

//是否拷貝緩存中的數據到客戶端,默認 YES ,客戶端能夠隨意修改數據,可是爲優化性能,一般設爲 NO
@property (nonatomic) BOOL alwaysCopiesSampleData NS_AVAILABLE(10_8, 5_0);

//同步獲取下一個緩存數據,使用返回的數據結束後,應使用 CFRelease 函數將其釋放
//當錯誤或沒有數據可讀取時,返回 NULL ,返回空後,應檢查相關聯的 reader 的狀態
- (nullable CMSampleBufferRef)copyNextSampleBuffer CF_RETURNS_RETAINED;

//是否支持從新設置數據的讀取時間範圍,即可否修改 reader 的 timeRange 屬性
@property (nonatomic) BOOL supportsRandomAccess NS_AVAILABLE(10_10, 8_0);
//設置從新讀取的時間範圍,這個時間範圍集合中的每個時間範圍的開始時間必需是增加的且各個時間範圍不能重疊
//應在 reader 調用 copyNextSampleBuffer 方法返回 NULL 以後纔可調用
- (void)resetForReadingTimeRanges:(NSArray<NSValue *> *)timeRanges NS_AVAILABLE(10_10, 8_0);
//該方法調用後,上面的方法即不可再調用,同時 reader 的狀態也不會被阻止變爲 AVAssetReaderStatusCompleted 了
- (void)markConfigurationAsFinal NS_AVAILABLE(10_10, 8_0);
複製代碼

1.6.3 AVAssetReaderTrackOutput

  • AVAssetReaderTrackOutputAVAssetReaderOutput 的子類,它用來描述待讀取的數據來自 asset track ,在讀取前,還能夠對數據的格式進行修改。
//初始化方法,參數中指定了 track 和 媒體的格式
//指定的 track 應在 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;

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

1.6.4 AVAssetReaderAudioMixOutput

  • AVAssetReaderAudioMixOutputAVAssetReaderOutput 的子類,它用來描述待讀取的數據來自音頻組合數據。建立該類實例對象提供的參數 audioTracks 集合中的每個 asset track 都屬於相應的 reader 中的 asset 實例對象,且類型爲 AVMediaTypeAudio 。
  • 參數 audioSettings 給出了音頻數據的格式設置。
+ (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 屬性,描述了從多個 track 中讀取的音頻的音量變化狀況:@property (nonatomic, copy, nullable) AVAudioMix *audioMix;

1.6.5 AVAssetReaderVideoCompositionOutput

  • AVAssetReaderVideoCompositionOutputAVAssetReaderOutput 的子類,該類用來表示要讀取的類是組合的視頻數據。 同 AVAssetReaderAudioMixOutput 相似,該類也提供了兩個建立實例的方法,須要提供的參數的 videoTracks 集合中每個 track 都是 與 reader 相關聯的 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 一樣描述了每一個 track 的幀的顯示方式。
@property (nonatomic, copy, nullable) AVVideoComposition *videoComposition;
複製代碼

1.7 AVFoundation 之媒體的時間和數據

AVFoundation 媒體的時間與數據

相關文章
相關標籤/搜索