広告の挿入

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.ProviderAdViewProvider で構成された 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 でラップします。AdsMediaSourceAdsLoader.Provider から AdsLoader を取得し、それを使用して、メディア アイテムの広告タグで定義されている広告を挿入します。

ExoPlayer の PlayerViewAdViewProvider を実装します。ExoPlayer IMA ライブラリには、以下で説明するように、使いやすい AdsLoader が用意されています。

広告付きのプレイリスト

複数のメディア アイテムを含む再生リストを再生する場合、デフォルトの動作では、広告タグをリクエストし、メディア ID、コンテンツ URI、広告タグ URI の組み合わせごとに広告の再生状態を 1 回保存します。つまり、広告タグの URI が一致していても、メディア ID またはコンテンツ URI が異なる広告が掲載されているすべてのメディア アイテムの広告がユーザーに表示されます。メディア アイテムが繰り返された場合、ユーザーには対応する広告が 1 回だけ表示されます(広告の再生ステータスには広告が再生されたかどうかが保存されるため、1 回目の再生後にスキップされます)。

この動作をカスタマイズするには、オブジェクトの等価性に基づいて、特定のメディア アイテムの広告再生ステータスがリンクされる不透明な広告 ID を渡します。次の例では、広告タグ URI を広告識別子として渡すことで、広告の再生ステータスがメディア 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 IMA ライブラリ

ExoPlayer IMA ライブラリImaAdsLoader を提供します。これにより、クライアントサイドの広告挿入をアプリに簡単に統合できます。クライアントサイド IMA SDK の機能をラップして、VAST/VMAP 広告の挿入をサポートします。バックグラウンド処理や再生の再開を処理する方法など、ライブラリの使用方法については、README をご覧ください。

デモ アプリケーションは IMA ライブラリを使用しており、サンプルリストにいくつかのサンプル VAST/VMAP 広告タグが含まれています。

UI に関する考慮事項

PlayerView は、デフォルトで広告の再生中にトランスポート コントロールを非表示にしますが、アプリは setControllerHideDuringAds を呼び出してこの動作を切り替えることができます。IMA SDK では、広告の再生中にプレーヤーの上に追加ビュー([詳細] リンクやスキップ ボタンなど)が表示されます(該当する場合)。

IMA SDK は、プレーヤーの上にレンダリングされるアプリ提供のビューによって広告が隠されているかどうかを報告できます。再生の制御に不可欠なビューをオーバーレイする必要があるアプリは、ビューアビリティの計算から除外できるように、それらのビューを IMA SDK に登録する必要があります。PlayerViewAdViewProvider として使用すると、そのコントロール オーバーレイが自動的に登録されます。カスタム プレーヤー UI を使用するアプリは、AdViewProvider.getAdOverlayInfos からオーバーレイ ビューを返して登録する必要があります。

オーバーレイ ビューについて詳しくは、IMA SDK の Open Measurement をご覧ください。

コンパニオン広告

一部の広告タグには、アプリの UI の「スロット」に表示できる追加のコンパニオン広告が含まれています。これらのスロットは ImaAdsLoader.Builder.setCompanionAdSlots(slots) を介して渡すことができます。詳しくは、コンパニオン広告を追加するをご覧ください。

スタンドアロン広告

IMA SDK は、スタンドアロン広告を単独で再生するためのものではなく、メディア コンテンツに広告を挿入するためのものです。そのため、IMA ライブラリでは単独の広告を再生することはできません。このユースケースでは、代わりに Google Mobile Ads 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.AdsLoaderImaServerSideAdInsertionMediaSource.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 を使用してプレーヤーからのタイミング設定されたメタデータ イベントをリッスンできます。