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 的 DefaultMediaSourceFactory 和 AdViewProvider:
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 的組合,方法是將廣告代碼 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 隨附 HlsInterstitialsAdsLoader,支援在用戶端自動插入 HLS 播放清單中定義的廣告。請參閱 HLS 頁面中關於 HlsInterstitialsAdsLoader 的小節。
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」。
隨播廣告
部分廣告代碼含有額外的隨播廣告,可顯示在應用程式 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 可以使用 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.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 的「位置」中。這些位置可以透過 ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots) 傳遞。詳情請參閱「新增隨播廣告」。
使用第三方廣告 SDK
如需使用第三方廣告 SDK 載入廣告,建議先確認該 SDK 是否已提供 ExoPlayer 整合功能。如果不是,建議您提供自訂 MediaSource,接受具有 ssai:// 配置的 URI,類似於 ImaServerSideAdInsertionMediaSource。
建立廣告結構的實際邏輯可委派給一般用途的 ServerSideAdInsertionMediaSource,該結構會包裝串流 MediaSource,並允許使用者設定及更新代表廣告中繼資料的 AdPlaybackState。
通常,伺服器端插入的廣告串流會包含時間事件,用來通知播放器廣告中繼資料。如要瞭解 ExoPlayer 支援哪些時間碼中繼資料格式,請參閱支援的格式。自訂廣告 SDK MediaSource 實作項目可以使用 Player.Listener.onMetadata 監聽播放器的時間碼中繼資料事件。