插入廣告

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,並使用該 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 廣告代碼範例。

使用者介面考量事項

根據預設,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 載入廣告,建議您檢查該 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 資訊清單可能會指向內容和廣告片段,且可能位於不同的時段。如為 HTTP 即時串流,請參閱 Apple 說明文件,瞭解如何將廣告加入播放清單

使用伺服器端廣告插入功能時,用戶端可能需要動態解析媒體網址,才能取得拼接串流,也可能需要在使用者介面中顯示廣告疊加層,或向廣告 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 整合功能。如果不是的話,建議您提供自訂 MediaSource,以便接受使用 ssai:// 配置的 URI,類似於 ImaServerSideAdInsertionMediaSource

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

伺服器端插入的廣告串流通常會包含計時事件,用於通知播放器廣告中繼資料。如要瞭解 ExoPlayer 支援的時間中繼資料格式,請參閱「支援的格式」一節。自訂廣告 SDK MediaSource 導入作業可以使用 Player.Listener.onMetadata,從播放器監聽計時中繼資料事件。