插入廣告

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

用戶端廣告插播

在用戶端廣告插播中,播放器會在播放內容和廣告之間轉換時,切換載入媒體的媒體。廣告相關資訊會與媒體分開載入,例如從 XML VASTVMAP 廣告代碼載入。這可能包含與內容開頭相對的廣告提示位置、實際廣告媒體 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.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 會將內容媒體來源納入 AdsMediaSourceAdsMediaSource 會從 AdsLoader.Provider 取得 AdsLoader,並根據媒體項目的廣告代碼定義來插入廣告。

ExoPlayer 的 PlayerView 會實作 AdViewProvider,ExoPlayer IMA 程式庫提供易用的 AdsLoader,如下所述。

含廣告的播放清單

播放包含多個媒體項目的播放清單時,預設行為是針對每個媒體 ID、內容 URI 和廣告代碼 URI 組合請求廣告代碼,並儲存廣告播放狀態。也就是說,即使廣告代碼 URI 相符,每個媒體項目都會向使用者顯示具有不同媒體 ID 或內容 URI 的廣告。如果重複播放媒體項目,使用者只會看到對應的廣告一次 (廣告播放狀態會儲存廣告是否已播放,因此會在第一次播放後略過)。

如要自訂這個行為,您可以傳遞不透明的廣告 ID,並根據物件相等性傳遞特定媒體項目連結哪個廣告播放狀態。在以下範例中,廣告播放狀態僅連結至廣告代碼 URI,而不是與媒體 ID 和廣告代碼 URI 的組合,並藉由傳遞廣告代碼 URI 做為廣告 ID。效果在於廣告只載入一次,且使用者從頭播放完畢的播放清單時,不會在第二個項目看到廣告。

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 註冊,才能在可視度計算時省略這些檢視畫面。使用 PlayerView 做為 AdViewProvider 時,系統會自動註冊其控制項疊加層。使用自訂播放器 UI 的應用程式,必須從 AdViewProvider.getAdOverlayInfos 傳回疊加層檢視畫面,才能註冊該檢視畫面。

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

隨播廣告

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

獨立廣告

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

使用第三方廣告 SDK

如果您需要透過第三方廣告 SDK 載入廣告,建議您檢查它是否已提供 ExoPlayer 整合。如果沒有,建議您導入納入第三方廣告 SDK 的自訂 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(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 說明文件,瞭解將廣告加入播放清單的方式。

使用伺服器端廣告插播時,用戶端可能需要動態解析媒體網址以取得拼接的串流,可能需要在 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 建立網址,載入 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 載入廣告,建議您檢查它是否已提供 ExoPlayer 整合。如果不是,建議您提供可接受具有 ssai:// 配置 (與 ImaServerSideAdInsertionMediaSource 類似) 的自訂 MediaSource

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

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