ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
AVFoundationにおけるHLSバリアント
AVFoundation APIを使用して、App内でコンテンツの異なるバリアントをハイライトする方法を確認します。SDR/HDR、FPSなどの属性を含むさまざまなビデオ特性について、これらのAPIを使用してHLSコンテンツを検査する方法を紹介します。また、ストリーミングやオフラインのコンテンツを表すAVAssetVarientについても紹介します。
リソース
関連ビデオ
WWDC21
WWDC20
-
ダウンロード
♪ (AVFoundationにおける HLSバリアント) WWDCにようこそ AVFoundationチーム エンジニアの ニシャントです 今日のテーマは HLSバリアントです まずAVFoundation APIで HLSバリアントを 検証する方法を説明し その後HLSバリアントを ダウンロードして 使う方法に移ります ではバリアント検証 から始めましょう 通常の プレイリストについては ご存知ですよね この例の このプレイリストには 2つのバリアントがあります 1つはステレオオーディオの SDRバリアントで もう1つは Dolby Atmosオーディオの Dolby Vision バリアントです このプレイリストを 示すアセットは Appではこのように 表示されているかもしれません よく見てみるとアセットに 4KとDolby Vision Dolby Atmosの バッジがあります 従来はこうした情報は 帯の外にありましたが iOS 15では HLSプレイリストから 直接見られます そのためには マスタープレイリストの 場所を指すAVURLAsset から始めましょう 後でHLSプレイリストを バリアントの プロパティ経由で 得られるようになります このAVAssetVarientは マスタープレイリストからの HLSバリアントを表します 従って様々な メディア属性を 表す複数のプロパティが あります メディアビットレートなど 属性の中には 直接アクセスされる ものもあります 一方で動画・オーディオ レンディション関連のものなど 独自のサブクラスに 一緒にグループ化される ものもあります それぞれ VideoAttribute AudioAttribute と呼ばれます ご覧の通りそれぞれに 関連するプロパティがあり これを使って自分のアセットを 理解できます AVFoundationでHLSバリアントを 検証する方法が分かったので ダウンロードして使う方法を 見ていきましょう オフライン再生用HLS コンテンツダウンロードは 2016年から サポートされています HLS doanload API を初めて聞く方は WWDC 2020の 関連動画を チェックしてください iOS 15では HLS download APIが さらにパワフルになりました 通常はダウンロードに 選択されたHLSバリアントに 影響させたいものです ビジネス的に必要だったり ユーザーにさらなる選択肢を 与えたい場合です 以前はこのようなインプットを downloadTaskオプション 経由で提供できました HDRやロスレスオーディオ その他の属性用の オプションがありました iOS 15では NSPredicatesで バリアント選択が 拡大されています Core Dataからの述語は 既にお使いかもしれません そうでなくても今日説明するので ご心配なく では バリアント修飾語 インターフェイスをご紹介します このインターフェイスでは バリアント設定をAVFoundationに 指定することができます 私が述べた通り NSPredicateを使って 構築可能です 分かりやすいように いくつか例を見ましょう ピークのビットレートが 5MB以下になるよう 式で表されたNSPredicate があります これを使って バリアント修飾語を構築します するとそれがAVFoundationを 5MB以下のバリアントを 好むように構築します 非常に単純ですね 別の例を 見てみましょう HDRビデオレンジの NSPredicateを作成します 前と同じように そのためのバリアント 修飾語を構築できます また2つの述語を 組み合わせて 複合述語を作ったり バリアント修飾語を 作ったりもできます バリアントのプロパティは それに対する述語を作るのに 使えます 述語フォーマット 文字列では 式を書きにくい オーディオチャネルカウント などのプロパティにも カスタムのコンストラクタ を用意しました バリアント修飾語の ヘッダー ドキュメント内から 検索できます バリアント修飾語を 用意したら それを使ってコンテンツ コンフィギュレーションを作ります コンテンツコンフィギュレーション はそれぞれ動画やオーディオ 字幕レンディションのセットを 示します 例を使って 理解しましょう これは先程見た 2つの述語を複合する バリアント修飾語です 確かに複合ですね これはAVFoundationに 5MB以下のHDRバリアントを 優先するよう通知します また 英語やフランス語 のオーディオや 英語字幕レンディション を示す メディア選択のセットも あります これらは両方とも コンテンツコンフィギュレーション オブジェクト作成に使えます こうしたコンテンツ コンフィギュレーションを 複数作成し downloadTask に提供できます これら複数のコンテンツ コンフィギュレーションは ダウンロードコンフィギュレーション で束ねられます これは全てをまとめている ルートです AVURLAssetで作成され アセット名や任意で 画像が必要です アセット名と画像は 設定Appに表示されています これでユーザーは 全てのダウンロードを 設定Appという 1つの場所から管理できます そしてもちろん downloadTaskは 複数のコンテンツコンフィギュレーション で構成可能です よく見てみましょう コンテンツコンフィギュレーション の1つは プライマリとして 残りは 補助として指定されます この2つの違いは 通常は最優先の動画やオーディオ 字幕レンディションを ダウンロードし それらを追加オーディオや 字幕レンディションで 補完したいからです 追加のレンディションを 補助コンテンツ コンフィギュレーションとして 指定することで AVFoundationの最適化 を支持し 動画レンディションの ダウンロードを回避できます 例で説明すると より分かりやすいでしょう ここに完璧な例があります まずAVURLAssetとタイトルで ダウンロード コンフィギュレーション を作成します プライマリコンテンツ コンフィギュレーションは 先程のものと同じです 5MB以下のHDRバリアントを 英語とフランス語音声と 英語字幕レンディションで ダウンロードする構成です この例では それを補助コンテンツ コンフィギュレーションで 補完して 英語音声をロスレスフォーマットで ダウンロードしたいです ダウンロードしたい コンテンツコンフィギュレーション は両方揃っています optimizesAuxiliary ContentConfigurations はtrueに設定します ところでデフォルトでは trueになっていて AVFoundationはロスレス バリアントを選択できます ロスレスバリアントの 動画レンディションが プライマリコンテンツ コンフィギュレーションと同じなどです falseにすると ロスレスバリアントが 別々で評価され 二重の動画レンディションが ダウンロードされる場合があります ダウンロードサイズも増えるという 嫌な結果になります さて ダウンロード コンフィギュレーションが済んだら それでdownloadTaskを 作成できます downloadTaskを再開し ダウンロードを開始しましょう iOS 15以降は NSProgressインターフェイスで downloadTaskの進捗を チェックすることもできます NSProgressオブジェクトは KVO-observableなので それでユーザーインターフェイス を更新できます 次にいきましょう Appleではバリアントの選択に ビジネス的要素の検討も 含まれると理解しています そのため述語経由で式を書くのは より大変かもしれません そうしたケースでは ダウンロードしたい バリアントを明示的に 選択することもできます この例では プライマリ・補助バリアントを 既に選択済みで メディア選択の準備は 万端です 修飾語を直接 バリアントで作成することで AVFoundationにそのまま ダウンロードするよう指示できます ダウンロード時にデバイスで 再生できるよう バリアントは注意深く 選びましょう 今日のテーマはここまでです まとめると HLSバリアントを検証し downloadTaskの 構成に用いる方法を 見てきました その時 downloadTask コンフィギュレーションで 様々なインターフェイスが ありました 1番目はバリアント 修飾語で バリアント設定を 書くのに使われます 次はコンテンツコン フィギュレーションインターフェイスで これはバリアント設定と メディア選択内容を つなぐのに用いられます 最後はダウンロード コンフィギュレーションです これは全てを結合させる ルートインターフェイスです 最後になりましたが downloadTaskを NSProgressで 監視できることも学びました 詳しくはAppleの詳しい ヘッダードキュメント をご覧ください ご視聴ありがとうございました ♪
-
-
0:40 - HLS Master Playlist
#EXTM3U #EXT-X-VERSION:7 #EXT-X-INDEPENDENT-SEGMENTS #EXT-X-MEDIA:TYPE=AUDIO,NAME="English",GROUP-ID="stereo",LANGUAGE="en",DEFAULT=YES, AUTOSELECT=YES,CHANNELS="2",URI="en_stereo.m3u8" #EXT-X-MEDIA:TYPE=AUDIO,NAME="French",GROUP-ID="stereo",LANGUAGE="fr",DEFAULT=NO, AUTOSELECT=YES,CHANNELS="2",URI="fr_stereo.m3u8" #EXT-X-MEDIA:TYPE=AUDIO,NAME="English",GROUP-ID="atmos",LANGUAGE="en",DEFAULT=YES, AUTOSELECT=YES,CHANNELS="16/JOC",URI="en_atmos.m3u8" #EXT-X-MEDIA:TYPE=AUDIO,NAME="French",GROUP-ID="atmos",LANGUAGE="fr",DEFAULT=NO, AUTOSELECT=YES,CHANNELS="16/JOC",URI="fr_atmos.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=14516883,VIDEO-RANGE=SDR,CODECS="avc1.64001f,mp4a.40.5", AUDIO="stereo",FRAME-RATE=23.976,RESOLUTION=1920x1080 sdr_variant.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=34516883,VIDEO-RANGE=PQ,CODECS="dvh1.05.06,ec-3", AUDIO="atmos",FRAME-RATE=23.976,RESOLUTION=3840x1920 dovi_variant.m3u8
-
3:38 - Peak bitrate cap predicate
let peakBitRateCap = NSPredicate(format: "peakBitRate < 5000000") let peakBitRateCapQualifier = AVAssetVariantQualifier(predicate: peakBitRateCap)
-
3:55 - HDR predicate
let hdrOnlyPredicate = NSPredicate(format: "videoAttributes.videoRange == %@", argumentArray: [AVVideoRange.pq]) let hdrOnlyQualifier = AVAssetVariantQualifier(predicate: hdrOnlyPredicate)
-
4:46 - Content configuration
let variantPref = AVAssetVariantQualifier(predicate: NSPredicate(format: "videoAttributes.videoRange == %@ && peakBitRate < 5000000", argumentArray: [AVVideoRange.pq])) let myMediaSelections : [AVMediaSelection] = [enAudioMS, frAudioMS, enLegibleMS] //English, French audio and English subtitle renditions let contentConfig = AVAssetDownloadContentConfiguration() contentConfig.variantQualifiers = [variantPref] contentConfig.mediaSelections = myMediaSelections
-
6:29 - Download configuration
let asset = AVURLAsset(url: URL(string: "http://example.com/master.m3u8")!) let dwConfig = AVAssetDownloadConfiguration(asset: asset, title: "my-title") /* Primary content config */ let varPref = NSPredicate(format: "videoAttributes.videoRange == %@ && peakBitRate < 5000000", argumentArray: [AVVideoRange.pq]) let varQf = AVAssetVariantQualifier(predicate: varPref) dwConfig.primaryContentConfiguration.variantQualifiers = [varQf] dwConfig.primaryContentConfiguration.mediaSelections = [enAudioMS, frAudioMS, enLegibleMS] //English, French audio and English subtitle renditions /* Aux content config */ let auxVarPref = NSPredicate(format: "%d IN audioAttributes.formatIDs", argumentArray: [kAudioFormatAppleLossless]) let auxVarQf = AVAssetVariantQualifier(predicate: auxVarPref) let auxContentConfig = AVAssetDownloadContentConfiguration() auxContentConfig.variantQualifiers = [auxVarQf] auxContentConfig.mediaSelections = [enAudioMS] //english audio dwConfig.auxiliaryContentConfigurations = [auxContentConfig] dwConfig.optimizesAuxiliaryContentConfigurations = true
-
7:42 - Download task
let myAssetDownloadDelegate = MyDownloadDelegate() let avurlsession = AVAssetDownloadURLSession(configuration: URLSessionConfiguration.background(withIdentifier: "my-background-session"), assetDownloadDelegate: myAssetDownloadDelegate, delegateQueue: OperationQueue.main) let asset = AVURLAsset(url: URL(string: "http://example.com/master.m3u8")!) let dwConfig = AVAssetDownloadConfiguration(asset: asset, title: “my-title”) ... let downloadTask = avurlsession.makeAssetDownloadTask(downloadConfiguration: dwConfig) downloadTask.resume() let progress = downloadTask.progress
-
8:10 - Direct variant selection
/* Example for direct variant selection */ let asset = AVURLAsset(url: URL(string: "http://example.com/master.m3u8")!) let dwConfig = AVAssetDownloadConfiguration(asset: asset, title: "my-title") /* Primary content config */ let myVariant : AVAssetVariant = ... let myMediaSelections : [AVMediaSelection] = ... let variantQf = AVAssetVariantQualifier(variant: myVariant) dwConfig.primaryContentConfiguration.variantQualifiers = [variantQf] dwConfig.primaryContentConfiguration.mediaSelections = myMediaSelections /* Aux content config */ let myAuxVariant : AVAssetVariant = ... let myAuxMediaSelections : [AVMediaSelection] = ... let auxVariantQf = AVAssetVariantQualifier(variant: myAuxVariant) let auxContentConfig = AVAssetDownloadContentConfiguration() auxContentConfig.variantQualifiers = [auxVariantQf] auxContentConfig.mediaSelections = myAuxMediaSelections dwConfig.auxiliaryContentConfigurations = [auxContentConfig]
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。