日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

IOS音视频(一)AVFoundation核心类

發布時間:2024/3/13 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 IOS音视频(一)AVFoundation核心类 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

IOS音視頻(一)AVFoundation核心類

  • 1. AVFoundation框架架構簡介
    • 1.1 AVFoundation框架
    • 1.2 AVFoundation 之 Assets
    • 1.3 AVFoundation 之 視頻播放
      • 1.3.1 AVPlayer
      • 1.3.2 播放不同類型的資源
      • 1.3.3 播放控制
      • 1.3.4 自定義播放--音頻
        • 1.3.4.1 AVAudioMix
        • 1.3.4.2 AVMutableAudioMix
        • 1.3.4.3 AVAudioMixInputParameters
        • 1.3.4.4 AVMutableAudioMixInputParameters
      • 1.3.5 自定義播放--視頻
        • 1.3.5.1 AVVideoComposition
        • 1.3.5.2 AVMutableVideoComposition
        • 1.3.5.3 AVVideoCompositionInstruction
        • 1.3.5.4 AVMutableVideoCompositionInstruction
        • 1.3.5.5 AVVideoCompositionLayerInstruction
        • 1.3.5.6 AVMutableVideoCompositionLayerInstruction
        • 1.3.5.7 AVVideoCompositionCoreAnimationTool
        • 1.3.5.8 AVVideoCompositionValidationHandling
        • 1.3.5.9 AVVideoCompositionValidationHandling
    • 1.4 AVFoundation 之 視音頻編輯
      • 1.4.1 AVAssetExportSession
      • 1.4.2 AVComposition
      • 1.4.3 AVMutableComposition
      • 1.4.4 AVCompositionTrack
      • 1.4.5 AVMutableCompositionTrack
      • 1.4.6 AVAssetTrackSegment
      • 1.4.7 AVCompositionTrackSegment
    • 1.5 AVFoundation 之 視音頻媒體捕獲
      • 1.5.1 AVCaptureSession
      • 1.5.2 AVCaptureDevice
      • 1.5.3 AVCaptureDeviceInput
      • 1.5.4 AVCaptureOutput
      • 1.5.5 AVCaptureFileOutput
      • 1.5.6 AVCaptureFileOutputRecordingDelegate
      • 1.5.7 AVCaptureFileOutputDelegate
      • 1.5.8 AVCaptureAudioFileOutput
      • 1.5.9 AVCaptureVideoDataOutput
      • 1.5.10 AVCaptureVideoDataOutputSampleBufferDelegate
      • 1.5.11 AVCaptureVideoPreviewLayer
      • 1.5.12 AVCaptureAudioDataOutput
      • 1.5.13 AVCaptureAudioDataOutputSampleBufferDelegate
      • 1.5.14 AVAssetImageGenerator
    • 1.6 AVFoundation 之媒體流輸出
      • 1.6.1 AVAssetReader
      • 1.6.2 AVAssetReaderOutput
      • 1.6.3 AVAssetReaderTrackOutput
      • 1.6.4 AVAssetReaderAudioMixOutput
      • 1.6.5 AVAssetReaderVideoCompositionOutput
    • 1.7 AVFoundation 之媒體的時間和數據

  • 做音視頻開發是個很復雜的工作,需要我們理解很多有關素材的知識:聲學和視覺相關的科學理論,數的程序開發技術和有AVFoundation框架而引出的其他框架的知識,比如:Core Media, Core Video, Core Image, Core Audio, Media Player 和 VideoToolbox 等等。

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

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

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

1. AVFoundation框架架構簡介

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

  • Core Audio

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

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

  • Core Media

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

  • Core Animation

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

  • 蘋果提供了AVFoundation框架,可以用來檢測,編輯,創建,重新編碼媒體文件,還可以實時獲取設備的流媒體數據,實時操作這些被捕獲的視頻流數據。
  • 蘋果推薦我們盡可能的使用高度抽象的接口:
  • 如果只是簡單播放視頻文件,使用AVKit框架即可。
  • 如果只是想簡單錄制視頻,使用UIKit框架里的UIImagePickerController既可以實現。
    • AVFoundation 框架包含視頻相關的接口以及音頻相關的接口,與音頻相關的類有 AVAudioPlayer、AVAudioRecorder、AVAudioSession。

    1.1 AVFoundation框架

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

    • 音頻播放和記錄——AVAudioPlayer 和 AVAudioRecorder
    • 媒體文件檢查——AVMetadataItem
    • 視頻播放——AVPlayer 和 AVPlayerItem
    • 媒體捕捉——AVCaptureSession
    • 媒體編輯
    • 媒體處理——AVAssetReader、AVAssetWriter

    • 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

    • 參考蘋果官方介紹

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

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

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

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

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

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

    • 您可以使用CMTimeMake或CMTimeMakeWithSeconds等相關函數之一創建時間(該函數允許您使用浮點值創建時間并指定首選時間刻度)。有幾個函數用于基于時間的算術和比較時間,如下例所示:

    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://TODObreak;case AVKeyValueStatusLoading://TODObreak;case AVKeyValueStatusLoaded://TODObreak;case AVKeyValueStatusFailed://TODObreak;case AVKeyValueStatusCancelled://TODObreak;} }];

    1.3 AVFoundation 之 視頻播放


    1.3.1 AVPlayer

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

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

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

    • 播放器向您提供有關播放狀態的信息,因此,如果需要,您可以將用戶界面與播放器的狀態同步。通常將播放器的輸出定向到特定的核心動畫層(AVPlayerLayer或AVSynchronizedLayer的實例)。有關層的更多信息,請參見Core Animation Programming Guide。

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

    • 這種抽象意味著您可以同時使用不同的玩家來玩給定的資產,但是每個玩家呈現的方式不同。圖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 后,AVAsset 和 AVAssetTrack 對象將由 item 對象創建。

    1.3.3 播放控制

    • 通過調用 player 的 play 、pause 、setRate: 方法,可以控制 item 的播放,這些方法都會改變 player 的屬性 rate 的值,該值為 1 表示 item 按正常速率播放,為 0 表示 item 暫停播放,0~1 表示低速播放,大于 1 表示高速播放,小于 0 表示從后向前播放。
    • item 的屬性 timeControlStatus 的值表示當前 item 的狀態,有下面 3 個值:
  • AVPlayerTimeControlStatusPaused 暫停
  • AVPlayerTimeControlStatusPlaying 播放
  • AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate 等待按指定速率播放狀態,該狀態是當 rate 的值設置為非 0 值時,而 item 因某些原因還無法播放的情況,而無法播放的原因,可依通過 item 的 reasonForWaitingToPlay 屬性值查看。
    • item 的屬性 actionAtItemEnd 的值表示當前 item 播放結束后的動作,有下面 3 個值:
  • AVPlayerActionAtItemEndAdvance 只適用于 AVQueuePlayer 類,表示播放隊列中的下一個 item
  • AVPlayerActionAtItemEndPause 表示暫停
  • 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

    • AVMutableAudioMix 是 AVAudioMix 的子類,它的方法 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 *)assetapplyingCIFiltersWithHandler:(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

    • 在自定義視頻播放時,可能需要添加水印、標題或者其他的動畫效果,需要使用該類。該類通常用來協調離線視頻中圖層與動畫圖層的組合(如使用 AVAssetExportSession 和 AVAssetReader 、AVAssetReader 類導出視頻文件或讀取視頻文件時),而若是在線實時的視頻播放,應使用 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 之 視音頻編輯

    • 詳情可以參考蘋果官方文檔:Editing章節
    • AVFoundation使用組合從現有的媒體片段(通常是一個或多個視頻和音頻軌道)創建新資產。您可以使用可變組合來添加和刪除軌跡,并調整它們的時間順序。你也可以設置音軌的相對音量和傾斜;設置視頻軌跡的不透明度和不透明度坡道。合成是存儲在內存中的媒體片段的集合。當您使用導出會話導出一個組合時,它會折疊成一個文件。您還可以使用資產寫入器從媒體(例如示例緩沖區或靜態圖像)創建資產。
    • AVFoundation 框架中提供了豐富的接口用于視聽資源的編輯,其中的關鍵是 composition ,它將不同的 asset 相結合并形成一個新的 asset 。使用 AVMutableComposition 類可以增刪 asset 來將指定的 asset 集合到一起。除此之外,若想將集合到一起的視聽資源以自定義的方式進行播放,需要使用 AVMutableAudioMix 和 AVMutableVideoComposition類對其中的資源進行協調管理。最終要使用 AVAssetExportSession 類將編輯的內容保存到文件中。
    • AVFoundation框架提供了一組功能豐富的類,以方便編輯視聽資產。AVFoundation編輯API的核心是復合。組合就是來自一個或多個不同媒體資產的音軌集合。AVMutableComposition類提供了一個接口,用于插入和刪除軌跡,以及管理它們的時間順序。圖3-1顯示了如何將現有資產組合拼湊成新資產。如果您想做的只是將多個資產按順序合并到一個文件中,那么這就是您所需要的全部細節。如果你想在你的作曲中對音軌進行任何自定義音頻或視頻處理,你需要分別合并一個音頻混合或一個視頻合成。

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

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

    • 要將組合與音頻和視頻組合組合在一起,可以使用AVAssetExportSession對象,如圖3-4所示。使用組合初始化導出會話,然后分別將音頻混合和視頻組合分配給audioMix和videoComposition屬性。

    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:AVAssetExportPresetHighestQualitywithAsset:anAssetoutputFileType:AVFileTypeMPEG4completionHandler:^(BOOL compatible) {if (compatible){AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:anAssetpresetName: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 ,而 AVCompositionTrack 是 AVAssetTrack 的子類。所以,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

    • AVMutableComposition 是 AVComposition 的子類,其包含的 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 有兩個屬性:
  • timeMapping 描述的是數據片段在整個媒體文件中所處的時間范圍.timeMapping 是一個結構體,擁有兩個成員,對于編輯中的媒體數據片段,它們分別表示數據在源文件中的位置和目標文件中的位置.
  • 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 之 視音頻媒體捕獲

    • 數字媒體采樣

    將現實世界的模擬信號轉換為能夠被計算機存儲和傳輸的數字信號,需要經過模擬-數字轉換過程,也稱為采樣。數字化采樣有兩種方式,一種是時間采樣,即捕捉一個信號周期內的變化,一種是空間采樣,一般用于圖片數字化和其他可視化媒體內容數字化上,它對一個圖片在一定分辨率下捕捉其亮度和色度,進而創建出由該圖片的像素點數據所構成的數字化結果。視頻既有空間屬性又有時間屬性,所以數字化時都可以使用。

    • 音頻采樣

    對于一個音頻,麥克風負責將物理振動轉化為相同頻率和振幅的電流信號,之后通過線性脈沖編碼調制(LPCM)進行編碼。LPCM 采樣或測量一個固定的音頻信號,其周期率被稱為采樣率。采樣頻率達到奈奎斯特頻率(采樣對象最高頻率的 2 倍)時即可準確表現原始信號的信息。另一方面編碼字節數(也稱位元深度)表現了采樣精度,如位元深度為 8 位的編碼能夠提供 256 個離散級別的數據,CD 音質位元深度為 16

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

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

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

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

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

    • 對于許多應用程序,這是您需要的盡可能多的細節。但是,對于某些操作(例如,如果希望監視音頻通道中的功率級別),需要考慮如何表示輸入設備的各個端口,以及如何將這些端口連接到輸出。

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

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

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

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

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

    1.5.1 AVCaptureSession

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

    • AVCaptureSession 類實例可設置的數據質量有 AVCaptureSessionPresetHigh 、AVCaptureSessionPresetMedium 、AVCaptureSessionPresetLow 、AVCaptureSessionPreset320x240 等。在進行設置之前,可以調用 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 開始執行、結束執行、執行過程中出錯或被打斷時,都會發出通知,通過注冊下面的通知,可以獲取我們感興趣的信息。
  • VCaptureSessionRuntimeErrorNotification 通過 AVCaptureSessionErrorKey 可以獲取出錯的原因
  • AVCaptureSessionDidStartRunningNotification 開始 session
  • AVCaptureSessionDidStopRunningNotification 結束 session
  • AVCaptureSessionWasInterruptedNotification 通過 AVCaptureSessionInterruptionReasonKey 可以獲取被打斷的原因
  • AVCaptureSessionInterruptionEndedNotification 打斷結束,session 重新開始
  • 1.5.2 AVCaptureDevice

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

    • 在獲取設備之前,要先確定要獲取的設備的類型 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;
    • 獲取一個設備后,可以通過修改它的屬性來滿足自己的需要。
  • flashMode 閃光燈的模式(AVCaptureFlashModeOff 、AVCaptureFlashModeOn 、AVCaptureFlashModeAuto)
  • torchMode 手電筒的模式(AVCaptureTorchModeOff 、AVCaptureTorchModeOn 、AVCaptureTorchModeAuto)
    torchLevel 手電筒的亮度(0~1)
  • focusMode 聚焦模式(AVCaptureFocusModeLocked 、AVCaptureFocusModeAutoFocus 、AVCaptureFocusModeContinuousAutoFocus)
  • exposureMode 曝光模式(AVCaptureExposureModeLocked 、AVCaptureExposureModeAutoExpose 、AVCaptureExposureModeContinuousAutoExposure 、AVCaptureExposureModeCustom)
  • whiteBalanceMode 白平衡模式(AVCaptureWhiteBalanceModeLocked 、AVCaptureWhiteBalanceModeAutoWhiteBalance 、AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance)
    • 在修改這些屬性時,應先判斷當前設備是否支持要設置的屬性值,并且所有的屬性修改都要放在下面兩個方法之間,以保證屬性能夠被正確設置。
    - (BOOL)lockForConfiguration:(NSError **)outError; - (void)unlockForConfiguration;
    • 在調用硬件設備之前,應先判斷應用是否擁有相應的權限,其權限分為以下幾種:
  • AVAuthorizationStatusNotDetermined 未定義
  • AVAuthorizationStatusRestricted 無權限(因某些原因,系統拒絕權限)
  • AVAuthorizationStatusDenied 無權限(用戶拒絕)
  • 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

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

    1.5.4 AVCaptureOutput

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

    1.5.5 AVCaptureFileOutput

    • AVCaptureFileOutput 是 AVCaptureOutput 的子類,是 AVCaptureMovieFileOutput 、AVCaptureAudioFileOutput 的父類。這個類中定義了文件輸出時的地址、時長、容量等屬性。
    //當前記錄的數據的文件的地址 @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

    • AVCaptureVideoDataOutput 是 AVCaptureOutput 的子類,該類可以用來處理捕獲的每一個視頻幀數據。創建一個該類的實例對象后,要調用下面的方法設置一個代理對象,及調用代理對象所實現的協議方法的隊列。
    - (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

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

    • AVCaptureAudioDataOutput 是 AVCaptureOutput 的子類,該類可以處理接收到的音頻數據。同 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 之媒體流輸出

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

    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

    • AVAssetReaderTrackOutput 是 AVAssetReaderOutput 的子類,它用來描述待讀取的數據來自 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

    • AVAssetReaderAudioMixOutput 是 AVAssetReaderOutput 的子類,它用來描述待讀取的數據來自音頻組合數據。創建該類實例對象提供的參數 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

    • AVAssetReaderVideoCompositionOutput 是 AVAssetReaderOutput 的子類,該類用來表示要讀取的類是組合的視頻數據。
      同 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 之媒體的時間和數據

    總結

    以上是生活随笔為你收集整理的IOS音视频(一)AVFoundation核心类的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 日本不卡视频一区二区 | 亚洲精品理论 | 黄色免费网站 | 免费观看黄色一级视频 | 少妇搡bbbb搡bbb搡澳门 | 国产高清不卡一区 | 少妇人妻综合久久中文字幕 | 亚洲再线| 久久b| 欧美黄色一区二区 | 色综合啪啪 | 99热只有这里有精品 | 成人美女在线 | 久久国产精品一区 | 中文在线视频 | www.午夜视频 | 内射一区二区三区 | 免费av日韩 | 黄色免费入口 | 农夫色综合 | 黄页网站免费观看 | 男人操女人动态图 | 海角社区id:1220.7126,10. | 性囗交免费视频观看 | 一区二区三区黄色 | 日韩一级 | 亚洲国产亚洲 | 亚洲第一在线播放 | 天天玩天天干 | 樱花电影最新免费观看国语版 | 伊人天天干 | 岛国av免费在线观看 | 特高潮videossexhd | 国产伦精品一区二区三区视频痴汉 | 911美女片黄在线观看游戏 | 亚洲天堂黄色 | 日韩av综合网 | 日韩三级av在线 | av一区二区三区免费观看 | 国产资源在线播放 | 人妻互换一二三区激情视频 | 日韩电影网址 | 麻豆91茄子在线观看 | 小箩莉末发育娇小性色xxxx | 国产精品欧美性爱 | 国产粉嫩白浆 | 国产乱子轮xxx农村 岛国久久久 | 青娱乐最新视频 | 亚洲成人网在线播放 | 国产一区二区视频播放 | 日韩精品av一区二区三区 | 黄色一级视频免费观看 | 日日干夜夜干 | 热久久影院 | 亚洲av综合色区无码一二三区 | 综合天天色| 久久人人澡 | 新av在线 | 一二三四精品 | 国产精品久久久久久久免费看 | 日本天堂在线播放 | 国产精品成人Av | 国产老头老太作爱视频 | 欧洲成人精品 | 日韩少妇毛片 | 色五丁香 | 熟妇人妻av无码一区二区三区 | 免费成人一级片 | av在线播放地址 | 99re视频 | 我要看18毛片 | 亚洲午夜精品在线 | 亚洲天堂免费观看 | 欧美日韩中 | 国产成人aaa | 欧美sm凌虐视频网站 | 五十路母| 中文字幕无码毛片免费看 | 免费成人在线看 | 免费看麻豆 | 在线免费观看污片 | 亚洲AV乱码国产精品观看麻豆 | 久久靠逼视频 | 大尺度做爰床戏呻吟舒畅 | 日韩精品人妻中文字幕有码 | 国产精品日本一区二区在线播放 | 深夜天堂 | 最近中文在线观看 | 美女乱淫| 99在线精品视频 | 91av色 | 李华月全部毛片 | 调教亲女小嫩苞h文小说 | 亚洲我射av | 青青草成人免费在线视频 | 沈樵精品国产成av片 | 亚洲无码国产精品 | 日啪| 久久97人妻无码一区二区三区 |