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
,並使用該 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 廣告標記。
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 整合功能。如果不是,建議您實作包裝第三方廣告 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 資訊清單可能會指向內容和廣告片段,且可能位於不同的時段。如要使用 HLS,請參閱 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.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 考量事項。
隨播廣告
部分廣告代碼含有額外的隨播廣告,可顯示在應用程式 UI 中的「插槽」中。這些時間間隔可透過 ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots)
傳遞。詳情請參閱「新增隨附廣告」。
使用第三方廣告 SDK
如果您需要使用第三方廣告 SDK 載入廣告,建議您檢查該 SDK 是否已提供 ExoPlayer 整合功能。如果不是的話,建議您提供自訂 MediaSource
,以便接受使用 ssai://
配置的 URI,類似於 ImaServerSideAdInsertionMediaSource
。
建立廣告結構體的實際邏輯可委派給通用 ServerSideAdInsertionMediaSource
,後者會包裝串流 MediaSource
,並允許使用者設定及更新代表廣告中繼資料的 AdPlaybackState
。
伺服器端插入的廣告串流通常會包含計時事件,用於通知播放器廣告中繼資料。如要瞭解 ExoPlayer 支援的時間中繼資料格式,請參閱「支援的格式」一節。自訂廣告 SDK MediaSource
實作項目可使用 Player.Listener.onMetadata
監聽播放器的時間指定結構描述事件。