広告の挿入

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 回だけ表示されます(広告の再生状態には広告が再生されたかどうかが保存されるため、広告は初回再生後にスキップされます)。

この動作は、特定のメディア アイテムの広告再生状態がオブジェクトの等価性に基づいてリンクされている不透明な広告識別子を渡すことでカスタマイズできます。次の例では、広告タグ 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 にビューを登録する必要があります。PlayerViewAdViewProvider として使用すると、コントロール オーバーレイが自動的に登録されます。カスタム プレーヤー UI を使用するアプリは、AdViewProvider.getAdOverlayInfos からオーバーレイ ビューを返すことで、オーバーレイ ビューを登録する必要があります。

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

コンパニオン広告

一部の広告タグには、アプリの 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(MediaItem.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(MediaItem.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 MediaItem.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 MediaItem.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 のサーバーサイド挿入広告ストリームを簡単に統合できるようにします。このライブラリは Android 用 IMA DAI SDK の機能をラップし、提供された広告メタデータをプレーヤーに完全に統合します。たとえば、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 を使用してプレーヤーからのタイムド メタデータ イベントをリッスンできます。