View in English

  • メニューを開く メニューを閉じる
  • Apple Developer
検索
検索を終了
  • Apple Developer
  • ニュース
  • 見つける
  • デザイン
  • 開発
  • 配信
  • サポート
  • アカウント
次の内容に検索結果を絞り込む

クイックリンク

5 クイックリンク

ビデオ

メニューを開く メニューを閉じる
  • コレクション
  • トピック
  • すべてのビデオ
  • 利用方法

WWDC24に戻る

ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。

  • 概要
  • トランスクリプト
  • コード
  • HLSインタースティシャルによる広告体験の向上

    HLSインタースティシャルを使用すると、HLSコンテンツに広告をシームレスに挿入できます。統合されたタイムラインを使用してUI体験を調整し、インタースティシャル対応のSharePlayを構築する方法もご紹介します。

    関連する章

    • 0:00 - Introduction
    • 0:45 - Interstitals recap
    • 1:56 - Integrated timeline
    • 10:40 - SharePlay with interstitials

    リソース

    • Forum: Media Technologies
    • Providing an integrated view of your timeline when playing HLS interstitials
      • HDビデオ
      • SDビデオ

    関連ビデオ

    WWDC21

    • Group Activitiesによるメディアエクスペリエンス連携
    • HLSにおけるダイナミックなプレロールとミッドロール
  • このビデオを検索

    こんにちは AVFoundationエンジニアのJulianです 近年 メインコンテンツに 広告を挿入する簡単な方法として HLSインタースティシャルが導入されました 今年はインタースティシャルを使用して 表示および操作する新しい方法を提供します 広告掲載に関心がある方や HLSインタースティシャルを新しい方法で 組み込む方法を学びたい方にとって 本セッションは最適です まず 現在のHLSインタースティシャルの 仕組みを振り返ります

    次に 新しいIntegrated Timeline APIを ご紹介します このAPIは アプリのUI体験を 構築するためのデータモデルを提供します

    最後に インタースティシャル対応の SharePlayの新機能を解説します

    それでは HLSインタースティシャルの概要 を簡単に復習しましょう

    HLSインタースティシャルでは 広告やインタースティシャルは別のアセットで メインコンテンツのタイムラインで スケジュール設定することができます これは典型的なメディアプレイリストです 例えば コンテンツの開始5秒後に インタースティシャルを再生する場合は コンテンツのPROGRAM-DATE-TIMEで START-DATEを5秒に指定します すると メインコンテンツが 5秒まで再生された後 インタースティシャルURLの再生が 開始されます その後 インタースティシャルが終了すると メインコンテンツの再生が再開されます

    HLSインタースティシャルには メインコンテンツへの広告の直接挿入では 得られない多くの利点があります インタースティシャルでは 遅延バインディングによる広告決定ができ 広告をメインコンテンツと 組み合わせる必要がありません HLSインタースティシャルは主に 広告の挿入に使われてきましたが その他の補助コンテンツの表示に 使用することをおすすめします 番組のプロモーション スタジオのバナー 番組の要約のセグメントなど 区切りとして挿入されるコンテンツの 代わりに表示します 以上はHLSインタースティシャルの コンテンツへの 挿入に関する説明のほんの一部です 詳細については 「Explore dynamic pre-rolls and mid-rolls in HLS」をご覧ください Integrated Timelineと呼ばれる 新しいAVFoundation APIが 今年提供開始されます このAPIは インタースティシャルを使ったコンテンツの 再生タイミングと シーケンスのデータモデルを導入します このデータモデルを活用すれば 新しいUI体験を構築でき ユーザーはインタースティシャルの表示の 滑らかな切り替えが可能になります

    まず インタースティシャルを 統合されたタイムラインに表示する 様々な方法の概要を説明します

    その後 APIとその使い方の説明に 進みます 次に Integrated Timelineを使用して UIを構築する サンプルアプリをお見せします 最後に Integrated Timelineでの インタースティシャルの動作を記述する 新しいHLS構文について説明します

    まずは インタースティシャルを タイムラインに表示する各種の方法です

    VODコンテンツへの広告挿入の 一般的なユースケースは トランスポートバー上のポイントとして インタースティシャルをマークすることです 再生がこのポイントに達すると 再生ヘッドが停止し インタースティシャルが再生されます インタースティシャルの終了後 メインコンテンツが再開され 再生ヘッドが先に進みます ほかのユースケースの例は インタースティシャルを トランスポートバーに範囲として表示し インタースティシャルの再生時間が トランスポートバー全体の再生時間に 含まれるようにすることです

    これは ブロードキャスト形式の ライブストリームにおける広告や インタースティシャルで 埋め込みの コンテンツを置き換える場合に使われます

    最後の例は 先ほどの例を拡張したものです 先ほどの例では UIのインタースティシャルが 黄色いハイライトで示されていました ここではインタースティシャルは メインコンテンツと 区別がつかないものとして組み込まれます これは HLSインタースティシャルを 評価バンパー 番組の要約などのプリロール 吹き替えなどのポストロールに 使用する場合に役立ちます 特に コンテンツがメインコンテンツと 密接に関連している場合に適しています

    統合タイムラインでモデル化される 様々なケースを確認したところで 各ユースケースで再生時点を示す AVPlayerInterstitalEvent APIの 追加機能を見てみましょう

    タイムライン上のポイントを示すには インタースティシャルイベントを作成します 次に timelineOccupancyという 新しいプロパティを設定し 値をsinglePointにします

    タイムライン上の範囲を示すには イベントのtimelineOccupancyを fillに設定します ただし インタースティシャルイベントは 動的に読み込まれるため 再生ヘッドが近づいた際 イベントの実際の再生時間の 検出が遅れる可能性があります plannedDurationをタイムラインの フォールバックとして指定すれば 実際の再生時間がわかるまでの間 使用できます 範囲を指定するインタースティシャルでは このプロパティを設定しましょう

    最後のケースでは インタースティシャルの範囲を UI上で区別できないようにするために supplementsPrimaryContentを trueに設定します

    タイムライン上で インタースティシャルの 再生時点を示す方法を確認しました 次は Integrated Timeline APIの解説です

    タイムラインの進行を確認するために Integrated Timelineには currentTimeを 取得するためのAPIが用意されています

    再生ヘッドがPointEventに到達すると currentTimeが停止して イベントが再生されます

    イベントの再生が終わると currentTimeは再び進みます 一方 次のFillのインタースティシャル イベントに到達した際は currentTimeは進み続けたままで イベントが再生されます

    このAPIには インタースティシャル内の シーク機能も用意されています 例えば クライアントが10秒進めて シークしたいと仮定します これはFillEventの真ん中まで 進むことになります このAPIを使わない場合 このシークの実行は難しいでしょう 特に インタースティシャルイベントは 現時点で AVPlayerに読み込まれることも キューに入れられることもないためです このAPIを使えば タイムライン上の任意の位置に 簡単にシークできます メインコンテンツか インタースティシャルかは関係ありません Integrated Timelineの一部として AVPlayerItemSegmentという 新しいオブジェクトが用意されています タイムラインの各領域はセグメントであり 各セグメントには コンテンツに関する主要な詳細情報と タイムライン上での占有時間が 設定されています メインコンテンツの範囲も セグメントと見なされます

    Integrated Timelineの最大のメリットは 再生UIを簡単に描画できることです ただし タイムラインは常に変化するので その描画は難しい場合があります 一貫した状態を維持するために導入したのが タイムラインから取得できる スナップショットオブジェクトです スナップショットは UIの描画に必要な 一貫性のあるプロパティセット全体を表します

    再生が進んでタイムラインが変化しても 下部のスナップショットは固定されており 変化しません

    AVPlayerItemIntegratedSnapshotを 使用すると そのスナップショットに含まれるすべての AVPlayerItemSegmentの一覧を取得できます この例では いくつかのセグメントを取り出して その値を確認できるようにしました 例えば スナップショット内の 最初のメインセグメントは メインとしてマークされ タイムライン上の0〜5の範囲を占めます 次のセグメントはインタースティシャルで PointEventです このセグメントの占有範囲は5〜5であり 再生時間はゼロです インタースティシャルイベントへの アクセスも提供し これにはtimelineOccupancyも singlePointとして含まれます

    選択された最後のセグメントは FillEventです このセグメントはタイムライン上の 20〜30の範囲を占めており timelineOccupancyはfillです

    すべての主要なオブジェクトを確認しました 次は Integrated Timelineを使った シンプルなUIの作成方法です まず メインのAVPlayerItemを作成します 次に AVPlayerItemから integratedTimelineを取得します タイムラインからスナップショットを取得し 現在の状態を描画できるようになりました 開始位置 終了位置 現在の位置を指定するだけで UIスライダを描画するルーチンがあると 仮定しましょう これらの値はすべて スナップショットから取得できます startはzeroで durationは スナップショットの再生時間です currentPositionは スナップショットのcurrentTimeです この時点で シンプルなトランスポートバーができました スライダ全体の一部として fillインタースティシャルが含まれます 次に タイムラインに 1つのポイントを描画してみます ポイントイベントの位置を取得するには スナップショットのセグメントをフィルタし Typeがinterstitialで timelineOccupancyがsinglePointの セグメントのみを取得します

    それぞれのセグメントで セグメントのtimeMapping.target.startを タイムライン全体での位置として使って ポイントを描画します

    最後に fillインタースティシャルを ハイライトします ここではスナップショットの セグメントをフィルタし occupancyがfillの インタースティシャルを表す セグメントを取得します supplementsPrimaryContentは イベントがUI上で 区別されるべきでないことを示すので これが設定されたインタースティシャルは 無視されます セグメントを取得したら セグメントのtimeMapping.targetを使って UIスライダ上のその領域をハイライトします

    タイムラインは極めて動的で 各インタースティシャルの完了とともに 頻繁に変化します ライブストリームの場合も 頻繁に更新されます そのため タイムラインの snapshotsOutOfSyncNotificationをリッスンし その発生時には UIを更新する必要があります 通知クロージャが呼び出されたら 理由をuserInfoで調査できます 例えば 理由がsegmentsChangedであれば 新しいスナップショットを使って トランスポートバーを再描画できます 一方 理由が currentSegmentChangedであれば インタースティシャルとの 切り替えを行っている場合は playerControlsや その他のUI要素を更新します

    以上 APIとサンプルコードを確認しました 次に 本セッションに関連する サンプルアプリを見てみます

    このサンプルアプリには 様々な例が含まれています Fill Interstitialという例を 見てみましょう コンテンツ開始10秒後に再生されるよう 範囲設定したインタースティシャルを含みます

    下部のトランスポートバーを見ると インタースティシャルが 10秒後の 黄色の範囲から開始することがわかります 再生すると 想定したタイミングで インタースティシャルに切り替わります

    ここでシークをいくつか試し メインコンテンツに戻ってみましょう 最後に インタースティシャルまで戻ります

    いいですね

    先ほど アプリでインタースティシャルを 作成する方法を説明しましたが メインプレイリストで 指定することもできます サーバからタイムライン上の表示を 記述する方法を説明します

    ポイントの例から見ていきます これはHLSインタースティシャルの DateRangeタグです タイムラインで これをポイントと見なすために 新しい属性である X-TIMELINE-OCCUPIESを導入しました 値がPOINTとして設定されています DateRangeタグには新たに X-TIMELINE-STYLEの属性も含まれており 値はHIGHLIGHTです これは UI表示でこのポイントを マークしなければならないことを示しています

    範囲を設定する場合 新しい属性 X-TIMELINE-OCCUPIESの値は RANGEに設定されています X-TIMELINE-STYLEは 先ほどの例と同じです

    最後に インタースティシャルをUI上で 区別できないように表示する場合 X-TIMELINE-OCCUPIESはRANGEのままです X-TIMELINE-SYTLEはPRIMARYに設定し アプリのUI内で その領域を特別な スタイルで表示しないことを示します

    Integrated Timelineでは インタースティシャルを メインコンテンツの一部として UIに表示できるので インタースティシャルを SharePlayセッション中に 連携させられると便利です そこで今年 インタースティシャルの 連携のサポートを追加します

    インタースティシャル対応の SharePlayの仕組みと その利用方法を見てみましょう 2つのプレイヤーで SharePlayセッションを連携させています 考え方としては Player1とPlayer2の両方が Event1の再生中も引き続き再生を同期します

    シークについては Player1で Event1からメインコンテンツに 戻ろうとしているとします このシークはPlayer2に提案され 両方のプレイヤーが この新しいポイントから引き続き 再生を同期します インタースティシャルを SharePlayでサポートするための 重要な要件の一つは インタースティシャルイベントが 参加者全員に共通のものであることです つまり この例のEvent1は 両方のプレイヤーで共通している必要があり 同じコンテンツでなければなりません インタースティシャルが共通でない場合 インタースティシャルの再生は プレイヤー間で連携しません この要件に対応する方法を見てみましょう

    AVPlayerInterstitialEventに 追加された新機能として 参加者や再生セッションにより コンテンツが変わるかを ブール値で指定できます この例では contentMayVaryをfalseに設定して このインタースティシャルが静的であり 共通することを示すことで イベントが連携可能になります

    最後に DateRangeタグで 同じ動作を実現するために 新しい属性 X-CONTENT-MAY-VARYを NOに設定することもできます

    では SharePlay対応の サンプルアプリを見てみましょう FaceTime通話で 2台のスマートフォンを使用しています このデモでは コンテンツの開始10秒後に インタースティシャルを再生する Fill(Supplements Primary)の例を 選択します

    両方のスマートフォンで 起動が同期されており インタースティシャルに切り替わっても 同期状態が続きます その後 一時停止して 後方にシークし 最後に前方にシークします

    これらすべてのコマンドが 両方のデバイスでシームレスに機能します まとめです インタースティシャルを含むUI体験の構築に Integrated Timelineを活用できます インタースティシャルの体験を カスタマイズするために APIまたは新しいDateRange属性で 動作を指定できます また APIでインタースティシャルを 変更不可としてマークすることで インタースティシャルアセットの SharePlayでの連携をサポートできます 関連するセッションである 「Explore dynamic pre-rolls and mid-rolls in HLS」もご覧ください HLSインタースティシャルの 詳細を説明しています SharePlayの詳細については 「Coordinate media experiences with Group Activities」をご覧ください ご視聴ありがとうございました

    • 3:55 - Create a point interstitial event

      // Creating a single point interstitial event
       
      let pointEvent = AVPlayerInterstitialEvent(primaryItem: playerItem, time: ten)
      
      pointEvent.timelineOccupancy = .singlePoint
    • 4:07 - Create a fill interstitial event

      // Creating a fill interstitial event
          
      let fillEvent = AVPlayerInterstitialEvent(primaryItem: playerItem, time: ten)
      
      fillEvent.timelineOccupancy = .fill
      fillEvent.plannedDuration = CMTime(value: 15, timescale: 1)
    • 4:32 - Create fill interstitial supplementing primary

      // Creating a fill interstitial event supplementing primary
       
      let fillEvent2 = AVPlayerInterstitialEvent(primaryItem: playerItem, time: ten)
      
      fillEvent2.supplementsPrimaryContent = true
      fillEvent2.timelineOccupancy = .fill
      fillEvent2.plannedDuration = CMTime(value: 15, timescale: 1)
    • 7:14 - Draw simple transport bar with integrated timeline

      // Create AVPlayerItem and obtain its integrated timeline
      
      let item = AVPlayerItem(url: ...)
      let integratedTimeline = item.integratedTimeline
      
      //  Any time we need a new representation of the timeline state, we can request for a snapshot
      let snapshot = integratedTimeline.currentSnapshot
      
      //  Using our snapshot, we can build a simple transport bar
      drawUISlider(start: .zero, duration: snapshot.duration, currentPosition: snapshot.currentTime)
      
      // Draw single-point interstitials on the transport bar
      let pointSegments = snapshot.segments.filter { segment in
          segment.segmentType == .interstitial &&
          segment.interstitialEvent?.timelineOccupancy == .singlePoint
      }
      for segment in pointSegments {
          drawPoint(position: segment.timeMapping.target.start)
      }
      
      // Draw range interstitials on the transport bar
      let highlightFillSegments = snapshot.segments.filter { segment in
          if (segment.segmentType == .interstitial) {
              if let interstitialEvent = segment.interstitialEvent {
                  return interstitialEvent.timelineOccupancy == .fill &&
                         !interstitialEvent.supplementsPrimaryContent
              }
          }
          return false
      }
      
      for segment in highlightFillSegments {
          let range = segment.timeMapping.target
          highlightRegion(start: range.start, end: range.end)
      }
    • 8:26 - Listen to snapshotsOutOfSyncNotification to update our UI

      // Listen to integrated timeline notifications to update our logic
      
      for await _ in NotificationCenter.default.notifications(named: AVPlayerItemIntegratedTimeline.snapshotsOutOfSyncNotification, object: integratedTimeline) {
      
          let reason = _.userInfo![AVPlayerItemIntegratedTimeline.snapshotsOutOfSyncReasonKey] 
                      as! AVPlayerIntegratedTimelineSnapshotsOutOfSyncReason
                      
          switch(reason) {
          case .segmentsChanged:
              redrawTransportBar(snapshot: integratedTimeline.currentSnapshot)
          case .currentSegmentChanged:
              updatePlayerControls(snapshot: integratedTimeline.currentSnapshot)
          }
      }
    • 11:42 - Set ContentMayVary to false for Interstitial SharePlay support

      // Set contentMayVary to false for SharePlay support
      let event = AVPlayerInterstitialEvent(primaryItem: playerItem, time: ten)
      event.contentMayVary = false
      event.timelineOccupancy = .fill
      event.plannedDuration = CMTime(value: 15, timescale: 1)
      event.supplementsPrimaryContent = truensert code snippet.

Developer Footer

  • ビデオ
  • WWDC24
  • HLSインタースティシャルによる広告体験の向上
  • メニューを開く メニューを閉じる
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    メニューを開く メニューを閉じる
    • アクセシビリティ
    • アクセサリ
    • App Extension
    • App Store
    • オーディオとビデオ(英語)
    • 拡張現実
    • デザイン
    • 配信
    • 教育
    • フォント(英語)
    • ゲーム
    • ヘルスケアとフィットネス
    • アプリ内課金
    • ローカリゼーション
    • マップと位置情報
    • 機械学習
    • オープンソース(英語)
    • セキュリティ
    • SafariとWeb(英語)
    メニューを開く メニューを閉じる
    • 英語ドキュメント(完全版)
    • 日本語ドキュメント(一部トピック)
    • チュートリアル
    • ダウンロード(英語)
    • フォーラム(英語)
    • ビデオ
    Open Menu Close Menu
    • サポートドキュメント
    • お問い合わせ
    • バグ報告
    • システム状況(英語)
    メニューを開く メニューを閉じる
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles(英語)
    • フィードバックアシスタント
    メニューを開く メニューを閉じる
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(英語)
    • News Partner Program(英語)
    • Video Partner Program(英語)
    • セキュリティ報奨金プログラム(英語)
    • Security Research Device Program(英語)
    Open Menu Close Menu
    • Appleに相談
    • Apple Developer Center
    • App Store Awards(英語)
    • Apple Design Awards
    • Apple Developer Academy(英語)
    • WWDC
    Apple Developerアプリを入手する
    Copyright © 2025 Apple Inc. All rights reserved.
    利用規約 プライバシーポリシー 契約とガイドライン