版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2017.08.29 |
前言
AVFoundation
框架是ios中很重要的框架,所有與視頻音頻相關(guān)的軟硬件控制都在這個(gè)框架里面,接下來(lái)這幾篇就主要對(duì)這個(gè)框架進(jìn)行介紹和講解。感興趣的可以看我上幾篇。
1. AVFoundation框架解析(一)—— 基本概覽
2. AVFoundation框架解析(二)—— 實(shí)現(xiàn)視頻預(yù)覽錄制保存到相冊(cè)
3. AVFoundation框架解析(三)—— 幾個(gè)關(guān)鍵問(wèn)題之關(guān)于框架的深度概括
AVFoundation探索
在例子Building a Basic Playback App
中展示了,使用AVKit創(chuàng)建播放應(yīng)用程序是多么的容易,對(duì)于基本的視頻播放,那一章的例子中也許就有所有你需要的,但是為了利用好AVKit的所有特性和優(yōu)勢(shì),你應(yīng)該好好理解AVFoundation框架對(duì)象驅(qū)動(dòng)播放的,本章探討AVFoundation的基本知識(shí),并提供您使用AVKit和AVFoundation構(gòu)建全功能視頻播放應(yīng)用程序所需的信息。
Asset模型的理解
AVFoundation
的許多主要特征和功能與播放和處理媒體資源有關(guān),框架模型資源使用AVAsset類(lèi),是一個(gè)抽象不可變的類(lèi),代表了單個(gè)的媒體資源。它提供了媒體資源的綜合視圖,對(duì)整個(gè)媒體的靜態(tài)方面進(jìn)行了建模。AVAsset
的一個(gè)實(shí)例可以建?;诒镜匚募拿襟w,例如QuickTime
影片或MP3音頻文件,但也可以表示從遠(yuǎn)程主機(jī)逐步下載或使用HTTP Live Streaming(HLS)
流式傳輸?shù)馁Y產(chǎn)。
AVAsset
以?xún)煞N重要的方式處理多媒體文件。第一:它提供了與媒體格式的獨(dú)立性水平。 它為您提供了一個(gè)一致的界面,用于管理和與媒體進(jìn)行互動(dòng),無(wú)論其底層類(lèi)型如何。使用容器格式和編解碼器類(lèi)型的細(xì)節(jié)留在框架中,讓您專(zhuān)注于如何在app中使用這些資源。其次,AVAsset提供了與媒體位置的獨(dú)立性。 您可以通過(guò)使用媒體的URL初始化資源實(shí)例來(lái)創(chuàng)建資產(chǎn)實(shí)例。 這可能是本地URL,例如包含在應(yīng)用程序包或文件系統(tǒng)中其他位置的本地URL,也可能是遠(yuǎn)程服務(wù)器上托管的HLS流等資源。
在這兩種情況下,框架執(zhí)行必要的工作,以便及時(shí)有效地檢索和加載媒體。 消除處理媒體格式和位置的負(fù)擔(dān)大大簡(jiǎn)化了視聽(tīng)媒體的處理。
AVAsset是由AVAssetTrack
的一個(gè)或多個(gè)實(shí)例組成的容器對(duì)象,它對(duì)資產(chǎn)的均勻類(lèi)型的媒體流進(jìn)行建模。 最常用的軌道類(lèi)型是音頻和視頻軌道,但AVAssetTrack還可以建模其他補(bǔ)充軌道,例如隱藏字幕,字幕和定時(shí)元數(shù)據(jù)。
您使用其軌道屬性檢索資源的軌道集合。 在許多情況下,您將需要對(duì)資產(chǎn)軌道的子集合執(zhí)行操作,而不是對(duì)其完整集合執(zhí)行操作。 在這些情況下,AVAsset還提供了例如基于標(biāo)識(shí)符,媒體類(lèi)型或特征等標(biāo)準(zhǔn)來(lái)檢索軌道子集的方法。
創(chuàng)建Asset
通過(guò)使用指向媒體資源的本地或遠(yuǎn)程URL對(duì)其進(jìn)行初始化來(lái)創(chuàng)建AVAsset,如以下示例所示:
let url: URL = // Local or Remote Asset URL
let asset = AVAsset(url: url)
AVAsset是一個(gè)抽象類(lèi),所以當(dāng)您創(chuàng)建一個(gè)資源時(shí),如下面實(shí)例所示,您實(shí)際上正在創(chuàng)建一個(gè)名為AVURLAsset的具體子類(lèi)的實(shí)例。在許多情況下,這是創(chuàng)建資產(chǎn)的合適方式,但是當(dāng)您需要對(duì)其初始化進(jìn)行更細(xì)粒度的控制時(shí),也可以直接實(shí)例化AVURLAsset。 AVURLAsset的初始化程序接受一個(gè)選項(xiàng)字典,可以讓您根據(jù)特定用例定制資產(chǎn)的初始化。例如,如果您正在為HLS流創(chuàng)建資源,則當(dāng)用戶連接到蜂窩網(wǎng)絡(luò)時(shí),您可能希望阻止它獲取媒體。 你可以這樣做,如下面的例子所示:
let url: URL = // Remote Asset URL
let options = [AVURLAssetAllowsCellularAccessKey: false]
let asset = AVURLAsset(url: url, options: options)
為AVURLAssetAllowsCellularAccessKey
選項(xiàng)傳遞值為false表示您希望此資產(chǎn)僅在用戶連接到Wi-Fi網(wǎng)絡(luò)時(shí)才能檢索其媒體。
準(zhǔn)備Asset
您可以使用AVAsset的屬性來(lái)確定其特性和功能,例如其適用于播放,持續(xù)時(shí)間,創(chuàng)建日期和元數(shù)據(jù)。 創(chuàng)建資源不會(huì)自動(dòng)加載其屬性或?yàn)槿魏翁囟ㄓ猛咀鰷?zhǔn)備。相反,資產(chǎn)的屬性值的加載被推遲到被請(qǐng)求為止。 因?yàn)閷傩栽L問(wèn)是同步的,如果以前沒(méi)有加載請(qǐng)求的屬性,則框架可能需要執(zhí)行大量的工作才能返回值。在macOS中,如果從主線程訪問(wèn)卸載的屬性,則可能導(dǎo)致無(wú)響應(yīng)的用戶界面。 在iOS和tvOS中,由于媒體操作是由共享媒體服務(wù)守護(hù)進(jìn)程執(zhí)行的,所以情況會(huì)更加嚴(yán)重。如果檢索卸載的屬性值的請(qǐng)求被阻止太久,則超時(shí)會(huì)導(dǎo)致媒體服務(wù)終止。 為了防止這種情況發(fā)生,請(qǐng)異步加載資產(chǎn)的屬性。
AVAsset和AVAssetTrack采用AVAsynchronousKeyValueLoading
協(xié)議,它定義了用于查詢(xún)屬性的當(dāng)前加載狀態(tài)的方法,并根據(jù)需要異步加載一個(gè)或多個(gè)屬性值。 協(xié)議定義了兩種方法:
public func loadValuesAsynchronously(forKeys keys: [String], completionHandler handler: (() -> Void)?)
public func statusOfValue(forKey key: String, error outError: NSErrorPointer) -> AVKeyValueStatus
你可以使用方法loadValuesAsynchronouslyForKeys:completionHandler:
異步的加載一個(gè)或者多個(gè)屬性值,你傳遞給一個(gè)鍵組成的數(shù)組,它們是要加載的屬性的名字,和在確定狀態(tài)之后調(diào)用的完成塊。 以下示例顯示如何異步加載資產(chǎn)的可播放屬性。
// URL of a bundle asset called 'example.mp4'
let url = Bundle.main.url(forResource: "example", withExtension: "mp4")!
let asset = AVAsset(url: url)
let playableKey = "playable"
// Load the "playable" property
asset.loadValuesAsynchronously(forKeys: [playableKey]) {
var error: NSError? = nil
let status = asset.statusOfValue(forKey: playableKey, error: &error)
switch status {
case .loaded:
// Sucessfully loaded. Continue processing.
case .failed:
// Handle error
case .cancelled:
// Terminate processing
default:
// Handle all other cases
}
}
你檢查屬性的狀態(tài),在使用方法statusOfValueForKey:error:
的完成塊調(diào)用中。AVKeyValueStatusLoaded
狀態(tài)表示屬性值成功的加載了,可以不用block塊檢索。AVKeyValueStatusFailed
狀態(tài)表示屬性值不可用,因?yàn)樵趪L試加載數(shù)據(jù)時(shí)發(fā)生了錯(cuò)誤。你可以通過(guò)NSError
指針確定失敗的原因。在所有情況下,請(qǐng)注意,在任意后臺(tái)隊(duì)列中調(diào)用完成回調(diào)。 在執(zhí)行任何與用戶界面相關(guān)的操作之前,將調(diào)度方法調(diào)用回主隊(duì)列。
處理元數(shù)據(jù)Metadata
媒體容器格式可以存儲(chǔ)有關(guān)其媒體的描述性元數(shù)據(jù)。 作為開(kāi)發(fā)人員,使用元數(shù)據(jù)往往具有挑戰(zhàn)性,因?yàn)槊總€(gè)容器格式都有自己獨(dú)特的元數(shù)據(jù)格式。您通常需要對(duì)讀取和寫(xiě)入容器元數(shù)據(jù)的格式進(jìn)行低級(jí)的了解,但AVFoundation可以通過(guò)使用其AVMetadataItem
類(lèi)來(lái)簡(jiǎn)化使用元數(shù)據(jù)。
在其最基本的形式中,AVMetadataItem
的一個(gè)實(shí)例是表示單個(gè)元數(shù)據(jù)值的鍵值對(duì),例如電影的標(biāo)題或?qū)]嫷淖髌贰?以與AVAsset提供媒體標(biāo)準(zhǔn)化視圖相同的方式,AVMetadataItem提供其關(guān)聯(lián)元數(shù)據(jù)的歸一化視圖。
1. 檢索元數(shù)據(jù)集合
要有效地使用AVMetadataItem,您應(yīng)該了解AVFoundation如何組織元數(shù)據(jù)。 為了簡(jiǎn)化查找和過(guò)濾元數(shù)據(jù)項(xiàng),框架將相關(guān)元數(shù)據(jù)分組成關(guān)鍵空間。
- 格式特定的鍵空格
- 框架定義了一些特定于格式的關(guān)鍵空間。 這些與特定的容器或文件格式大致相關(guān),例如QuickTime(Quicktime元數(shù)據(jù)和用戶數(shù)據(jù))或MP3(ID3)。 但是,單個(gè)資產(chǎn)可能包含跨多個(gè)關(guān)鍵空間的元數(shù)據(jù)值。 您可以使用其元數(shù)據(jù)屬性來(lái)檢索資產(chǎn)的格式特定元數(shù)據(jù)的完整集合。
- 公共密鑰空間
- 有許多常見(jiàn)的元數(shù)據(jù)值,例如電影的創(chuàng)建日期或描述,可以跨多個(gè)關(guān)鍵空間存在。 為了幫助規(guī)范對(duì)這個(gè)公共元數(shù)據(jù)的訪問(wèn),框架提供了一個(gè)公共密鑰空間,可以訪問(wèn)幾個(gè)密鑰空間共有的有限的一組元數(shù)據(jù)值。這樣可以方便地檢索常用的元數(shù)據(jù),而不用考慮特定的格式。 您可以使用其
commonMetadata
屬性來(lái)檢索資產(chǎn)的公共元數(shù)據(jù)集合。
- 有許多常見(jiàn)的元數(shù)據(jù)值,例如電影的創(chuàng)建日期或描述,可以跨多個(gè)關(guān)鍵空間存在。 為了幫助規(guī)范對(duì)這個(gè)公共元數(shù)據(jù)的訪問(wèn),框架提供了一個(gè)公共密鑰空間,可以訪問(wèn)幾個(gè)密鑰空間共有的有限的一組元數(shù)據(jù)值。這樣可以方便地檢索常用的元數(shù)據(jù),而不用考慮特定的格式。 您可以使用其
您可以通過(guò)調(diào)用其可用的MetadataFormats
屬性來(lái)確定資產(chǎn)包含的元數(shù)據(jù)格式。 此屬性返回其包含的每個(gè)元數(shù)據(jù)格式的字符串標(biāo)識(shí)符數(shù)組。 然后,使用其metadataForFormat:
方法通過(guò)傳遞適當(dāng)?shù)母袷綐?biāo)識(shí)符來(lái)檢索特定于格式的元數(shù)據(jù)值,如下所示:
let url = Bundle.main.url(forResource: "audio", withExtension: "m4a")!
let asset = AVAsset(url: url)
let formatsKey = "availableMetadataFormats"
asset.loadValuesAsynchronously(forKeys: [formatsKey]) {
var error: NSError? = nil
let status = asset.statusOfValue(forKey: formatsKey, error: &error)
if status == .loaded {
for format in asset.availableMetadataFormats {
let metadata = asset.metadata(forFormat: format)
// process format-specific metadata collection
}
}
}
2. 發(fā)現(xiàn)和使用元數(shù)據(jù)值
檢索到元數(shù)據(jù)的集合后,下一步是查找其中的特定值。 您使用AVMetadataItem的各種類(lèi)方法將元數(shù)據(jù)集合過(guò)濾到一組離散值。 查找特定元數(shù)據(jù)項(xiàng)目的最簡(jiǎn)單方法是按標(biāo)識(shí)符進(jìn)行過(guò)濾,將標(biāo)識(shí)符和密鑰的概念分組到一個(gè)單元中。 以下示例顯示如何從公共密鑰空間中檢索標(biāo)題項(xiàng)。
let metadata = asset.commonMetadata
let titleID = AVMetadataCommonIdentifierTitle
let titleItems = AVMetadataItem.metadataItems(from: metadata, filteredByIdentifier: titleID)
if let item = titleItems.first {
// process title item
}
這里還要注意:AVMetadataItem的過(guò)濾方法返回項(xiàng)目的集合而不是單個(gè)實(shí)例。 在許多情況下,返回的集合包含單個(gè)元素,但是如果介質(zhì)包含本地化的元數(shù)據(jù),或者如果從公共密鑰空間檢索數(shù)據(jù),并且多個(gè)密鑰空間中存在相同的值,則會(huì)返回與每個(gè)區(qū)域設(shè)置或密鑰空間匹配的不同值。
檢索到特定元數(shù)據(jù)項(xiàng)后,下一步是調(diào)用其value屬性。 返回的值是采用NSObject
和NSCopying
協(xié)議的對(duì)象類(lèi)型。 您可以手動(dòng)將值轉(zhuǎn)換為適當(dāng)?shù)念?lèi)型,但使用元數(shù)據(jù)項(xiàng)的類(lèi)型強(qiáng)制屬性更安全和更容易。 您可以使用其stringValue,numberValue,dateValue和dataValue屬性來(lái)輕松將該值強(qiáng)制為適當(dāng)?shù)念?lèi)型。 例如,以下示例顯示如何檢索與iTunes音軌相關(guān)聯(lián)的藝術(shù)作品。
// Collection of "common" metadata
let metadata = asset.commonMetadata
// Filter metadata to find the asset's artwork
let artworkItems =
AVMetadataItem.metadataItems(from: metadata,
filteredByIdentifier: AVMetadataCommonIdentifierArtwork)
if let artworkItem = artworkItems.first {
// Coerce the value to an NSData using its dataValue property
if let imageData = artworkItem.dataValue {
let image = UIImage(data: imageData)
// process image
} else {
// No image data found
}
}
元數(shù)據(jù)在許多媒體app中起著重要的作用。 本指南的后續(xù)部分將介紹如何使用靜態(tài)和定時(shí)元數(shù)據(jù)來(lái)增強(qiáng)播放app的功能。
后記
未完,待續(xù)~~~