ExoPlayer สามารถใช้ได้ทั้งสำหรับการแทรกโฆษณาฝั่งไคลเอ็นต์และฝั่งเซิร์ฟเวอร์
การแทรกโฆษณาฝั่งไคลเอ็นต์
ในการแทรกโฆษณาฝั่งไคลเอ็นต์ โปรแกรมเล่นจะสลับระหว่างการโหลดสื่อจาก URL ต่างๆ เมื่อสลับระหว่างการเล่นเนื้อหากับโฆษณา ระบบจะโหลดข้อมูลเกี่ยวกับโฆษณาแยกจากสื่อ เช่น จากแท็กโฆษณา VAST หรือ VMAP XML ซึ่งอาจรวมถึงตําแหน่งจุดเริ่มต้นโฆษณาสัมพันธ์กับจุดเริ่มต้นของเนื้อหา, URI ของสื่อโฆษณาจริง และข้อมูลเมตา เช่น โฆษณาหนึ่งๆ ข้ามได้หรือไม่
เมื่อใช้ AdsMediaSource
ของ ExoPlayer สำหรับการแทรกโฆษณาฝั่งไคลเอ็นต์ โปรแกรมเล่นจะมีข้อมูลเกี่ยวกับโฆษณาที่จะเล่น ซึ่งมีประโยชน์หลายประการ ดังนี้
- โปรแกรมเล่นสามารถแสดงข้อมูลเมตาและฟังก์ชันการทำงานที่เกี่ยวข้องกับโฆษณาได้โดยใช้ API
- คอมโพเนนต์ UI ของ ExoPlayer สามารถแสดงเครื่องหมายสำหรับตําแหน่งโฆษณาโดยอัตโนมัติ และเปลี่ยนลักษณะการทํางานโดยขึ้นอยู่กับว่าโฆษณากําลังเล่นอยู่หรือไม่
- โปรแกรมเล่นสามารถบัฟเฟอร์ข้อมูลได้อย่างสม่ำเสมอในระหว่างการเปลี่ยนจากโฆษณาไปยังเนื้อหา
ในการตั้งค่านี้ เพลเยอร์จะจัดการการสลับระหว่างโฆษณาและเนื้อหา ซึ่งหมายความว่าแอปไม่จําเป็นต้องควบคุมเพลเยอร์เบื้องหน้า/เบื้องหลังหลายรายการแยกกันสําหรับโฆษณาและเนื้อหา
เมื่อเตรียมวิดีโอเนื้อหาและแท็กโฆษณาเพื่อใช้กับการแสดงโฆษณาฝั่งไคลเอ็นต์ การวางโฆษณาควรอยู่ที่ตัวอย่างการซิงค์ (คีย์เฟรม) ในวิดีโอเนื้อหาเพื่อให้โปรแกรมเล่นเล่นเนื้อหาต่อได้อย่างราบรื่น
การรองรับโฆษณาแบบประกาศ
คุณสามารถระบุ URI แท็กโฆษณาเมื่อสร้าง MediaItem
ดังนี้
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();
หากต้องการเปิดใช้การรองรับรายการสื่อที่ระบุแท็กโฆษณาของโปรแกรมเล่น คุณจะต้องสร้างและแทรก DefaultMediaSourceFactory
ที่กําหนดค่าด้วย AdsLoader.Provider
และ 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
จาก
AdsLoader.Provider
และใช้เพื่อแทรกโฆษณาตามที่แท็กโฆษณาของรายการสื่อกำหนด
PlayerView
ของ ExoPlayer ใช้ AdViewProvider
คลัง IMA ของ ExoPlayer มี AdsLoader
ที่ใช้งานง่ายตามที่อธิบายไว้ด้านล่าง
เพลย์ลิสต์ที่มีโฆษณา
เมื่อเล่นเพลย์ลิสต์ที่มีรายการสื่อหลายรายการ ลักษณะการทำงานเริ่มต้นคือจะขอแท็กโฆษณาและจัดเก็บสถานะการเล่นโฆษณา 1 ครั้งสำหรับชุดค่าผสมรหัสสื่อ, URI ของเนื้อหา และ URI ของแท็กโฆษณาแต่ละรายการ ซึ่งหมายความว่าผู้ใช้จะเห็นโฆษณาของรายการสื่อทุกรายการที่มีโฆษณาซึ่งมีรหัสสื่อหรือ URI เนื้อหาที่แตกต่างกัน แม้ว่า URI ของแท็กโฆษณาจะตรงกันก็ตาม หากมีการแสดงรายการสื่อซ้ำ ผู้ใช้จะเห็นโฆษณาที่เกี่ยวข้องเพียงครั้งเดียว (สถานะการเล่นโฆษณาจะจัดเก็บข้อมูลว่าโฆษณาเล่นหรือไม่ เพื่อข้ามโฆษณาหลังจากแสดงครั้งแรก)
คุณปรับแต่งลักษณะการทํางานนี้ได้โดยส่งตัวระบุโฆษณาแบบทึบซึ่งเชื่อมโยงกับสถานะการเล่นโฆษณาสําหรับรายการสื่อหนึ่งๆ โดยอิงตามความเท่าเทียมของออบเจ็กต์ ต่อไปนี้คือตัวอย่างที่สถานะการเล่นโฆษณาลิงก์กับ URI แท็กโฆษณาเท่านั้น ไม่ใช่การรวมรหัสสื่อและ URI แท็กโฆษณา โดยส่ง URI แท็กโฆษณาเป็นตัวระบุโฆษณา ผลที่ได้คือโฆษณาจะโหลดเพียงครั้งเดียวและผู้ใช้จะไม่เห็นโฆษณาในรายการที่ 2 เมื่อเล่นเพลย์ลิสต์ตั้งแต่ต้นจนจบ
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 เพื่อแทรกในฝั่งไคลเอ็นต์โดยอัตโนมัติ ดูส่วนเกี่ยวกับ HlsInterstitialsAdsLoader
ในหน้า HLS
ไลบรารี IMA ของ ExoPlayer
ไลบรารี IMA ของ ExoPlayer มี 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
โฆษณาที่แสดงร่วม
แท็กโฆษณาบางรายการมีโฆษณาที่แสดงร่วมกันเพิ่มเติมซึ่งสามารถแสดงใน "ช่อง" ใน 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(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) สตรีมสื่อจะมีทั้งโฆษณาและเนื้อหา ไฟล์ Manifest ของ DASH อาจชี้ไปยังทั้งเนื้อหาและกลุ่มโฆษณา ซึ่งอาจอยู่ในช่วงเวลาที่ต่างกัน สำหรับ HLS โปรดดูเอกสารประกอบของ Apple เกี่ยวกับการรวมโฆษณาไว้ในเพลย์ลิสต์
เมื่อใช้การแทรกโฆษณาฝั่งเซิร์ฟเวอร์ ไคลเอ็นต์อาจต้องแก้ไข URL สื่อแบบไดนามิกเพื่อรับสตรีมที่ต่อกัน อาจต้องแสดงโฆษณาซ้อนใน UI หรืออาจต้องรายงานเหตุการณ์ไปยัง SDK โฆษณาหรือเซิร์ฟเวอร์โฆษณา
DefaultMediaSourceFactory
ของ ExoPlayer สามารถมอบหมายงานเหล่านี้ทั้งหมดให้กับ MediaSource
ของแทรกโฆษณาฝั่งเซิร์ฟเวอร์สําหรับ URI โดยใช้รูปแบบ ssai://
ดังนี้
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();
ไลบรารี IMA ของ ExoPlayer
ไลบรารี IMA ของ ExoPlayer มี ImaServerSideAdInsertionMediaSource
ซึ่งช่วยให้ผสานรวมกับสตรีมโฆษณาที่แทรกฝั่งเซิร์ฟเวอร์ของ IMA ในแอปได้อย่างง่ายดาย โดยไลบรารีนี้จะรวมฟังก์ชันการทำงานของ IMA DAI SDK สําหรับ Android และผสานรวมข้อมูลเมตาโฆษณาที่ระบุไว้ในเพลเยอร์อย่างเต็มรูปแบบ ตัวอย่างเช่น การดำเนินการนี้จะช่วยให้คุณใช้เมธอดอย่าง 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);
โหลดคีย์เนื้อหา IMA หรือรหัสแหล่งที่มาของเนื้อหาและรหัสวิดีโอโดยสร้าง URL ImaServerSideAdInsertionUriBuilder
ดังนี้
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
ที่กําหนดเองซึ่งยอมรับ URI ที่มีรูปแบบ ssai://
คล้ายกับ ImaServerSideAdInsertionMediaSource
คุณสามารถมอบหมายตรรกะจริงของการสร้างโครงสร้างโฆษณาให้กับ ServerSideAdInsertionMediaSource
วัตถุประสงค์ทั่วไป ซึ่งจะรวมสตรีม MediaSource
และอนุญาตให้ผู้ใช้ตั้งค่าและอัปเดต AdPlaybackState
ที่แสดงข้อมูลเมตาของโฆษณา
บ่อยครั้งที่สตรีมโฆษณาที่แทรกฝั่งเซิร์ฟเวอร์จะมีเหตุการณ์แบบกำหนดเวลาเพื่อแจ้งให้โปรแกรมเล่นทราบเกี่ยวกับข้อมูลเมตาของโฆษณา โปรดดูข้อมูลเกี่ยวกับรูปแบบข้อมูลเมตาแบบมีเวลาซึ่ง ExoPlayer รองรับได้ที่รูปแบบที่รองรับ การติดตั้งใช้งาน SDK โฆษณาที่กําหนดเองMediaSource
จะฟังเหตุการณ์ข้อมูลเมตาแบบกําหนดเวลาจากโปรแกรมเล่นได้โดยใช้
Player.Listener.onMetadata