短視訊編輯中的AVFoundation框架(一)框架概述與基礎

語言: CN / TW / HK

前言

提到短視訊編輯,我們可能會第一時間想到FFmpegOpenGL ES這些讓人望而生畏的龐大框架,誠然音視訊開發的入門的確需要一定的基礎,但是僅僅依託於蘋果為我們提供的AVFoundation框架,我們仍然可以在短視訊編輯領域做很多事情。本系列文章圍繞iOS平臺上短視訊編輯功能中AVFoundation扮演的角色展開討論,本篇主要介紹學習AVFoundation框架需要了解的基礎模組和相關的資料型別及注意事項。

一、 AVFouondation框架概述

AVFoundation 是在 iOS、macOS、watchOS 和 tvOS 上處理多媒體資料的功能齊全的框架。使用AVFoundation,我們可以播放、建立和編輯 QuickTime movie和 MPEG-4 檔案,播放 HLS 流,並將強大的媒體編輯功能構建到我們的應用程式中。

1.1 iOS多媒體框架體系

我們首先來看AVFouondation框架在蘋果的多媒體框架體系中的位置。在iOS的多媒體體系中,高層級的AVKit提供了 高度封裝的播放器控制類AVPlayerViewController 、用於切換播放路由(投屏)的AVRoutePickerView,以及實現畫中畫播放效果的AVPictureInPictureController。低層級的框架主要以C介面為主,其中:

  • Core Audio 最底層的音訊處理介面,直接驅動裝置的音訊硬體,對音樂遊戲或專業的音訊編輯軟體提供了全面的支援。Audio Unit提供了包含合成樂器聲音、回聲消除、混音、聲音均衡等相關介面。

    Audio Unit已經遷移到 Audio Toolbox Framework了。

  • Core Video 為其相對的Core Media提供圖片快取(CVPixelBuffer)和快取池(CVPixelBufferPool)支援,提供了一個能夠對數字視訊逐幀訪問的介面,以及對Metal(CVMetalTexture) 、OpenGL(CVOpenGLTexture) 以及OpenGLES(CVOpenGLESTexture)的支援。

  • Core Media 定義和封裝了AVFoundation等更上層的媒體框架需要的媒體處理流水線(包含時間資訊)以及其中使用的介面和資料型別(CMSampleBufferCMTime)。使用 Core Media 層的介面和資料型別可以高效的處理媒體取樣資料、管理取樣資料佇列(CMSimpleQueueCMBufferQueue)。
  • Core Animation 是iOS中動畫相關的框架,AVFoundation結合Core Animation讓開發者能夠在視訊編輯和播放過程中新增動畫和貼紙效果。

1-1

而AVFoundation位於高層級框架和低層級框架之間,封裝了低層級框架才能實現的功能,提供了OC和Swift語言的介面,同時蘋果在迭代過程中不斷優化AVFoundation這種中間層框架的效能,很好地支援了新的裝置和視訊格式。

1.2 AVFoundation各模組簡介

AVFoundation官方文件介紹:AVFoundation框架結合了六個主要技術領域,這些領域覆蓋了在Apple平臺上錄製、處理、合成、控制、匯入和匯出視聽媒體的主要功能。而API官方文件將AVFoundation分成了Assets媒體資源、Playback播放、Capture錄製、Editing編輯、Audio音訊、Speech(語音播報)六個功能模組。

1-2

  • Assets:提供載入、檢查和匯出媒體資源和元資料資訊的功能,也可以使用AVAssetReaderAVAssetWriter對媒體樣本資料進行樣本級讀寫,使用AVAssetImageGenerator獲取視訊縮圖,使用AVCaption進行字幕創作(mac os)等。
  • Playback:提供對AVAsset的播放和播放控制的功能,可以使用AVPlayer播放一個專案,也可以使用AVQueuePlayer播放多個專案,AVSynchronizedLayer可以讓我們結合Core Animation將動畫層與播放檢視層進行同步,實現播放中的諸如貼紙、文字等效果。
  • Capture:用於拍攝照片、錄製音訊和視訊,通過配置內建攝像頭和麥克風或外部錄製裝置,可以構建自定義相機功能,控制照片和視訊拍攝的輸出格式,或者直接修改音視訊資料流作為自定義輸出。
  • Editing:用於將來自多個來源的音訊和視訊軌道組合、編輯和重新混合到一個AVMutableComposition中,可以使用AVAudioMixAVVideoComposition分別控制音訊混合和視訊合成的細節。
  • Audio:播放、錄製和處理音訊;配置應用程式的系統音訊行為。蘋果又在iOS14.5整合了一個AVFAudio框架,內容與這部分完全相同,可能未來會把音訊部分單獨處理。
  • Speech:將文字轉換為語音音訊進行朗讀。

在短視訊編輯中,無論是編輯所用的素材還是編輯中處理的半成品亦或是最終匯出的成品,我們都在跟AVAsset或其子類打交道,其所在的Assets模組作為AVFoundation媒體處理的基礎是需要首先學習的內容。

二、 基礎模組-Assets

2.1 AVAsset & AVAssetTrack

AVAsset是一個抽象類和不可變類,定義了媒體資源混合呈現的方式,將媒體資源的靜態屬性模組化成一個整體。它提供了對基本媒體格式的抽象,這意味著無論是處理Quick Time Movie還是MP3音訊,對開發者和對框架其餘部分而言,面對的只有資源這個概念。

AVAsset通常通過其子類AVURLAsset例項化,其中的引數"URL"可以來自遠端或者本地甚至是流媒體,使我們無須關注其來源,只須專注於處理AVAsset本身。

使用下面程式碼示例中的方法建立返回的都是AVURLAsset的例項。方法二中的options可以用來來自定義AVURLAsset的初始化以滿足特定需求。例如,通過HLS流建立AVURLAsset,使用{AVURLAssetAllowsCellularAccessKey: @NO}作為options的引數,可以阻止在使用蜂窩網路時檢索其媒體資料。而與視訊編輯密切相關的是AVURLAssetPreferPreciseDurationAndTimingKey,用於指示資源是否提供準確的"duration"值和精確的隨機訪問,視訊編輯需要精確的值,建議使用"YES",不過這種精度可能需要進行額外的解析而導致更長的載入時間。

許多容器格式為精確計時提供了足夠的摘要資訊,並不需要額外的解析來準備,例如QuickTime Movie和MPEG-4檔案。 AVAsset *asset = [AVAsset assetWithURL:url]; AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:@{AVURLAssetPreferPreciseDurationAndTimingKey: @YES}];

一個AVAsset例項是一個或多個AVAssetTrack例項的容器,該例項是對媒體的統一型別"軌道"進行的建模。一個簡單的視訊檔案通常包含一個音訊軌道和一個視訊軌道,也可能包含一些補充內容,如隱藏式字幕、字幕,也可能包含描述媒體內容的元資料(AVMetadataItem)。

隱藏式字幕即“Closed Caption”,簡稱CC字幕。大多數CC字幕和劇本是一樣的,裡面除了對白之外,還有場景中產生的聲音和配樂等的描述,主要是為了聽障人士所設定的,“Closed”一詞也說明了並不是預設開啟的狀態,與之相對的是“Open Caption”,也就是通常所說的字幕,而與對話語言相同的字幕稱為”Caption“,不同的(即翻譯)稱為“Subtitle”。

建立一個AVAsset是一個輕量級操作,因為AVAsset的底層媒體資料採用了延遲載入的設計,直到獲取時才會進行載入,並且屬性的獲取是同步進行的,如果沒有進行提前進行非同步載入直接去訪問它的屬性會阻塞呼叫執行緒,不過這也要取決於要訪問的媒體資料的大小和位置。為了避免阻塞執行緒,我們最好在使用之前進行非同步載入屬性。AVAsset和AVAssetTrack都遵循了AVAsynchronousKeyValueLoading協議,可以進行非同步載入屬性和獲取載入狀態。 @protocol AVAsynchronousKeyValueLoading // 非同步載入包含在keys陣列中的屬性,在handler中使用statusOfValueForKey:error:方法判斷載入是否完成。 - (void)loadValuesAsynchronouslyForKeys:(NSArray<NSString *> *)keys completionHandler:(nullable void (^)(void))handler; // 獲取key屬性載入的狀態,status為AVKeyValueStatusLoaded為載入完成。 - (AVKeyValueStatus)statusOfValueForKey:(NSString *)key error:(NSError * _Nullable * _Nullable)outError; WWDC2021What’s new in AVFoundation提到,針對swift API引入了async / await ,讓我們得以使用與同步程式設計類似的控制流來進行非同步程式設計。 let asset = AVAsset (url: assetURL) let duration = trv await asset.load(.duration) // 我們也可以載入多個屬性,使用元組接收返回值: let (duration, tracks) = try await asset.load(.duration, .tracks) AVAsset的屬性:

程式碼示例中tracks屬性返回的是一個AVAsset例項包含的所有AVAssetTrack例項的陣列,蘋果也提供了根據特定標準(如軌道ID、媒體型別和特徵)檢索軌道子集的方法如下,這也是編輯模組中取出某種型別的軌道常用的方法。

// 根據TrackID檢索軌道 - (void)loadTrackWithTrackID:(CMPersistentTrackID)trackID completionHandler:(void (^)(AVAssetTrack * _Nullable_result, NSError * _Nullable))completionHandler; // 根據媒體型別檢索軌道子集 - (voidloadTracksWithMediaType:(AVMediaType)mediaType completionHandler:(void (^)(NSArray<AVAssetTrack *> * _Nullable NSError * _Nullable))completionHandler; // 根據媒體特徵檢索軌道子集 - (void)loadTracksWithMediaCharacteristic:(AVMediaCharacteristic)mediaCharacteristic completionHandler:(void (^)(NSArray<AVAssetTrack *> * _Nullable, NSError * _Nullable))completionHandler; 其中AVMediaType常用的有:音訊AVMediaTypeAudio、視訊AVMediaTypeVideo、字幕AVMediaTypeSubtitle、元資料AVMediaTypeMetadata等。

AVMediaCharacteristic用於定義媒體資料特徵,例如是否包含HDR視訊軌道AVMediaCharacteristicContainsHDRVideo,是否包含可聽內容AVMediaCharacteristicAudible等。

2.2 元資料

媒體容器格式儲存關於其媒體的描述性元資料,每種容器格式都有自己獨特的元資料格式,AVFoundation通過使用其AVMetadataItem類簡化了對元資料的處理,在最基本的形式中,AVMetadataItem的例項是一個鍵值對,表示單個元資料值,比如電影的標題或專輯的插圖。

要高效地使用AVMetadataItem,我們需要了解AVFoundation是如何組織元資料的。為了簡化元資料項的查詢和過濾,AVFoundation框架將相關元資料分組到鍵空間中: - 特定格式的鍵空間。AVFoundation框架定義了幾個特定格式的鍵空間,它們大致與特定容器或檔案格式相關,例如 QuickTime(QuickTime 元資料和使用者資料)或 MP3 (ID3)。但是,單個資源可能包含跨多個鍵空間的元資料值。要檢索資源的特定格式元資料的完整集合,可以使用metadata屬性。 - Common鍵空間。有幾個常見的元資料值,例如電影的建立日期或描述,可以存在於多個鍵空間中。為了幫助規範化對這個公共元資料的訪問,該框架提供了一個common鍵空間,它允許訪問幾個鍵空間共有的一組有限元資料值。要檢索資源的公共元資料集合,可以直接使用commonMetadata屬性。

除此之外,我們還可以通過呼叫AVAssetavailableMetadataFormats屬性來確定資源包含哪些元資料格式。此屬性返回包含每個元資料格式的字串識別符號陣列。然後使用它的metadataForFormat:方法,通過傳遞適當的格式識別符號來檢索特定於格式的元資料值。

一個iPhone13 Pro拍攝的HDR視訊檔案的元資料: creationDate : 2022-03-01T18:16:17+0800 location : +39.9950+116.4749+044.903/ make: Apple model: iPhone 13 Pro software: 15.3.1 雖然本系列文章旨在不過多關注音視訊編解碼格式,但是拿到一個視訊檔案(.mov),如果仍然想獲取視訊樣本的編碼型別(h264/hevc)、轉換函式(ITU_R_709_2/ITU_R_2100_HLG)等,獲取音訊樣本的取樣率、通道數、位深等格式資訊,我們應該從哪裡入手呢?前面我們介紹了在一個AVAsset資源中以軌道(track)的形式把音訊、視訊等資料分別進行了單獨的建模,如果要獲取視訊樣本格式的資訊,只要根據媒體型別檢索相應的視訊軌道,獲取assetTrack的formatDescriptions屬性,即可拿到視訊樣本的格式資訊CMVideoFormatDescription的集合,同樣還有CMAudioFormatDescriptionCMClosedCaptionFormatDescription等用於描述各自軌道樣本的資料格式。 // 獲取資料樣本格式資訊 AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] firstObject]; NSArray *videoFormats = VideoTrack.formatDescriptions; 上述視訊檔案中的視訊軌道格式描述資訊如下: "<CMVideoFormatDescription 0x2834305a0 [0x1dbce41b8]> { mediaType:'vide' mediaSubType:'hvc1' mediaSpecific: { codecType: 'hvc1' dimensions: 1920 x 1080 } extensions: {{ AmbientViewingEnvironment = {length = 8, bytes = 0x002fe9a03d134042}; BitsPerComponent = 10; CVFieldCount = 1; CVImageBufferChromaLocationBottomField = Left; CVImageBufferChromaLocationTopField = Left; CVImageBufferColorPrimaries = \"ITU_R_2020\"; CVImageBufferTransferFunction = \"ITU_R_2100_HLG\"; CVImageBufferYCbCrMatrix = \"ITU_R_2020\"; Depth = 24; FormatName = HEVC; FullRangeVideo = 0; RevisionLevel = 0; SampleDescriptionExtensionAtoms = { dvvC = { length = 24, bytes = 0x010010254000000000000000000000000000000000000000 }; hvcC = { length = 125, bytes = 0x01022000 0000b000 00000000 78f000fc ... 2fe9a03d 13404280 }; }; SpatialQuality = 512; TemporalQuality = 512; VerbatimSampleDescription = { length = 289, bytes = 0x00000121 68766331 00000000 00000001 ... 3d134042 00000000 }; Version = 0; }} }"

2.3 視訊預覽

在短視訊編輯中將播放匯出前的視訊資源稱為預覽,實際上播放屬於AVFoundation中Playback模組的內容,但是本系列文章重點不在播放器上,我們簡單介紹一下預覽AVAsset使用的類AVPlayer

AVPlayer的初始化需要一個AVPlayerItem物件,它用來管理資源物件,提供播放資料來源的類,要播放一個視訊,只使用AVPlayer的話,只有聲音沒有畫面,要顯示畫面我們還需要AVPlayerLayer。 ``` // 1.例項化AVAsset AVAsset *asset = [AVAsset assetWithURL:url];

// 2.通過asset建立AVPlayerItem AVPlayerItem* item = [[AVPlayerItem alloc] initWithAsset:asset];

// 3.建立AVPlayer AVPlayer* player = [AVPlayer playerWithPlayerItem:item];

// 4.建立AVPlayerLayer用來顯示視訊 AVPlayerLayer* playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];

// 5.將AVPlayerLayer新增到檢視層級中 [self.view.layer addSublayer:playerLayer];

// 6.播放 [player play]; ```

2.4 獲取視訊縮圖

通常在視訊匯出前會有一個選擇視訊封面的功能,該功能需要提供視訊縮圖的列表,要獲取視訊的縮圖需要使用AVAssetImageGenerator,使用AVAsset例項建立 AVAssetImageGenerator物件的方法如下: + (instancetype)assetImageGeneratorWithAsset:(AVAsset *)asset; - (instancetype)initWithAsset:(AVAsset *)asset; 如果需要精確時間截圖,可以使用按照如下方法將前後時間容忍度設為kCMTimeZero,設定maximumSize屬性可以指定擷取畫面的大小。 // 精確時刻獲取縮圖 imageGenerator.requestedTimeToleranceBefore = kCMTimeZero; imageGenerator.requestedTimeToleranceAfter = kCMTimeZero; // 指定縮圖畫面的大小 imageGenerator.maximumSize = CGSizeMake(100, 100); 然後呼叫如下方法來獲取某個時刻的縮圖,或者多個時刻的縮圖: ``` // 獲取指定時刻requestedTime的視訊縮圖 - (nullable CGImageRef)copyCGImageAtTime:(CMTime)requestedTime actualTime:(nullable CMTime *)actualTime error:(NSError * _Nullable * _Nullable)outError;

// 獲取多個時刻的縮圖,每生成一張圖片,都會呼叫一次handler - (void)generateCGImagesAsynchronouslyForTimes:(NSArray *)requestedTimes completionHandler:(AVAssetImageGeneratorCompletionHandler)handler;

// 上述方法的handler的型別定義,actualTime為縮圖所處的真實時刻 typedef void (^AVAssetImageGeneratorCompletionHandler)(CMTime requestedTime, CGImageRef _Nullable image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * _Nullable error); ```

三、 常用資料型別

3.1 CMTime & CMTimeRange

在獲取視訊縮圖中我們需要傳入一個用於表示某個時刻的型別CMTime,通常我們認為用於表示時間的一般是NSTimeInterval(double型別),在AVFoundation中的AVAudioPlayerAVAudioRecorder處理時間可以使用,但是浮點型的不精確性(簡單的舍入就會導致丟幀),無法用於更多的高階時基媒體的開發中,所以Core Media提供了這樣一個結構體來表示時間: typedef struct { CMTimeValue value; CMTimeScale timescale; CMTimeFlags flags; CMTimeEpoch epoch; } CMTime; 其中CMTimeFlags是一個位掩碼用於表示時間的指定狀態,例如判斷資料是否有效,CMTimeEpoch表示紀元,通常是0。我們重點關注表示時間的CMTimeValue和CMTimeScale,一個CMTime表示的時間 = value / timescale,timescale表示將時間劃分了多少份,value表示該時間含有多少份,為滿足大部分常用的視訊頻率24FPS、25FPS、30FPS,通常我們會將timescale設為他們的公倍數600。

我們可以使用如下方法建立一個CMTime:

CMTime time1 = CMTimeMake(3, 1); // 3 / 1 = 3s CMTime time2 = CMTimeMakeWithSeconds(5, 1); 5s timescale = 1 NSDictionary *timeData = @{(id)kCMTimeValueKey : @2, (id)kCMTimeScaleKey : @1, (id)kCMTimeFlagsKey : @1, (id)kCMTimeEpochKey : @0}; CMTime time3 = CMTimeMakeFromDictionary((__bridge CFDictionaryRef)timeData); // 特殊值 // 表示0時刻 CMTime time4 = kCMTimeZero; // 表示時間非法 CMTime time5 = kCMTimeInvalid; CMTime的運算: // 加 CMTimeAdd(<#CMTime lhs#>, <#CMTime rhs#>) // 減 CMTimeSubtract(<#CMTime lhs#>, <#CMTime rhs#>) // 比較 CMTimeCompare(<#CMTime time1#>, <#CMTime time2#>) // 校驗 CMTIME_IS_VALID(<#time#>) CMTIME_IS_INVALID(<#time#>) // print CMTimeShow(<#CMTime time#>)

CMTimeRange用於表示一個時間範圍,由兩個CMTime值組成,第一個定義時間範圍的開始時間,第二個定義時間範圍的持續時間。 typedef struct { CMTime start; CMTime duration; } CMTimeRange; 我們可以使用如下方法建立一個CMTimeRange: CMTime beginTime = CMTimeMake(5, 1); CMTime endTime = CMTimeMake(12, 1); CMTimeRange timeRange1 = CMTimeRangeMake(beginTime, endTime); CMTimeRange timeRange2 = CMTimeRangeFromTimeToTime(beginTime, endTime); // 特殊值 // 表示0長度的時間範圍 CMTimeRange timeRange3 = kCMTimeRangeZero; // 表示時間範圍非法 CMTimeRange timeRange4 = kCMTimeRangeInvalid; CMTimeRange的運算: // 取兩個CMTimeRange的交集 CMTimeRangeGetIntersection(<#CMTimeRange range#>, <#CMTimeRange otherRange#>) // 取兩個CMTimeRange的並集 CMTimeRangeGetUnion(<#CMTimeRange range#>, <#CMTimeRange otherRange#>) // 是否包含某個時刻CMTime CMTimeRangeContainsTime(<#CMTimeRange range#>, <#CMTime time#>) // 是否包含某個時間範圍 CMTimeRangeContainsTimeRange(<#CMTimeRange range#>, <#CMTimeRange otherRange#>) // 校驗 CMTIMERANGE_IS_VALID(<#range#>) CMTIMERANGE_IS_INVALID(<#range#>) // print CMTimeRangeShow(<#CMTimeRange range#>)

3.2 CMSampleBuffer

使用AVFoundation處理樣本級的資料時要經常跟CMSampleBuffer打交道,例如AVFoundation的Capture模組相機採集的資料輸出型別、AVAssetReaderAVAssetWriter讀取和寫入過程中操作的資料型別等。

CMSampleBuffer同樣來自Core Media框架,它是系統用來通過媒體管道移動媒體樣本資料的核心基礎物件,CMSampleBuffer的角色是將基礎的樣本資料進行封裝並提供格式描述時間資訊

官方的文件介紹,它包含0個或多個特定媒體型別(音訊、視訊、混合等)的壓縮(或未壓縮)樣本,CMSampleBuffer可以包含: - 樣本資料。包含以下兩者中的一個: - 一個或多個媒體樣本的CMBlockBufferCMBlockBuffer為編碼的資料,並未進行解碼。 - 一個或多個媒體樣本的CVPixelBufferCVPixelBuffer為編碼前或解碼後的資料。

  • 時間資訊。CMSampleBuffer還包含表示當前樣本的顯示時間(Presentation Time Stamp)的pts,表示樣本的編碼時間(Decode Time Stamp)的dts,dts主要用於視訊的解碼,如果解碼時間與顯示時間順序一致,其值可以設定為kCMTimeInvalid。可以分別使用CMSampleBufferGetPresentationTimeStampCMSampleBufferGetDecodeTimeStamp獲取pts和dts。
  • 格式資訊。格式資訊封裝在CMFormatDescription物件中。可以分別使用CMVideoFormatDescriptionGetCodecTypeCMVideoFormatDescriptionGetDimensions獲取編碼型別和視訊尺寸。除此之外還可以使用CMGetAttachment檢索字典獲取元資料: CFDictionaryRef metadataDictionary = CMGetAttachment(sampleBuffer, CFSTR("MetadataDictionary", NULL);

3.3 CVPixelBuffer

CVPixelBufferRef是畫素緩衝區型別,畫素緩衝區型別基於影象緩衝區型別,屬於Core Video框架的資料型別。 typedef CVImageBufferRef CVPixelBufferRef; CVPixelBufferRef裡包含很多圖片相關屬性,比較重要的有widthheightPixelFormatType等。除了常見的RGB32以外,還可以支援比如 kCVPixelFormatType_420YpCbCr8BiPlanarFullRange這種YUV多平面的資料格式,通過CVPixelBufferGetBaseAddressOfPlane可以得到每個平面的資料指標。如果使用CPU訪問畫素資料,在獲取Address之前需要呼叫CVPixelBufferLockBaseAddress

CMSampleBuffer的一個例項在對應的CVPixelBuffer中包含了視訊幀的資料。我們可以使用CMSampleBufferGetImageBuffer獲取: CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(<#A CMSampleBuffer#>);

四、 注意事項

4.1 隱私許可權

AVFoundation中的Capture模組涉及使用裝置的相機和麥克風,對圖片與視訊檔案的讀取與儲存涉及對使用者相簿的訪問,這些都被蘋果列為使用者的隱私許可權,我們需要在Xcode的info.plist新增響應的申請訪問許可權說明。下面列舉了部分許可權與其對應的key值。 | 隱私資料 | key | |--------------|-----------------------------------------------------| | 相簿(讀許可權) | Privacy - Photo Library Usage Description | | 相簿(寫許可權) | Privacy - Photo Library Additions Usage Description | | 麥克風 | Privacy - Microphone Usage Description | | 相機 | Privacy - Camera Usage Description |

4.2 配置AVAudioSession

iOS裝置的音訊環境相對mac os較為複雜,蘋果提供了AVAudioSession音訊會話,在應用程式和作業系統之間扮演中間人的角色,我們只需指明應用程式的音訊行為即可將對音訊行為的管理委託給AVAudioSession。預設的音訊會話預配置了以下行為: - 支援音訊播放,但不允許錄製音訊。 - 靜音模式會使應用程式播放的任何音訊靜音。 - 鎖定裝置會使app的音訊靜音。 - 當應用程式播放音訊時,它會使任何其他背景音訊靜音。 iOS提供六個Category可供選擇:

AVAudioSessionCategoryAudioProcessing在iOS10.0已經廢棄。

| Category | 播放/錄製 | 是否中斷其他音訊 | 靜音或鎖屏模式是否靜音 | |:----------------------------------|:----------:|:--------------------:|:----------------------------------------------------:| | SoloAmbient | 僅播放 | 是 | 是 | | Ambient | 僅播放 | 否 | 是 | | MultiRoute | 播放和錄製 | 是 | 否 | | PlayAndRecord | 播放和錄製 | 預設YES,可以重寫為NO | 否 | | Playback | 僅播放 | 預設YES,可以重寫為NO | 否 | | Record | 僅錄製 | 是 | 否(鎖屏下仍可錄製,需要配置後臺模式UIBackgroundModes) |

除此之外,音訊會話還提供了用於監聽如電話呼入、鬧鐘響起引起的音訊中斷的通知AVAudioSessionInterruptionNotification,以及例如耳機插入造成的路由線路變更的通知AVAudioSessionRouteChangeReason

4.3 多執行緒

AVFoundation的構建考慮到了當前的硬體環境和應用程式,其設計過程高度依賴多執行緒機制。我們在使用的過程中,要明確所呼叫的API預設工作在哪個執行緒,或者需要工作在哪個執行緒,保證對UI的處理及時回到主執行緒來進行,避免耗時的操作阻塞主執行緒。

總結

本篇作為AVFoundation系列文章的開篇,主要介紹了AVFoundation的概述和各模組的基本功能,之後通過AVAssets模組的學習我們建立了一個從軌道(track)的角度看待音視訊檔案的視野,瞭解了常用的資料型別以及使用AVFoundation的注意事項。下一篇我們將從短視訊編輯第一步素材的新增與處理方面介紹AVFoundation框架提供的支援。

參考連結

AVFoundation AVAudioSession音訊會話 CMSampleBuffer