ExoPlayer สามารถใช้ได้ทั้งสำหรับการแทรกโฆษณาฝั่งไคลเอ็นต์และฝั่งเซิร์ฟเวอร์
การแทรกโฆษณาฝั่งไคลเอ็นต์
ในการแทรกโฆษณาฝั่งไคลเอ็นต์ โปรแกรมเล่นจะสลับระหว่างการโหลดสื่อจาก URL ต่างๆ เมื่อสลับระหว่างการเล่นเนื้อหากับโฆษณา ข้อมูลเกี่ยวกับโฆษณาจะโหลดแยกจากสื่อ เช่น จากแท็กโฆษณา XML VAST หรือ VMAP ซึ่งอาจรวมถึงตําแหน่งจุดเริ่มต้นโฆษณาสัมพันธ์กับจุดเริ่มต้นของเนื้อหา, 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
ไลบรารี ExoPlayer IMA มี 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);
ไลบรารี IMA ของ ExoPlayer
ไลบรารี 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
โฆษณาที่แสดงร่วม
แท็กโฆษณาบางรายการมีโฆษณาที่แสดงร่วมกันเพิ่มเติมซึ่งสามารถแสดงใน "ช่อง" ใน UI ของแอป คุณสามารถส่งผ่านช่องเหล่านี้ได้ผ่าน ImaAdsLoader.Builder.setCompanionAdSlots(slots)
สำหรับข้อมูลเพิ่มเติม โปรดดู
การเพิ่มโฆษณาที่แสดงร่วม
โฆษณาแบบสแตนด์อโลน
IMA SDK ออกแบบมาเพื่อแทรกโฆษณาลงในเนื้อหาสื่อ ไม่ใช่เพื่อแสดงโฆษณาเดี่ยวๆ คลัง IMA จึงไม่รองรับการเล่นโฆษณาแบบสแตนด์อโลน เราขอแนะนำให้ใช้ SDK โฆษณาในอุปกรณ์เคลื่อนที่ของ Google แทนสำหรับกรณีการใช้งานนี้
การใช้ 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