ExoPlayer เป็นไลบรารีโปรแกรมเล่นสื่อแบบโอเพนซอร์สสำหรับ Android ที่พัฒนาโดย Google เพื่อเป็นทางเลือกแทน MediaPlayer ในตัว ExoPlayer รองรับการเล่นเสียงและวิดีโอในรูปแบบต่าง ๆ รวมถึง DASH, HLS, SmoothStreaming และไฟล์สื่อทั่วไป ผ่าน API เดียวที่มีการรองรับ สตรีมมิงแบบปรับตัวได้ ตามข้อมูลของ Google I/O (2024) ExoPlayer ถูกใช้ในแอปพลิเคชัน Android กว่า 60,000 รายการ รวมถึง YouTube, Google TV และ Netflix
ประเด็นสำคัญ
ExoPlayer เป็นไลบรารีการเล่นมัลติมีเดียแบบโอเพนซอร์ส (Apache 2.0) สำหรับ Android ซึ่งเวอร์ชันแรกได้รับการเผยแพร่โดย Google ในปี 2014 แตกต่างจาก MediaPlayer ในตัวซึ่งเป็นชั้นบาง ๆ ที่ห่อหุ้มตัวแปลงสัญญาณสื่อของระบบ (MediaCodec) ExoPlayer ถูกใช้งานทั้งหมดในระดับ Java/Kotlin ทำให้นักพัฒนาสามารถควบคุมทุกขั้นตอนของการเล่นได้อย่างสมบูรณ์
ในเชิงสถาปัตยกรรม ExoPlayer สร้างขึ้นบนหลักการแบบโมดูลาร์: แต่ละด้านของการเล่นถูกใช้งานโดยส่วนประกอบแยกกัน โมดูลหลัก (exoplayer-core) ประกอบด้วยโปรแกรมเล่น, เรนเดอร์เรอร์, ตัวเลือกแทร็ก และการจัดการบัฟเฟอร์ โมดูลเพิ่มเติม (exoplayer-dash, exoplayer-hls, exoplayer-rtsp, exoplayer-smoothstreaming) เพิ่มการรองรับโปรโตคอลสตรีมมิงที่เกี่ยวข้อง สถาปัตยกรรมนี้ช่วยให้แอปพลิเคชันรวมเฉพาะส่วนประกอบที่จำเป็นเท่านั้น ช่วยลดขนาด APK
ExoPlayer 2 (เวอร์ชันหลักปัจจุบัน) เผยแพร่ในปี 2018 และนำการปรับปรุง API ครั้งใหญ่: การแนะนำ Player Interface, การรองรับ Compose ผ่าน AndroidX Media3, การจัดการข้อผิดพลาดที่ดีขึ้น และอัลกอริทึมการเลือกแทร็กแบบปรับตัวได้ ตั้งแต่เวอร์ชัน 2.19 (2024) ExoPlayer ได้กลายเป็นส่วนหนึ่งของไลบรารี AndroidX Media ทำให้การรวมและการอัปเดตง่ายขึ้นผ่านตัวจัดการการพึ่งพามาตรฐานของ Android
ที่แกนกลางของ ExoPlayer คือส่วนประกอบ ExoPlayerImpl ซึ่งจัดการวงจรชีวิตการเล่น ประกอบด้วย MediaSource (แหล่งสื่อ), TrackSelector (การเลือกแทร็ก), LoadControl (การจัดการบัฟเฟอร์) และรายการ Renderer (เรนเดอร์เรอร์สำหรับวิดีโอ, เสียง, คำบรรยาย และข้อมูลเมตา) แต่ละส่วนประกอบสามารถแทนที่ได้ด้วยการใช้งานแบบกำหนดเองผ่าน Builder หรือวิธีการจากโรงงาน
สำหรับการเรนเดอร์วิดีโอ ExoPlayer ใช้ SurfaceView, TextureView หรือ SphericalSurfaceView (สำหรับวิดีโอ 360 องศา) ตัวเลือกที่แนะนำคือ SurfaceView เนื่องจากให้การเร่งด้วยฮาร์ดแวร์และการใช้พลังงานน้อยที่สุด สำหรับ Jetpack Compose ไลบรารี AndroidX Media3 มีส่วนประกอบ `AndroidView` ที่ห่อหุ้ม SurfaceView และ `Media3Compose` แบบทดลองที่มีการผสานรวม Compose โดยตรง
ExoPlayer มีคุณสมบัติมากมายที่เหนือกว่าโปรแกรมเล่นสื่อทั่วไป ความสามารถหลักรวมถึงการรองรับโปรโตคอลสตรีมมิงยอดนิยมทั้งหมด, ระบบ DRM ที่ยืดหยุ่น, การสลับอัตราบิตแบบปรับตัวได้ (ABR) และเครื่องมือวิเคราะห์การเล่น
| คุณสมบัติ | คำอธิบาย | โมดูล |
|---|---|---|
| DASH | สตรีมมิงแบบปรับตัวได้ตามมาตรฐาน MPEG | exoplayer-dash |
| HLS | HTTP Live Streaming จาก Apple | exoplayer-hls |
| SmoothStreaming | สตรีมมิงแบบปรับตัวได้จาก Microsoft | exoplayer-smoothstreaming |
| RTSP | โปรโตคอลสตรีมมิงแบบเวลาจริงสำหรับถ่ายทอดสด | exoplayer-rtsp |
| Widevine | การป้องกันเนื้อหา DRM | exoplayer-drm |
| Concatenation | การรวมไฟล์สื่อหลายไฟล์ | exoplayer-core |
| Ads | การผสานรวม IMA SDK สำหรับโฆษณา | exoplayer-ima |
ABR (Adaptive Bitrate) ใน ExoPlayer ถูกใช้งานผ่านอินเทอร์เฟซ AdaptiveTrackSelection โดยค่าเริ่มต้นจะใช้ AdaptiveTrackSelectionFactory ซึ่งสร้าง DefaultAdaptiveTrackSelection — อัลกอริทึมที่สมดุลซึ่งพิจารณาแบนด์วิดท์เครือข่ายและขนาดบัฟเฟอร์ สำหรับสถานการณ์เฉพาะ สามารถเชื่อมต่อการใช้งานทางเลือก: BOLA (ลดการสลับให้น้อยที่สุด), RandomAdaptiveTrackSelection (การทดสอบ) หรือการใช้งานแบบกำหนดเองผ่านอินเทอร์เฟซ TrackSelection
BandwidthMeter — อีกหนึ่งส่วนประกอบสำคัญที่รับผิดชอบการวัดแบนด์วิดท์เครือข่าย โดยค่าเริ่มต้นจะใช้ DefaultBandwidthMeter ซึ่งรวบรวมสถิติของคำขอ HTTP ทั้งหมดของโปรแกรมเล่น นักพัฒนาสามารถขยายเพื่อพิจารณาปัจจัยเพิ่มเติม: ประเภทเครือข่าย (Wi-Fi, 4G, 5G), สัญญาณเสาโทรศัพท์เคลื่อนที่ หรือต้นทุนข้อมูลสำหรับผู้ใช้
ExoPlayer รองรับ Widevine (L1, L3), PlayReady และ ClearKey DRM การรับใบอนุญาตถูกกำหนดค่าผ่าน DrmSessionManager ซึ่งโต้ตอบกับเซิร์ฟเวอร์ใบอนุญาต สำหรับวิดีโอพรีเมียม (4K HDR) จำเป็นต้องมีการรองรับฮาร์ดแวร์ Widevine L1 ซึ่งให้การป้องกันระดับชิปและป้องกันการจับภาพหน้าจอ การเลือกระบบ DRM ขึ้นอยู่กับแพลตฟอร์มเป้าหมาย: Widevine ใช้บน Android และ Chromecast, PlayReady บน Xbox และ Windows, FairPlay บน iOS และ Apple TV ExoPlayer ตรวจสอบระบบ DRM ที่มีอยู่โดยอัตโนมัติตามไฟล์ MPD และไม่ต้องการการกำหนดค่าด้วยตนเองสำหรับสถานการณ์พื้นฐาน
การเชื่อมต่อ ExoPlayer กับโปรเจกต์ Android ทำได้ผ่านการพึ่งพา Gradle ตั้งแต่เวอร์ชัน 2.19 ExoPlayer เป็นส่วนหนึ่งของ AndroidX Media (androidx.media3) ทำให้มั่นใจในความเข้ากันได้กับ Jetpack Compose และส่วนประกอบ AndroidX อื่น ๆ มาดูการผสานรวมทีละขั้นตอนใน Kotlin
เพิ่มโมดูล ExoPlayer ลงในไฟล์ build.gradle (Module) ชุดขั้นต่ำประกอบด้วย core, ui และโมดูลสำหรับโปรโตคอลสตรีมมิงที่จำเป็น สำหรับการเล่นเนื้อหา DASH จำเป็นต้องใช้ exoplayer-dash สำหรับ HLS — exoplayer-hls
dependencies {
implementation "androidx.media3:media3-exoplayer:1.5.0"
implementation "androidx.media3:media3-ui:1.5.0"
implementation "androidx.media3:media3-exoplayer-dash:1.5.0"
implementation "androidx.media3:media3-exoplayer-hls:1.5.0"
}
การสร้างและกำหนดค่าโปรแกรมเล่นใน Activity หรือ Fragment ExoPlayer ใช้ PlayerView (หรือ StyledPlayerView สำหรับการปรับแต่ง) เพื่อแสดงวิดีโอและส่วนควบคุมในตัว การกำหนดค่าขั้นต่ำรวมถึงการสร้างโปรแกรมเล่นผ่าน ExoPlayer.Builder และส่ง MediaItem พร้อม URI ของแหล่งที่มา
class PlayerActivity : AppCompatActivity() {
private var player: ExoPlayer? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_player)
player = ExoPlayer.Builder(this).build()
val playerView = findViewById<StyledPlayerView>(R.id.playerView)
playerView.player = player
val mediaItem = MediaItem
.Builder()
.setUri("https://example.com/video.mp4")
.build()
player?.setMediaItem(mediaItem)
player?.prepare()
}
override fun onDestroy() {
player?.release()
super.onDestroy()
}
}
สำหรับแอปพลิเคชันที่ใช้งานจริง จำเป็นต้องมีการจัดการข้อผิดพลาดในการเล่นที่อาจเกิดขึ้น: ความล้มเหลวของเครือข่าย, รูปแบบที่ไม่รองรับ, ข้อผิดพลาดการออกใบอนุญาต DRM ExoPlayer มีอินเทอร์เฟซ Player.Listener พร้อมเมธอด onPlayerError, onPlaybackStateChanged และ onPlayWhenReadyChanged แนะนำให้แสดงข้อความแสดงข้อผิดพลาดที่ให้ข้อมูลแก่ผู้ใช้พร้อมตัวเลือกให้ลองใหม่
การเลือกระหว่าง ExoPlayer และ MediaPlayer ในตัวเป็นคำถามที่พบบ่อยเมื่อพัฒนาแอปพลิเคชัน Android MediaPlayer เป็นส่วนหนึ่งของ Android SDK ตั้งแต่เวอร์ชัน 1.0 ในขณะที่ ExoPlayer เป็นไลบรารีที่ต้องการการพึ่งพา Gradle มาดูความแตกต่างตามเกณฑ์สำคัญ
| เกณฑ์ | ExoPlayer | MediaPlayer |
|---|---|---|
| สถาปัตยกรรม | โมดูลาร์, ทั้งหมดใน Java/Kotlin | ชั้นห่อหุ้มส่วนประกอบ C++ ของระบบ |
| สตรีมมิง | DASH, HLS, SmoothStreaming, RTSP | เฉพาะไฟล์ในเครื่องและ HLS (Android 9+) |
| การปรับแต่ง | เต็มรูปแบบ (ทุกส่วนประกอบเปลี่ยนแทนได้) | น้อยที่สุด (เฉพาะพารามิเตอร์) |
| การอัปเดต | ผ่าน Google Play หรือ APK (อิสระจาก OS) | ผ่านการอัปเดต Android (OTA) เท่านั้น |
| ขนาด APK | +1–3 MB (ขึ้นอยู่กับโมดูล) | 0 (ส่วนหนึ่งของ OS) |
| SDK ขั้นต่ำ | API 16+ (Android 4.1) | API 1+ |
| DRM | Widevine, PlayReady, ClearKey | Widevine (จำกัด) |
ExoPlayer ชนะ ในสถานการณ์ที่ต้องการสตรีมมิง (DASH, HLS), การปรับแต่ง UI, การรองรับ DRM และความเป็นอิสระจากเวอร์ชัน Android MediaPlayer เหมาะสำหรับแอปพลิเคชันง่าย ๆ ที่เล่นไฟล์สื่อในเครื่องซึ่งขนาด APK มีความสำคัญและไม่มีข้อกำหนดสำหรับสตรีมมิงแบบปรับตัวได้ สำหรับแอปพลิเคชันสมัยใหม่ที่มีเนื้อหาจากเครือข่าย ExoPlayer เป็นตัวเลือกที่ชัดเจน
ข้อยกเว้น — แอปพลิเคชันที่มี SDK ขั้นต่ำต่ำกว่า API 16 (Android 4.1) ซึ่งแทบไม่มีในตลาดแล้ว สำหรับแอปพลิเคชันทั้งหมดที่มี targetSdk 33+ และ SDK ขั้นต่ำ 21+ ExoPlayer ไม่เพียงแต่เป็นที่ต้องการเท่านั้น แต่ยังจำเป็นสำหรับการรองรับรูปแบบสมัยใหม่ เช่น AV1 และ Dolby Vision ผ่านส่วนขยายที่เหมาะสม
สำหรับแอปพลิเคชันที่ใช้งานจริง การผสานรวม ExoPlayer ขั้นพื้นฐานมักต้องการการกำหนดค่าเพิ่มเติม: การจัดการแคช, การปรับแต่งบัฟเฟอร์สำหรับเครือข่ายมือถือ, การผสานรวมกับการวิเคราะห์ และการปรับแต่งการเลือกแทร็กเสียง มาดูสถานการณ์การใช้งานขั้นสูง
CacheDataSourceFactory ช่วยให้แคชเซกเมนต์ที่ดาวน์โหลดไว้ในที่จัดเก็บในเครื่อง ประหยัดปริมาณการใช้งานเมื่อดูซ้ำและรองรับการเล่นแบบออฟไลน์ ExoPlayer ใช้ SimpleCache จากไลบรารี exoplayer-cas — การแคชบนไฟล์ที่มีการรองรับการนำออกแบบ LRU และข้อจำกัดด้านขนาด
val cache = SimpleCache(
cacheDir,
LeastRecentlyUsedCacheEvictor(50 * 1024 * 1024),
AppDatabaseProvider(this)
)
val cacheDataSourceFactory = CacheDataSource
.Factory()
.setCache(cache)
val player = ExoPlayer.Builder(this)
.setMediaSourceFactory(
DefaultMediaSourceFactory(cacheDataSourceFactory)
)
.build()
ในแอปพลิเคชันมือถือ การจัดการการสลับระหว่าง Wi-Fi และเครือข่ายมือถือเป็นสิ่งสำคัญ ExoPlayer มี ConnectivityManager สำหรับติดตามสถานะเครือข่าย เมื่อสูญเสียการเชื่อมต่อ แนะนำให้ไม่หยุดโปรแกรมเล่น แต่เปลี่ยนเป็นสถานะ PAUSED โดยรักษาตำแหน่งไว้ หลังจากกู้คืนการเชื่อมต่อ ให้เล่นต่อโดยโหลดเซกเมนต์ใหม่
ด้วยการเปิดตัว AndroidX Media3 ไลบรารีได้รับการรองรับแบบทดลองสำหรับ Jetpack Compose ส่วนประกอบ `AndroidView` ห่อหุ้ม SurfaceView หรือ PlayerView ทำให้มั่นใจในความเข้ากันได้กับลำดับชั้นของ Compose สำหรับการผสานรวมที่ลึกซึ้งยิ่งขึ้น มีการใช้ไลบรารี `androidx.media3:media3-ui-compose` ซึ่งให้ส่วนควบคุมโปรแกรมเล่นที่เข้ากันได้กับ Compose
@Composable
fun VideoPlayer(uri: String) {
val context = LocalContext.current
val player = remember {
ExoPlayer.Builder(context).build()
.also { it.setMediaItem(MediaItem.fromUri(uri)) }
}
DisposableEffect(key = null) {
player.prepare()
onDispose { player.release() }
}
AndroidView(
factory = { StyledPlayerView(context).also { it.player = player } }
)
}
คำถามที่พบบ่อย
ExoPlayer รองรับ Android API 16+ (Android 4.1 Jelly Bean) อย่างไรก็ตาม สำหรับ DASH และ HLS ที่มีเซกเมนต์ fMP4 แนะนำให้ใช้ API 21+ (Android 5.0 Lollipop) โมดูล DRM (Widevine) ต้องการ API 19+ และการถอดรหัส HEVC ด้วยฮาร์ดแวร์พร้อมใช้งานจาก API 21
ได้ ExoPlayer เหมาะอย่างยิ่งสำหรับเสียง สำหรับการเล่นเสียงอย่างเดียว ไม่จำเป็นต้องใช้ SurfaceView หรือ PlayerView ExoPlayer จะเลือกเรนเดอร์เรอร์เสียงโดยอัตโนมัติและทำงานในพื้นหลัง สำหรับการเล่นในพื้นหลัง แนะนำให้ใช้ MediaSessionService เพื่อผสานรวมกับส่วนควบคุมของระบบ
TrackSelector ใน ExoPlayer จัดการการเลือกแทร็กเสียง ในการสลับ ให้ใช้ player.getCurrentTracks().groups และ player.setTrackSelectionParameters() โดยระบุภาษาเสียงที่ต้องการ สำหรับสตรีม DASH และ HLS ที่มีหลายแทร็กเสียง การสลับเกิดขึ้นโดยไม่ขัดจังหวะการเล่น
ได้ ExoPlayer รองรับคำบรรยายในตัว (ในคอนเทนเนอร์ MP4, WebM) และภายนอกในรูปแบบ TTML, SRT, VTT และ CEA-608 สำหรับคำบรรยายภายนอก ใช้ SingleSampleMediaSource หรือ MergingMediaSource เพื่อรวมกับสตรีมวิดีโอ การแสดงคำบรรยายที่มีสไตล์ถูกกำหนดค่าผ่าน CaptionStyleCompat
สำหรับสตรีมมิงหน่วงต่ำ ให้กำหนดค่า LoadControl ด้วยค่าบัฟเฟอร์เป้าหมายที่เล็กลง: ใช้ DefaultLoadControl.Builder().setTargetBufferBytes(1024 * 512).setBufferDurationsMs(500, 2000, 500, 1000) สำหรับ HLS LL และ DASH LL นอกจากนี้ ตั้งค่า minPlaybackSpeed = 1.02 เพื่อการเติมบัฟเฟอร์แบบเร่งเมื่อ滞后การถ่ายทอดสด
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ