插入廣告

ExoPlayer 可用於用戶端和伺服器端廣告插播。

用戶端廣告插播

在用戶端廣告插播中,播放器會在播放內容和廣告之間切換時,從不同網址載入媒體。廣告資訊會與媒體分開載入,例如從 XML VAST 或 VMAP 廣告代碼載入。這類資訊包括廣告提示相對於內容開頭的位置、實際廣告媒體 URI,以及特定廣告是否可略過等中繼資料。

使用 ExoPlayer 的 AdsMediaSource 插入用戶端廣告時,播放器會取得要播放的廣告資訊。這麼做有幾個好處:

  • 播放器可使用其 API 公開與廣告相關的中繼資料和功能。
  • ExoPlayer UI 元件可自動顯示廣告位置標記,並根據廣告是否播放來變更行為。
  • 在內部,播放器可以在廣告和內容之間切換時,保持一致的緩衝區。

在這種設定下,播放器會負責切換廣告和內容,因此應用程式不必控制多個獨立的背景和前景播放器,來播放廣告和內容。

準備內容影片和廣告代碼,以便與用戶端廣告插播搭配使用時,廣告最好放在內容影片的同步範例 (主要畫面格) 中,這樣播放器才能順暢地繼續播放內容。

宣告式廣告支援

建構 MediaItem 時,可以指定廣告代碼 URI:

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 組合,請求廣告代碼並儲存廣告播放狀態一次。也就是說,即使廣告代碼 URI 相同,只要媒體 ID 或內容 URI 不同,使用者就會看到每個媒體項目的廣告。如果媒體項目重複,使用者只會看到對應的廣告一次 (廣告播放狀態會儲存廣告是否已播放,因此在首次播放後會略過)。

您可以傳遞不透明的廣告 ID,根據物件相等性連結特定媒體項目的廣告播放狀態,藉此自訂這項行為。以下範例將廣告代碼 URI 做為廣告 ID 傳遞,因此廣告播放狀態只會連結至廣告代碼 URI,而非媒體 ID 和廣告代碼 URI 的組合。這樣一來,廣告只會載入一次,使用者從頭到尾播放播放清單時,就不會在第二個項目看到廣告。

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 隨附 HlsInterstitialsAdsLoader,支援在用戶端自動插入 HLS 播放清單中定義的廣告。請參閱 HLS 頁面中關於 HlsInterstitialsAdsLoader 的章節。

ExoPlayer IMA 程式庫

ExoPlayer IMA 程式庫提供 ImaAdsLoader,可將用戶端廣告插播功能整合至應用程式。這個程式庫會包裝用戶端 IMA SDK 的功能,支援插入 VAST/VMAP 廣告。如需程式庫的使用說明,包括如何處理背景播放和繼續播放,請參閱 README。

試用版應用程式使用 IMA 程式庫,並在範例清單中包含多個 VAST/VMAP 廣告代碼範例。

UI 考量

PlayerView 預設會在播放廣告時隱藏傳輸控制項,但應用程式可以呼叫 setControllerHideDuringAds 切換這項行為。廣告播放時,IMA SDK 會在播放器上方顯示其他檢視畫面 (例如「更多資訊」連結和略過按鈕,如適用)。

IMA SDK 可能會回報廣告是否遭到應用程式提供的檢視畫面遮蔽,這些檢視畫面會顯示在播放器上方。如果應用程式需要疊加控制播放所不可或缺的檢視畫面,則必須向 IMA SDK 註冊這些檢視畫面,才能在計算可視度時略過。使用 PlayerView 做為 AdViewProvider 時,系統會自動註冊控制項疊加層。如果應用程式使用自訂播放器 UI,則必須從 AdViewProvider.getAdOverlayInfos 傳回疊加檢視畫面,藉此註冊這類檢視畫面。

如要進一步瞭解疊加檢視,請參閱「IMA SDK 中的 Open Measurement」。

隨播廣告

部分廣告代碼包含額外的隨播廣告,可在應用程式 UI 的「版位」中顯示。這些版位可使用 ImaAdsLoader.Builder.setCompanionAdSlots(slots) 傳遞。詳情請參閱「新增隨播廣告」。

獨立式廣告

IMA SDK 的設計目的是將廣告插入媒體內容,而非單獨播放獨立式廣告。因此,IMA 程式庫不支援播放獨立式廣告。在這種情況下,建議改用 Google Mobile Ads SDK。

使用第三方廣告 SDK

如需使用第三方廣告 SDK 載入廣告,建議您確認該 SDK 是否已提供 ExoPlayer 整合功能。如果沒有,建議您實作自訂 AdsLoader 來包裝第三方廣告 SDK,因為這樣可以享有上述 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 說明文件,瞭解如何將廣告納入播放清單。

使用伺服器端廣告插播時,用戶端可能需要動態解析媒體網址,才能取得拼接串流,也可能需要在 UI 中顯示廣告疊加層,或向廣告 SDK 或廣告伺服器回報事件。

ExoPlayer 的 DefaultMediaSourceFactory 可將所有這些工作委派給伺服器端廣告插播 MediaSource,用於使用 ssai:// 配置的 URI:

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.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 建立網址,載入 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 的「版位」中顯示。這些版位可使用 ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots) 傳遞。詳情請參閱「新增隨播廣告」。

使用第三方廣告 SDK

如需使用第三方廣告 SDK 載入廣告,建議您確認該 SDK 是否已提供 ExoPlayer 整合功能。如果不是,建議提供自訂 MediaSource,接受採用 ssai:// 配置的 URI,類似於 ImaServerSideAdInsertionMediaSource。

建立廣告結構的實際邏輯可委派給一般用途的 ServerSideAdInsertionMediaSource,該物件會包裝串流 MediaSource,並允許使用者設定及更新代表廣告中繼資料的 AdPlaybackState。

伺服器端插入的廣告串流通常包含定時事件,用於通知播放器廣告中繼資料。請參閱「支援的格式」,瞭解 ExoPlayer 支援哪些定時中繼資料格式。自訂廣告 SDK MediaSource 實作項目可使用 Player.Listener.onMetadata 監聽播放器的定時中繼資料事件。