หัวใจสำคัญของไลบรารี ExoPlayer คืออินเทอร์เฟซ Player
Player
แสดงให้เห็นถึงฟังก์ชันการทำงานของมีเดียเพลเยอร์ระดับสูงแบบดั้งเดิม เช่น ความสามารถในการ
บัฟเฟอร์สื่อ เล่น หยุดชั่วคราว และกรอวิดีโอ การใช้งานเริ่มต้น ExoPlayer
คือ
ออกแบบมาเพื่อให้มีสมมติฐานเกี่ยวกับ (และจึงตั้งข้อจำกัดบางประการ)
ประเภทสื่อที่เล่น วิธีและตำแหน่งที่จัดเก็บ และวิธีจัดเก็บ
ที่แสดงผล โดยแทนที่จะใช้การโหลดและการแสดงผลสื่อโดยตรง
การติดตั้งใช้งาน ExoPlayer
จะมอบสิทธิ์งานนี้ให้กับคอมโพเนนต์ที่มีการแทรก
เมื่อมีการสร้างโปรแกรมเล่น หรือเมื่อมีการส่งแหล่งที่มาสื่อใหม่ไปยังโปรแกรมเล่น
คอมโพเนนต์ที่พบบ่อยในการใช้งาน ExoPlayer
ทั้งหมด ได้แก่
MediaSource
อินสแตนซ์ที่กำหนดสื่อที่จะเล่น โหลดสื่อ และ ที่สามารถอ่านสื่อที่โหลดได้ สร้างอินสแตนซ์MediaSource
แล้ว จากMediaItem
โดยMediaSource.Factory
ภายในโปรแกรมเล่น นอกจากนี้ยังสามารถ จะส่งไปยังโปรแกรมเล่นโดยตรงโดยใช้ API ของเพลย์ลิสต์ตามแหล่งที่มาของสื่อ- อินสแตนซ์
MediaSource.Factory
ที่แปลงMediaItem
เป็นMediaSource
ระบบจะแทรกMediaSource.Factory
เมื่อสร้างโปรแกรมเล่น Renderer
อินสแตนซ์ที่แสดงผลแต่ละคอมโพเนนต์ของสื่อ สิ่งเหล่านี้คือ เมื่อมีการสร้างโปรแกรมเล่นTrackSelector
ที่เลือกแทร็กจากMediaSource
เป็น ใช้โดยRenderer
ที่มีอยู่แต่ละรายการ แทรกTrackSelector
แล้ว เมื่อสร้างโปรแกรมเล่นLoadControl
ที่ควบคุมช่วงเวลาที่MediaSource
จะบัฟเฟอร์สื่อเพิ่มเติม และ ปริมาณการบัฟเฟอร์สื่อ มีการแทรกLoadControl
เมื่อโปรแกรมเล่นวิดีโอ สร้าง แล้วLivePlaybackSpeedControl
ที่ควบคุมความเร็วในการเล่นระหว่างการถ่ายทอดสด เล่นเพื่อให้โปรแกรมเล่นอยู่ใกล้กับออฟเซ็ตแบบสดที่กำหนดค่าไว้ ต ระบบจะแทรกLivePlaybackSpeedControl
เมื่อสร้างโปรแกรมเล่น
แนวคิดในการแทรกโค้ดเพื่อนำชิ้นส่วนของผู้เล่น ฟังก์ชันที่มีอยู่ทั่วไลบรารี การติดตั้งใช้งานเริ่มต้นของ คอมโพเนนต์บางส่วนจะมอบสิทธิ์การทำงานให้กับคอมโพเนนต์ที่แทรกเข้ามาเพิ่มเติม สิ่งนี้ช่วยให้ และคอมโพเนนต์ย่อยจะถูกแทนที่ด้วยการใช้งานที่ ในแบบที่กำหนดเอง
การปรับแต่งโปรแกรมเล่น
ตัวอย่างที่พบบ่อยของการปรับแต่งโปรแกรมเล่นด้วยการแทรกคอมโพเนนต์ ได้แก่ ดังที่อธิบายไว้ด้านล่าง
การกำหนดค่าสแต็กเครือข่าย
เรามีหน้าเว็บเกี่ยวกับการปรับแต่งสแต็กเครือข่ายที่ ExoPlayer ใช้
ข้อมูลการแคชที่โหลดจากเครือข่าย
ดูคำแนะนำสำหรับ การแคชชั่วคราวขณะเดินทาง และการดาวน์โหลดสื่อ
การปรับแต่งการโต้ตอบกับเซิร์ฟเวอร์
บางแอปอาจต้องการสกัดกั้นคำขอและการตอบกลับ HTTP คุณอาจต้องการ แทรกส่วนหัวของคำขอที่กำหนดเอง อ่านส่วนหัวการตอบกลับของเซิร์ฟเวอร์ แก้ไข คำขอ URI เป็นต้น ตัวอย่างเช่น แอปของคุณอาจตรวจสอบสิทธิ์ตัวเองโดยการแทรก โทเค็นเป็นส่วนหัวเมื่อขอกลุ่มสื่อ
ตัวอย่างต่อไปนี้สาธิตวิธีนำลักษณะการทำงานเหล่านี้ไปใช้โดย
การแทรก DataSource.Factory
ที่กำหนดเองใน DefaultMediaSourceFactory
:
Kotlin
val dataSourceFactory = DataSource.Factory { val dataSource = httpDataSourceFactory.createDataSource() // Set a custom authentication request header. dataSource.setRequestProperty("Header", "Value") dataSource } val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory) ) .build()
Java
DataSource.Factory dataSourceFactory = () -> { HttpDataSource dataSource = httpDataSourceFactory.createDataSource(); // Set a custom authentication request header. dataSource.setRequestProperty("Header", "Value"); return dataSource; }; ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory)) .build();
ในข้อมูลโค้ดด้านบน HttpDataSource
ที่แทรกมีส่วนหัว
"Header: Value"
ในคำขอ HTTP ทุกรายการ ลักษณะการทำงานนี้จะได้รับการแก้ไขสำหรับ
การโต้ตอบกับแหล่งที่มา HTTP
สำหรับวิธีการที่ละเอียดยิ่งขึ้น คุณสามารถแทรกพฤติกรรมในช่วงเวลาสั้นๆ โดยใช้
ResolvingDataSource
ข้อมูลโค้ดต่อไปนี้แสดงวิธีแทรก
ของส่วนหัวคำขอก่อนที่จะโต้ตอบกับแหล่งที่มา HTTP:
Kotlin
val dataSourceFactory: DataSource.Factory = ResolvingDataSource.Factory(httpDataSourceFactory) { dataSpec: DataSpec -> // Provide just-in-time request headers. dataSpec.withRequestHeaders(getCustomHeaders(dataSpec.uri)) }
Java
DataSource.Factory dataSourceFactory = new ResolvingDataSource.Factory( httpDataSourceFactory, // Provide just-in-time request headers. dataSpec -> dataSpec.withRequestHeaders(getCustomHeaders(dataSpec.uri)));
นอกจากนี้คุณยังสามารถใช้ ResolvingDataSource
เพื่อดำเนินการ
การแก้ไข URI แบบทันที ดังที่แสดงในข้อมูลโค้ดต่อไปนี้
Kotlin
val dataSourceFactory: DataSource.Factory = ResolvingDataSource.Factory(httpDataSourceFactory) { dataSpec: DataSpec -> // Provide just-in-time URI resolution logic. dataSpec.withUri(resolveUri(dataSpec.uri)) }
Java
DataSource.Factory dataSourceFactory = new ResolvingDataSource.Factory( httpDataSourceFactory, // Provide just-in-time URI resolution logic. dataSpec -> dataSpec.withUri(resolveUri(dataSpec.uri)));
การปรับแต่งการจัดการข้อผิดพลาด
การใช้ LoadErrorHandlingPolicy
ที่กำหนดเองจะช่วยให้แอปปรับแต่ง
วิธีที่ ExoPlayer ตอบสนองต่อข้อผิดพลาดในการโหลด เช่น แอปอาจต้องการล้มเหลวอย่างรวดเร็ว
แทนที่จะต้องลองใหม่หลายๆ ครั้ง หรืออาจต้องปรับแต่งตรรกะการย้อนกลับ
ควบคุมระยะเวลาที่โปรแกรมเล่นต้องรอระหว่างการลองใหม่แต่ละครั้ง ข้อมูลโค้ดต่อไปนี้
แสดงวิธีใช้งานตรรกะ Backoff ที่กำหนดเอง
Kotlin
val loadErrorHandlingPolicy: LoadErrorHandlingPolicy = object : DefaultLoadErrorHandlingPolicy() { override fun getRetryDelayMsFor(loadErrorInfo: LoadErrorInfo): Long { // Implement custom back-off logic here. return 0 } } val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy) ) .build()
Java
LoadErrorHandlingPolicy loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy() { @Override public long getRetryDelayMsFor(LoadErrorInfo loadErrorInfo) { // Implement custom back-off logic here. return 0; } }; ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context) .setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)) .build();
อาร์กิวเมนต์ LoadErrorInfo
มีข้อมูลเพิ่มเติมเกี่ยวกับการโหลดที่ล้มเหลวไปยัง
ปรับแต่งตรรกะตามประเภทข้อผิดพลาดหรือคำขอที่ล้มเหลว
การปรับแต่งแฟล็กเครื่องมือแยก
แฟล็กเครื่องมือแยกข้อมูลสามารถใช้เพื่อปรับแต่งวิธีแยกไฟล์แต่ละรูปแบบได้
จากสื่อแบบโปรเกรสซีฟ สามารถตั้งค่าใน DefaultExtractorsFactory
ที่
ที่ให้ไว้ใน DefaultMediaSourceFactory
ตัวอย่างต่อไปนี้ส่งผ่าน Flag
ที่ช่วยให้ค้นหาสตรีม MP3 โดยอิงตามดัชนีได้
Kotlin
val extractorsFactory = DefaultExtractorsFactory().setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING) val player = ExoPlayer.Builder(context) .setMediaSourceFactory(DefaultMediaSourceFactory(context, extractorsFactory)) .build()
Java
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory().setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING); ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory(new DefaultMediaSourceFactory(context, extractorsFactory)) .build();
เปิดใช้การกรอวิดีโออัตราบิตคงที่
สำหรับสตรีม MP3, ADTS และ AMR คุณสามารถเปิดใช้การกรอวิดีโอโดยประมาณได้โดยใช้
สมมติฐานเกี่ยวกับอัตราบิตคงที่ที่มีแฟล็ก FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
ค่าสถานะเหล่านี้สามารถตั้งค่าสําหรับเครื่องมือแยกข้อมูลแต่ละรายการได้โดยใช้
DefaultExtractorsFactory.setXyzExtractorFlags
วิธีตามที่อธิบายไว้ข้างต้น ถึง
เปิดใช้งานการกรอวิดีโอบิตเรตคงที่สำหรับเครื่องมือแยกข้อมูลทุกตัวที่รองรับ ใช้
DefaultExtractorsFactory.setConstantBitrateSeekingEnabled
Kotlin
val extractorsFactory = DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true)
Java
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true);
จากนั้นสามารถแทรก ExtractorsFactory
ผ่าน DefaultMediaSourceFactory
เป็น
ตามที่อธิบายไว้สำหรับการปรับแต่งแฟล็กเครื่องมือแยกข้อมูลด้านบน
การเปิดใช้การจัดคิวบัฟเฟอร์แบบไม่พร้อมกัน
การจัดคิวบัฟเฟอร์แบบไม่พร้อมกันเป็นการเพิ่มประสิทธิภาพในการแสดงผลของ ExoPlayer
ไปป์ไลน์ ซึ่งดำเนินงานอินสแตนซ์ MediaCodec
ในโหมดอะซิงโครนัสและ
จะใช้เทรดเพิ่มเติมเพื่อกำหนดเวลาการถอดรหัสและการแสดงผลข้อมูล การเปิดใช้
ช่วยลดเฟรมที่กระเด็นและเสียงไม่ค่อยดีได้
การจัดคิวบัฟเฟอร์แบบไม่พร้อมกันจะเปิดใช้โดยค่าเริ่มต้นในอุปกรณ์ที่ใช้ Android 12 (API ระดับ 31) ขึ้นไป และสามารถเปิดใช้ได้ด้วยตนเองตั้งแต่ Android 6.0 (API ระดับ 23) ลองเปิดใช้ฟีเจอร์นี้สำหรับอุปกรณ์ที่เฉพาะเจาะจงซึ่งคุณสังเกตเห็นว่าลดลง เฟรมหรือเสียงด้อยกว่านั้น โดยเฉพาะอย่างยิ่งเมื่อเล่นด้วย DRM ที่มีการป้องกันหรือมีอัตราเฟรมสูง เนื้อหา
ในกรณีที่ง่ายที่สุด คุณต้องแทรก DefaultRenderersFactory
ลงในส่วน
ดังนี้
Kotlin
val renderersFactory = DefaultRenderersFactory(context).forceEnableMediaCodecAsynchronousQueueing() val exoPlayer = ExoPlayer.Builder(context, renderersFactory).build()
Java
DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(context).forceEnableMediaCodecAsynchronousQueueing(); ExoPlayer exoPlayer = new ExoPlayer.Builder(context, renderersFactory).build();
หากคุณกำลังสร้างอินสแตนซ์ให้กับโหมดแสดงภาพโดยตรง ให้ส่ง
AsynchronousMediaCodecAdapter.Factory
ไปยัง MediaCodecVideoRenderer
และ
เครื่องมือสร้าง MediaCodecAudioRenderer
การสกัดกั้นการเรียกด้วย ForwardingPlayer
คุณปรับแต่งลักษณะการทำงานบางอย่างของอินสแตนซ์ Player
ได้โดยการรวมอินสแตนซ์ไว้ใน
คลาสย่อยของ ForwardingPlayer
และการลบล้างเพื่อดําเนินการ
ดังต่อไปนี้
- เข้าถึงพารามิเตอร์ก่อนที่จะส่งไปยังผู้รับมอบสิทธิ์
Player
- เข้าถึงค่าที่ส่งคืนจากผู้รับมอบสิทธิ์
Player
ก่อนส่งคืน - นำวิธีการดังกล่าวมาใช้ใหม่โดยสมบูรณ์
เมื่อลบล้างเมธอด ForwardingPlayer
คุณต้องตรวจสอบว่า
การใช้งานยังคงมีความต่อเนื่องและสอดคล้องกับPlayer
โดยเฉพาะเมื่อจัดการกับเมธอดที่มีจุดประสงค์
มีลักษณะเหมือนหรือเกี่ยวข้องกัน เช่น
- หากคุณต้องการลบล้างทุกๆ "การเล่น" คุณจำเป็นต้องลบล้าง
ForwardingPlayer.play
และForwardingPlayer.setPlayWhenReady
เนื่องจาก ของผู้โทรจะคาดหวังลักษณะการทำงานของวิธีการเหล่านี้จะเหมือนกันเมื่อplayWhenReady = true
- หากต้องการเปลี่ยนการกรอไปข้างหน้า คุณจะต้องลบล้างทั้ง 2 ส่วน
ForwardingPlayer.seekForward
เพื่อทำการค้นหาด้วยโฆษณาที่คุณกำหนดเอง เพิ่มขึ้น และForwardingPlayer.getSeekForwardIncrement
เพื่อรายงาน ส่วนเพิ่มที่ปรับแต่งเองอย่างถูกต้องกลับไปยังผู้โทร - หากคุณต้องการควบคุมสิ่งที่ผู้เล่นโฆษณา
Player.Commands
ไว้ คุณต้องลบล้างทั้งPlayer.getAvailableCommands()
และPlayer.isCommandAvailable()
และยังฟังPlayer.Listener.onAvailableCommandsChanged()
โทรกลับเพื่อรับการแจ้งเตือน การเปลี่ยนแปลงที่มาจากโปรแกรมเล่นพื้นฐาน
การปรับแต่ง MediaSource
ตัวอย่างข้างต้นจะแทรกคอมโพเนนต์ที่ปรับแต่งไว้เพื่อใช้ในระหว่างการเล่นทั้งหมด
MediaItem
ออบเจ็กต์ที่ส่งไปยังโปรแกรมเล่น โดยการปรับแต่งแบบละเอียด
คุณยังสามารถแทรกคอมโพเนนต์ที่กำหนดเองลงใน
MediaSource
อินสแตนซ์ซึ่งส่งผ่านไปยังโปรแกรมเล่นโดยตรงได้ ตัวอย่าง
ด้านล่างแสดงวิธีปรับแต่ง ProgressiveMediaSource
ให้ใช้
DataSource.Factory
, ExtractorsFactory
และ LoadErrorHandlingPolicy
:
Kotlin
val mediaSource = ProgressiveMediaSource.Factory(customDataSourceFactory, customExtractorsFactory) .setLoadErrorHandlingPolicy(customLoadErrorHandlingPolicy) .createMediaSource(MediaItem.fromUri(streamUri))
Java
ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(customDataSourceFactory, customExtractorsFactory) .setLoadErrorHandlingPolicy(customLoadErrorHandlingPolicy) .createMediaSource(MediaItem.fromUri(streamUri));
การสร้างคอมโพเนนต์ที่กำหนดเอง
ไลบรารีมีการใช้งานเริ่มต้นของคอมโพเนนต์ที่แสดงอยู่ด้านบน
ของหน้านี้สำหรับ Use Case ทั่วไป ExoPlayer
จะใช้คอมโพเนนต์เหล่านี้ได้ แต่
นอกจากนี้ยังอาจสร้างให้ใช้การติดตั้งใช้งานที่กำหนดเองได้หากการทำงานที่ไม่เป็นไปตามมาตรฐาน
ต้องระบุ ตัวอย่างกรณีการใช้งานสำหรับการติดตั้งใช้งานที่กำหนดเองมีดังนี้
Renderer
– คุณอาจต้องการใช้Renderer
ที่กำหนดเองเพื่อจัดการ ประเภทสื่อไม่มีการสนับสนุนโดยการใช้งานเริ่มต้นที่ระบุโดย ไลบรารีTrackSelector
– การใช้TrackSelector
ที่กำหนดเองจะช่วยให้แอป ในการเปลี่ยนวิธีแสดงแทร็กโดยMediaSource
ที่เลือกเพื่อการบริโภคตามRenderer
แต่ละรายการที่มีอยู่LoadControl
– การใช้LoadControl
ที่กำหนดเองจะช่วยให้แอป นักพัฒนาซอฟต์แวร์ เพื่อเปลี่ยนนโยบายการบัฟเฟอร์ของโปรแกรมเล่นExtractor
– หากคุณต้องการรองรับรูปแบบคอนเทนเนอร์ในขณะนี้ ที่ไลบรารีรองรับ ให้พิจารณาใช้คลาสExtractor
ที่กำหนดเองMediaSource
– การใช้คลาสMediaSource
ที่กำหนดเองอาจมีประโยชน์ดังนี้ เหมาะสมหากคุณต้องการรับตัวอย่างสื่อเพื่อป้อนให้กับตัวแสดงผลใน เส้นทางที่กำหนดเอง หรือหากคุณต้องการใช้การประสานMediaSource
ที่กำหนดเอง พฤติกรรมของคุณMediaSource.Factory
– การใช้MediaSource.Factory
ที่กำหนดเอง อนุญาตให้แอปพลิเคชันปรับแต่งวิธีการสร้างMediaSource
จากMediaItem
DataSource
– แพ็กเกจอัปสตรีมของ ExoPlayer มีจำนวน การติดตั้งใช้งานDataSource
สำหรับ Use Case ที่แตกต่างกัน คุณอาจต้องการ ใช้คลาสDataSource
ที่คุณเป็นเจ้าของเพื่อโหลดข้อมูลด้วยวิธีอื่น เช่น โปรโตคอลที่กำหนดเอง การใช้สแต็ก HTTP ที่กำหนดเอง หรือจากแท็กถาวรที่กำหนดเอง แคช
เมื่อสร้างคอมโพเนนต์ที่กำหนดเอง เราขอแนะนำดังนี้
- หากคอมโพเนนต์ที่กำหนดเองจำเป็นต้องรายงานเหตุการณ์กลับไปยังแอป เราขอแนะนำ
โดยใช้โมเดลเดียวกับคอมโพเนนต์ ExoPlayer ที่มีอยู่
ตัวอย่างเช่น การใช้
EventDispatcher
ชั้นเรียน หรือการสอบผ่านHandler
ร่วมกับ Listener ตัวสร้างของคอมโพเนนต์ - เราขอแนะนำให้คอมโพเนนต์ที่กำหนดเองใช้รุ่นเดียวกันกับ ExoPlayer ที่มีอยู่
เพื่อให้แอปกำหนดค่าใหม่ในระหว่างการเล่นได้ วิธีการคือ
คอมโพเนนต์ที่กำหนดเองควรใช้
PlayerMessage.Target
และรับ การเปลี่ยนแปลงการกำหนดค่าในเมธอดhandleMessage
โค้ดของแอปพลิเคชันควร ส่งการเปลี่ยนแปลงการกำหนดค่าโดยเรียกใช้เมธอดcreateMessage
ของ ExoPlayer การกำหนดค่าข้อความ และส่งไปยังคอมโพเนนต์โดยใช้PlayerMessage.send
การส่งข้อความที่จะส่งในชุดข้อความการเล่น ทำให้แน่ใจว่าได้มีการดำเนินการตามลำดับกับการดำเนินการอื่นๆ ที่ ในโปรแกรมเล่น