広告の挿入

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 として渡すことで、広告の再生ステータスがメディア 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.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 を使用してプレーヤーからのタイミング設定されたメタデータ イベントをリッスンできます。