AVAsset
#AVFoundation #AVPlayer
概要
AVAsset はメディアのアセットのモデルであり、immutable な抽象クラス。メディアのコンテナフォーマットやコーデックに依存しない共通の I/F を提供する メディアフォーマット独立 と、初期化時に受け渡す URL の示す先がローカルファイルでもリモートサーバから配信される HLS ファイルでも良い メディアロケーション独立 を提供している。
また、AVAsset には トラック という概念があり、AVAssetTrack クラスとして扱える。これは例えば、映像や音声、字幕等のメディアストリームをモデル化したものであり、tracks プロパティに複数保持することができる。
初期化
抽象クラスなので、実際にインスタンス化する際には AVURLAsset 等の具象クラスを使用する。AVAsset 自体を url で初期化することもできるが、これは AVURLAsset のインスタンスになっている。AVURLAsset を直接インスタンス化することもでき、その場合はオプションをカスタムできる。その他のインスタンスには AVComposition などがある。
code:swift
let asset = AVAsset(url: URL(string: "https://google.com")!)
// 生成されるのは AVURLAsset のインスタンス
if asset is AVURLAsset {
Swift.print("a") // a
} else {
Swift.print("b")
}
https://developer.apple.com/documentation/avfoundation/avasset
AVAssetのロード
AVAsset の初期化後すぐに、その全てのプロパティが利用可能になるとは限らない。ほとんどのプロパティの同期的に返るようになっているが、その値がローディング中の場合には値が準備できるまで呼び出し側をブロッキングしてしまう可能性がある。まだロードが完了していないプロパティについてそのロード完了を監視するためには、loadValuesAsynchronously(forKeys:completionHandler:) を利用する。
ロード完了を監視する対象のプロパティは複数指定できる。指定した全てのプロパティがすでにロード済であった、あるいはエラーが発生していた場合には completion handler は同期的に呼び出される。それ以外の場合は Background Queue で非同期に呼び出される。いずれにしても、completion handler はこのメソッド呼び出し一回につき必ず一回呼び出されるようになっている。監視対象のプロパティが正常にロードできたかどうかは保証されないため、別途 statusOfValue(forKey:error:) を呼び出して確認すべき。
AVPlayer のサンプルコード にもあるとおり、AVAsset を利用して AVPlayer を初期化する際には、AVAsset を非同期にロードしてから AVPlayer の初期化を行うことが推奨されている。
code:swift
let asset = AVAsset(url: contentUrl)
let playerItem = AVPlayerItem(asset: asset)
asset.loadValuesAsynchronously(forKeys: \AVAsset.isPlayable, error: nil) {
switch asset.statusOfValue(forKey: \AVAsset.isPlayable, error: nil) {
case .loaded:
}
}
映像や音声等のメディアは、AVAsset の初期化成功後にすぐに値が全て利用可能とは限らない。AVAsset のとあるプロパティの値を要求した場合、同期的に値が返されるが、値がローディング中などの場合には呼び出し側をブロッキングしてしまう可能性がある。これを避けるために、参照したい特定のキーを登録しておき、利用可能になったら通知してくれる機構が存在する。それが AVAsynchronousKeyValueLoading である。これは、KVO の拡張っぽい。
code:swift
let url = Bundle.main.url(forResource: "example", withExtension: "mp4")!
let asset = AVAsset(url: url)
asset.loadValuesAsynchronously(forKeys: "playable") {
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
}
}
https://developer.apple.com/documentation/avfoundation/avasynchronouskeyvalueloading
アセットの再生
アセットの再生のためには、まずアセットにより AVPlayerItem を初期化し、presentation state (再生可能な時間範囲等) を設定する。その後、AVPlayer にそれをさらに渡して再生する。
また、複数のソースを組み合わせたい場合には、AVMutableComposition を利用できる。
AVURLAsset
初期化オプション
正確な長さとランダムアクセス
ネットワーク経由でダウンロードしているある音声コンテンツに対して、その正確な長さを測ること、及び時間指定により正確にジャンプすること、を実現するためには、追加の工程が必要になる場合がある。この追加の工程を実施し、正確な長さ及びジャンプの提供をおこなうかどうか?のフラグが AVURLAssetPreferPreciseDurationAndTimingKey] になる。
どのような追加の工程が必要か?は、コンテナの形式によて異なる。例えば、QuickTime や MPEG-4 等の多くの形式では追加のパースをしなくとも十分な情報が提供されるが、そうでない形式の場合は、ファイルのコンテンツを予め調査して初めてランダムアクセスが可能になる。.mpg などのフォーマットだとコストがかなり高いとのこと。
ただ、AVPlayer は、正確な時間が利用不可能な場合でも、おおおよそのランダムアクセスがサポートされているので、大抵はそれで十分になる。アセットを AVMutableComposition に格納した場合は、正確なランダムアクセスが望ましく、この値は true にすべき。
この値の状態は、後から providesPreciseDurationAndTiming で確認できる。
https://developer.apple.com/documentation/avfoundation/avurlassetpreferprecisedurationandtimingkey
https://developer.apple.com/documentation/avfoundation/avasset/1390850-providesprecisedurationandtiming
参考
AVAsset | Apple Developer
About the Asset Model | Apple Developer
AVFoundationQueuePlayer-iOS: Using a Mixture of Local File Based Assets and HTTP Live Streaming Assets with AVFoundation | Apple Developer | Documentation Archive