ExoPlayer รองรับ HLS ที่มีรูปแบบคอนเทนเนอร์หลายรูปแบบ นอกจากนี้ รูปแบบของตัวอย่างเสียงและวิดีโอที่รวมอยู่ด้วยต้องได้รับการรองรับด้วย (ดูรายละเอียดในส่วนรูปแบบของตัวอย่าง) เราสนับสนุนอย่างยิ่งให้ผู้ผลิตเนื้อหา HLS สร้างสตรีม HLS คุณภาพสูงตามที่อธิบายไว้ที่นี่
ฟีเจอร์ | รองรับ | ความคิดเห็น |
---|---|---|
คอนเทนเนอร์ | ||
MPEG-TS | ใช่ | |
FMP4/CMAF | ใช่ | |
ADTS (AAC) | ใช่ | |
MP3 | ใช่ | |
คำบรรยายแทนเสียง/คำบรรยาย | ||
CEA-608 | ใช่ | |
CEA-708 | ใช่ | |
WebVTT | ใช่ | |
ข้อมูลเมตา | ||
ID3 | ใช่ | |
SCTE-35 | ไม่ | |
การปกป้องเนื้อหา | ||
แบบ AES-128 | ใช่ | |
ตัวอย่าง AES-128 | ไม่ | |
Widevine | ใช่ | API 19+ ("รูปแบบ cenc") และ 25+ ("รูปแบบ cbcs") |
PlayReady SL2000 | ใช่ | Android TV เท่านั้น |
การควบคุมเซิร์ฟเวอร์ | ||
การอัปเดต Delta | ใช่ | |
การบล็อกการโหลดเพลย์ลิสต์ซ้ำ | ใช่ | |
การบล็อกการโหลดคำแนะนำในการโหลดล่วงหน้า | ใช่ | ยกเว้นช่วงไบต์ที่มีความยาวที่ไม่ระบุ |
การเล่นแบบสด | ||
การเล่นแบบสดปกติ | ใช่ | |
HLS แบบเวลาในการตอบสนองต่ำ (Apple) | ใช่ | |
HLS เวลาในการตอบสนองต่ำ (ชุมชน) | ไม่ | |
Common Media Client Data (CMCD) | ใช่ | คู่มือการผสานรวม |
การใช้ MediaItem
หากต้องการเล่นสตรีม HLS คุณต้องใช้โมดูล HLS
Kotlin
implementation("androidx.media3:media3-exoplayer-hls:1.4.1")
Groovy
implementation "androidx.media3:media3-exoplayer-hls:1.4.1"
จากนั้นสร้าง MediaItem
สำหรับ URI ของเพลย์ลิสต์ HLS แล้วส่งไปยังโปรแกรมเล่น
Kotlin
// Create a player instance. val player = ExoPlayer.Builder(context).build() // Set the media item to be played. player.setMediaItem(MediaItem.fromUri(hlsUri)) // Prepare the player. player.prepare()
Java
// Create a player instance. ExoPlayer player = new ExoPlayer.Builder(context).build(); // Set the media item to be played. player.setMediaItem(MediaItem.fromUri(hlsUri)); // Prepare the player. player.prepare();
หาก URI ไม่ได้ลงท้ายด้วย .m3u8
คุณสามารถส่ง MimeTypes.APPLICATION_M3U8
ไปยัง setMimeType
ของ MediaItem.Builder
เพื่อระบุประเภทของเนื้อหาอย่างชัดแจ้ง
URI ของรายการสื่ออาจชี้ไปยังเพลย์ลิสต์สื่อหรือเพลย์ลิสต์เวอร์ชันหลายตัวแปร หาก URI ชี้ไปยังเพลย์ลิสต์แบบหลายตัวแปรที่ประกาศแท็ก #EXT-X-STREAM-INF
หลายรายการ ExoPlayer จะปรับระหว่างตัวแปรต่างๆ โดยอัตโนมัติ โดยพิจารณาทั้งแบนด์วิดท์ที่มีอยู่และความสามารถของอุปกรณ์
การใช้ HlsMediaSource
หากต้องการตัวเลือกการปรับแต่งเพิ่มเติม คุณอาจสร้าง HlsMediaSource
และส่งไปยังโปรแกรมเล่นโดยตรงแทน MediaItem
Kotlin
// Create a data source factory. val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory() // Create a HLS media source pointing to a playlist uri. val hlsMediaSource = HlsMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(hlsUri)) // Create a player instance. val player = ExoPlayer.Builder(context).build() // Set the HLS media source as the playlist with a single media item. player.setMediaSource(hlsMediaSource) // Prepare the player. player.prepare()
Java
// Create a data source factory. DataSource.Factory dataSourceFactory = new DefaultHttpDataSource.Factory(); // Create a HLS media source pointing to a playlist uri. HlsMediaSource hlsMediaSource = new HlsMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(hlsUri)); // Create a player instance. ExoPlayer player = new ExoPlayer.Builder(context).build(); // Set the HLS media source as the playlist with a single media item. player.setMediaSource(hlsMediaSource); // Prepare the player. player.prepare();
การเข้าถึงไฟล์ Manifest
คุณสามารถเรียกข้อมูลไฟล์ Manifest ฉบับปัจจุบันได้โดยเรียกใช้ Player.getCurrentManifest
สำหรับ HLS คุณควรแคสต์ออบเจ็กต์ที่แสดงผลไปยัง HlsManifest
ระบบจะเรียกใช้ Callback onTimelineChanged
ของ Player.Listener
ทุกครั้งที่โหลดไฟล์ Manifest ด้วย การดำเนินการนี้จะเกิดขึ้น 1 ครั้งสำหรับเนื้อหาแบบออนดีมานด์ และอาจเกิดขึ้นหลายครั้งสำหรับเนื้อหาสด ข้อมูลโค้ดต่อไปนี้แสดงวิธีที่แอปสามารถดำเนินการเมื่อใดก็ตามที่มีการโหลดไฟล์ Manifest
Kotlin
player.addListener( object : Player.Listener { override fun onTimelineChanged(timeline: Timeline, @TimelineChangeReason reason: Int) { val manifest = player.currentManifest if (manifest is HlsManifest) { // Do something with the manifest. } } } )
Java
player.addListener( new Player.Listener() { @Override public void onTimelineChanged( Timeline timeline, @Player.TimelineChangeReason int reason) { Object manifest = player.getCurrentManifest(); if (manifest != null) { HlsManifest hlsManifest = (HlsManifest) manifest; // Do something with the manifest. } } });
การปรับแต่งการเล่น
ExoPlayer มีวิธีต่างๆ ในการปรับแต่งประสบการณ์การเล่นให้เหมาะกับความต้องการของแอป ดูตัวอย่างได้ที่หน้าการปรับแต่ง
การปิดใช้การเตรียมแบบไม่มีข้อมูลโค้ด
โดยค่าเริ่มต้น ExoPlayer จะใช้การเตรียมแบบไม่มีข้อมูลโค้ด ซึ่งหมายความว่า ExoPlayer จะใช้เฉพาะข้อมูลในเพลย์ลิสต์แบบหลายตัวแปรเพื่อเตรียมสตรีม ซึ่งจะใช้งานได้หากแท็ก #EXT-X-STREAM-INF
มีแอตทริบิวต์ CODECS
คุณอาจต้องปิดฟีเจอร์นี้หากกลุ่มสื่อมีแทร็กคำบรรยายแทนเสียงที่มักซ์ซึ่งไม่ได้ประกาศไว้ในเพลย์ลิสต์เวอร์ชันแปรผันหลายตัวแปรด้วยแท็ก #EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS
มิเช่นนั้น ระบบจะไม่ตรวจหาและเล่นแทร็กคำบรรยายแทนเสียงเหล่านี้ คุณสามารถปิดใช้การเตรียมแบบไม่แบ่งกลุ่มได้ใน HlsMediaSource.Factory
ดังที่แสดงในข้อมูลโค้ดต่อไปนี้ โปรดทราบว่าวิธีนี้จะเพิ่มเวลาเริ่มเนื่องจาก ExoPlayer ต้องดาวน์โหลดกลุ่มสื่อเพื่อค้นหาแทร็กเพิ่มเติมเหล่านี้ และขอแนะนำให้ประกาศแทร็กคำบรรยายแทนเสียงในเพลย์ลิสต์หลายตัวแปรแทน
Kotlin
val hlsMediaSource = HlsMediaSource.Factory(dataSourceFactory) .setAllowChunklessPreparation(false) .createMediaSource(MediaItem.fromUri(hlsUri))
Java
HlsMediaSource hlsMediaSource = new HlsMediaSource.Factory(dataSourceFactory) .setAllowChunklessPreparation(false) .createMediaSource(MediaItem.fromUri(hlsUri));
การสร้างเนื้อหา HLS ที่มีคุณภาพสูง
คุณสามารถทำตามหลักเกณฑ์บางอย่างเพื่อปรับปรุงเนื้อหา HLS เพื่อให้ ExoPlayer ทำงานได้เต็มประสิทธิภาพ โปรดอ่านคำอธิบายแบบเต็มในโพสต์ Medium เกี่ยวกับการเล่น HLS ใน ExoPlayer ประเด็นหลักๆ มีดังนี้
- ใช้ระยะเวลาของกลุ่มที่แน่นอน
- ใช้สตรีมสื่อแบบต่อเนื่อง หลีกเลี่ยงการเปลี่ยนแปลงโครงสร้างสื่อในแต่ละกลุ่ม
- ใช้แท็ก
#EXT-X-INDEPENDENT-SEGMENTS
- แนะนำให้ใช้สตรีมที่แยกข้อมูลแล้ว แทนไฟล์ที่มีทั้งวิดีโอและเสียง
- ระบุข้อมูลทั้งหมดที่คุณทำได้ในเพลย์ลิสต์เวอร์ชันหลายตัวแปร
หลักเกณฑ์ต่อไปนี้ใช้กับสตรีมแบบสดโดยเฉพาะ
- ใช้แท็ก
#EXT-X-PROGRAM-DATE-TIME
- ใช้แท็ก
#EXT-X-DISCONTINUITY-SEQUENCE
- แสดงเนื้อหาเป็นเวลานาน 1 นาทีขึ้นไปกำลังดี