ExoPlayer は、クライアントサイド広告挿入とサーバーサイド広告挿入の両方に使用できます。
クライアントサイド広告挿入
クライアントサイド広告挿入では、コンテンツの再生と広告の再生を切り替える際に、プレーヤーが異なる URL からのメディアの読み込みを切り替えます。広告に関する情報は、XML VAST タグや VMAP タグなど、メディアとは別に読み込まれます。これには、コンテンツの開始点に対する広告キューの位置、実際の広告メディア URI、特定の広告がスキップ可能かどうかなどのメタデータが含まれます。
ExoPlayer の AdsMediaSource
を使用してクライアントサイド広告挿入を行う場合、プレーヤーには再生される広告に関する情報が含まれます。これには、さまざまなメリットがあります。
- プレーヤーは、API を使用して広告に関連するメタデータと機能を公開できます。
- ExoPlayer UI コンポーネントは、広告の位置のマーカーを自動的に表示し、広告の再生中かどうかに応じて動作を変更できます。
- 内部的には、プレーヤーは広告とコンテンツの切り替え間で一貫したバッファを維持できます。
この設定では、プレーヤーが広告とコンテンツの切り替えを行います。つまり、アプリは広告とコンテンツ用の複数の個別のバックグラウンド/フォアグラウンド プレーヤーを制御する必要はありません。
クライアントサイド広告挿入で使用するコンテンツ動画と広告タグを準備する場合は、プレーヤーでコンテンツの再生をシームレスに再開できるように、コンテンツ動画の同期サンプル(キーフレーム)に広告を配置することをおすすめします。
宣言型広告のサポート
広告タグ URI は、MediaItem
の作成時に指定できます。
Kotlin
val mediaItem = MediaItem.Builder() .setUri(videoUri) .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).build()) .build()
Java
MediaItem mediaItem = new MediaItem.Builder() .setUri(videoUri) .setAdsConfiguration( new MediaItem.AdsConfiguration.Builder(adTagUri).build()) .build();
広告タグを指定するメディア アイテムのプレーヤー サポートを有効にするには、プレーヤーを作成するときに、AdsLoader.Provider
と AdViewProvider
で構成された DefaultMediaSourceFactory
をビルドして挿入する必要があります。
Kotlin
val mediaSourceFactory: MediaSource.Factory = DefaultMediaSourceFactory(context).setLocalAdInsertionComponents(adsLoaderProvider, playerView) val player = ExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build()
Java
MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(context) .setLocalAdInsertionComponents(adsLoaderProvider, /* adViewProvider= */ playerView); ExoPlayer player = new ExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build();
内部的には、DefaultMediaSourceFactory
はコンテンツ メディア ソースを AdsMediaSource
でラップします。AdsMediaSource
は AdsLoader.Provider
から AdsLoader
を取得し、メディア アイテムの広告タグで定義されているように広告を挿入します。
ExoPlayer の PlayerView
は AdViewProvider
を実装します。ExoPlayer IMA ライブラリには、以下に説明するように使いやすい AdsLoader
が用意されています。
広告付きのプレイリスト
複数のメディア アイテムを含む再生リストを再生する場合、デフォルトの動作では、広告タグをリクエストし、メディア ID、コンテンツ URI、広告タグ URI の組み合わせごとに広告の再生状態を 1 回保存します。つまり、広告タグの URI が一致していても、メディア ID またはコンテンツ URI が異なる広告が設定されているすべてのメディア アイテムの広告がユーザーに表示されます。メディア アイテムが繰り返された場合、ユーザーには対応する広告が 1 回だけ表示されます(広告の再生ステータスには広告が再生されたかどうかが保存されるため、1 回目の再生後にスキップされます)。
この動作は、オブジェクトの等価性に基づいて、特定のメディア アイテムの広告再生ステータスがリンクされる不透明な広告 ID を渡すことでカスタマイズできます。以下は、広告タグ URI を広告 ID として渡すことで、広告の再生ステータスがメディア ID と広告タグ URI の組み合わせではなく、広告タグ URI のみにリンクされている例です。つまり、広告は 1 回だけ読み込まれ、再生リストを最初から最後まで再生しても、2 番目のアイテムに広告は表示されなくなります。
Kotlin
// Build the media items, passing the same ads identifier for both items, // which means they share ad playback state so ads play only once. val firstItem = MediaItem.Builder() .setUri(firstVideoUri) .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build() val secondItem = MediaItem.Builder() .setUri(secondVideoUri) .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build() player.addMediaItem(firstItem) player.addMediaItem(secondItem)
Java
// Build the media items, passing the same ads identifier for both items, // which means they share ad playback state so ads play only once. MediaItem firstItem = new MediaItem.Builder() .setUri(firstVideoUri) .setAdsConfiguration( new MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build(); MediaItem secondItem = new MediaItem.Builder() .setUri(secondVideoUri) .setAdsConfiguration( new MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build(); player.addMediaItem(firstItem); player.addMediaItem(secondItem);
サーバー ガイド付きクライアントサイド広告挿入
ExoPlayer には、HLS プレイリストで定義された広告をクライアントサイドに自動的に挿入する HlsInterstitialsAdsLoader
が付属しています。詳しくは、HLS ページの HlsInterstitialsAdsLoader
に関するセクションをご覧ください。
ExoPlayer IMA ライブラリ
ExoPlayer IMA ライブラリは ImaAdsLoader
を提供します。これにより、クライアントサイドの広告挿入をアプリに簡単に統合できます。クライアントサイド IMA SDK の機能をラップして、VAST/VMAP 広告の挿入をサポートします。バックグラウンド処理や再生の再開を処理する方法など、ライブラリの使用方法については、README をご覧ください。
デモ アプリケーションは IMA ライブラリを使用しており、サンプルリストにいくつかのサンプル VAST/VMAP 広告タグが含まれています。
UI に関する考慮事項
PlayerView
はデフォルトで広告の再生中にトランスポート コントロールを非表示にしますが、アプリは setControllerHideDuringAds
を呼び出してこの動作を切り替えることができます。IMA SDK では、広告の再生中にプレーヤーの上に追加のビュー(「詳細」リンクやスキップ ボタンなど)が表示されます(該当する場合)。
IMA SDK は、プレーヤーの上にレンダリングされたアプリ提供ビューによって広告が隠されているかどうかを報告する場合があります。再生の制御に不可欠なビューをオーバーレイする必要があるアプリは、ビューアビリティの計算から除外できるように、それらのビューを IMA SDK に登録する必要があります。AdViewProvider
として PlayerView
を使用すると、コントロール オーバーレイが自動的に登録されます。カスタム プレーヤー UI を使用するアプリは、AdViewProvider.getAdOverlayInfos
からオーバーレイ ビューを返すことで、オーバーレイ ビューを登録する必要があります。
オーバーレイ ビューの詳細については、IMA SDK でのオープン測定をご覧ください。
コンパニオン広告
一部の広告タグには、アプリ UI の「スロット」に表示できる追加のコンパニオン広告が含まれています。これらのスロットは ImaAdsLoader.Builder.setCompanionAdSlots(slots)
を介して渡すことができます。詳しくは、コンパニオン広告を追加するをご覧ください。
スタンドアロン広告
IMA SDK は、スタンドアロン広告を単独で再生するためのものではなく、メディア コンテンツに広告を挿入するためのものです。そのため、IMA ライブラリではスタンドアロン広告の再生はサポートされていません。このユースケースでは、代わりに Google Mobile Ads SDK を使用することをおすすめします。
サードパーティの広告 SDK を使用する
サードパーティの広告 SDK を使用して広告を読み込む必要がある場合は、その SDK に ExoPlayer の統合がすでに含まれているかどうかを確認することをおすすめします。そうでない場合は、サードパーティの広告 SDK をラップするカスタム AdsLoader
を実装することをおすすめします。これは、上記の AdsMediaSource
のメリットが得られるためです。ImaAdsLoader
は実装例として機能します。
または、ExoPlayer の再生リストのサポートを使用して、広告とコンテンツ クリップのシーケンスを作成することもできます。
Kotlin
// A pre-roll ad. val preRollAd = MediaItem.fromUri(preRollAdUri) // The start of the content. val contentStart = MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration(ClippingConfiguration.Builder().setEndPositionMs(120000).build()) .build() // A mid-roll ad. val midRollAd = MediaItem.fromUri(midRollAdUri) // The rest of the content val contentEnd = MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration(ClippingConfiguration.Builder().setStartPositionMs(120000).build()) .build() // Build the playlist. player.addMediaItem(preRollAd) player.addMediaItem(contentStart) player.addMediaItem(midRollAd) player.addMediaItem(contentEnd)
Java
// A pre-roll ad. MediaItem preRollAd = MediaItem.fromUri(preRollAdUri); // The start of the content. MediaItem contentStart = new MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration( new ClippingConfiguration.Builder().setEndPositionMs(120_000).build()) .build(); // A mid-roll ad. MediaItem midRollAd = MediaItem.fromUri(midRollAdUri); // The rest of the content MediaItem contentEnd = new MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration( new ClippingConfiguration.Builder().setStartPositionMs(120_000).build()) .build(); // Build the playlist. player.addMediaItem(preRollAd); player.addMediaItem(contentStart); player.addMediaItem(midRollAd); player.addMediaItem(contentEnd);
サーバーサイド広告挿入
サーバーサイド広告挿入(ダイナミック広告挿入、DAI とも呼ばれます)では、メディア ストリームに広告とコンテンツの両方が含まれます。DASH マニフェストは、コンテンツ セグメントと広告セグメントの両方を参照できます。期間が異なる場合もあります。HLS の場合は、再生リストに広告を組み込む方法に関する Apple のドキュメントをご覧ください。
サーバーサイド広告挿入を使用する場合、クライアントは、ステッチされたストリームを取得するためにメディア URL を動的に解決する必要がある場合や、UI に広告オーバーレイを表示する必要がある場合、または広告 SDK または広告サーバーにイベントを報告する必要がある場合があります。
ExoPlayer の DefaultMediaSourceFactory
は、ssai://
スキームを使用する URI のサーバーサイド広告挿入 MediaSource
に、これらのタスクをすべて委任できます。
Kotlin
val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setServerSideAdInsertionMediaSourceFactory(ssaiFactory) ) .build()
Java
Player player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context) .setServerSideAdInsertionMediaSourceFactory(ssaiFactory)) .build();
ExoPlayer IMA ライブラリ
ExoPlayer IMA ライブラリは ImaServerSideAdInsertionMediaSource
を提供するため、アプリで IMA のサーバーサイド挿入広告ストリームを簡単に統合できます。IMA DAI SDK for Android の機能をラップし、提供された広告メタデータをプレーヤーに完全に統合します。たとえば、Player.isPlayingAd()
などのメソッドを使用したり、コンテンツと広告の遷移をリッスンしたり、すでに再生された広告のスキップなど、広告の再生ロジックをプレーヤーに処理させることができます。
このクラスを使用するには、ImaServerSideAdInsertionMediaSource.AdsLoader
と ImaServerSideAdInsertionMediaSource.Factory
を設定してプレーヤーに接続する必要があります。
Kotlin
// MediaSource.Factory to load the actual media stream. val defaultMediaSourceFactory = DefaultMediaSourceFactory(context) // AdsLoader that can be reused for multiple playbacks. val adsLoader = ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(context, adViewProvider).build() // MediaSource.Factory to create the ad sources for the current player. val adsMediaSourceFactory = ImaServerSideAdInsertionMediaSource.Factory(adsLoader, defaultMediaSourceFactory) // Configure DefaultMediaSourceFactory to create both IMA DAI sources and // regular media sources. If you just play IMA DAI streams, you can also use // adsMediaSourceFactory directly. defaultMediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory) // Set the MediaSource.Factory on the Player. val player = ExoPlayer.Builder(context).setMediaSourceFactory(defaultMediaSourceFactory).build() // Set the player on the AdsLoader adsLoader.setPlayer(player)
Java
// MediaSource.Factory to load the actual media stream. DefaultMediaSourceFactory defaultMediaSourceFactory = new DefaultMediaSourceFactory(context); // AdsLoader that can be reused for multiple playbacks. ImaServerSideAdInsertionMediaSource.AdsLoader adsLoader = new ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(context, adViewProvider).build(); // MediaSource.Factory to create the ad sources for the current player. ImaServerSideAdInsertionMediaSource.Factory adsMediaSourceFactory = new ImaServerSideAdInsertionMediaSource.Factory(adsLoader, defaultMediaSourceFactory); // Configure DefaultMediaSourceFactory to create both IMA DAI sources and // regular media sources. If you just play IMA DAI streams, you can also use // adsMediaSourceFactory directly. defaultMediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory); // Set the MediaSource.Factory on the Player. Player player = new ExoPlayer.Builder(context).setMediaSourceFactory(defaultMediaSourceFactory).build(); // Set the player on the AdsLoader adsLoader.setPlayer(player);
ImaServerSideAdInsertionUriBuilder
を使用して URL を作成して、IMA アセットキー(コンテンツ ソース ID と動画 ID)を読み込みます。
Kotlin
val ssaiUri = ImaServerSideAdInsertionUriBuilder() .setAssetKey(assetKey) .setFormat(C.CONTENT_TYPE_HLS) .build() player.setMediaItem(MediaItem.fromUri(ssaiUri))
Java
Uri ssaiUri = new ImaServerSideAdInsertionUriBuilder() .setAssetKey(assetKey) .setFormat(C.CONTENT_TYPE_HLS) .build(); player.setMediaItem(MediaItem.fromUri(ssaiUri));
最後に、広告ローダーが使用されなくなったら解放します。
Kotlin
adsLoader.release()
Java
adsLoader.release();
UI に関する考慮事項
サーバーサイド広告挿入にも、クライアントサイド広告挿入と同じ UI に関する考慮事項が適用されます。
コンパニオン広告
一部の広告タグには、アプリ UI の「スロット」に表示できる追加のコンパニオン広告が含まれています。これらのスロットは ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots)
を介して渡すことができます。詳しくは、コンパニオン広告を追加するをご覧ください。
サードパーティの広告 SDK を使用する
サードパーティの広告 SDK を使用して広告を読み込む必要がある場合は、その SDK に ExoPlayer の統合がすでに提供されているかどうかを確認することをおすすめします。そうでない場合は、ImaServerSideAdInsertionMediaSource
と同様に ssai://
スキームの URI を受け入れるカスタム MediaSource
を指定することをおすすめします。
広告構造の作成の実際のロジックは、汎用 ServerSideAdInsertionMediaSource
に委任できます。これはストリーム MediaSource
をラップし、広告メタデータを表す AdPlaybackState
を設定および更新できるようにします。
サーバーサイドで挿入された広告ストリームには、広告メタデータについてプレーヤーに通知するタイミング付きイベントが含まれていることがよくあります。ExoPlayer でサポートされているタイミング付きメタデータ形式については、サポートされている形式をご覧ください。カスタム広告 SDK の MediaSource
実装では、Player.Listener.onMetadata
を使用してプレーヤーからのタイミング設定されたメタデータ イベントをリッスンできます。