ExoPlayer là một thư viện trình phát đa phương tiện mã nguồn mở dành cho Android do Google phát triển như một sự thay thế cho MediaPlayer tích hợp sẵn. ExoPlayer cung cấp khả năng phát âm thanh và video ở nhiều định dạng khác nhau, bao gồm DASH, HLS, SmoothStreaming và các tệp đa phương tiện thông thường, thông qua một API duy nhất có hỗ trợ phát trực tuyến thích ứng. Theo Google I/O (2024), ExoPlayer được sử dụng trong hơn 60.000 ứng dụng Android, bao gồm YouTube, Google TV và Netflix.
Điểm chính
ExoPlayer là một thư viện phát đa phương tiện mã nguồn mở (Apache 2.0) dành cho Android, có phiên bản đầu tiên được Google phát hành vào năm 2014. Không giống như MediaPlayer tích hợp sẵn, vốn là một lớp bọc mỏng trên bộ giải mã đa phương tiện hệ thống (MediaCodec), ExoPlayer được triển khai hoàn toàn ở cấp độ Java/Kotlin, mang lại cho nhà phát triển quyền kiểm soát hoàn toàn đối với mọi giai đoạn phát lại.
Về mặt kiến trúc, ExoPlayer được xây dựng dựa trên nguyên tắc mô-đun: mỗi khía cạnh của việc phát lại được triển khai bởi một thành phần riêng biệt. Mô-đun lõi (exoplayer-core) chứa trình phát, bộ kết xuất, bộ chọn rành và quản lý bộ đệm. Các mô-đun bổ sung (exoplayer-dash, exoplayer-hls, exoplayer-rtsp, exoplayer-smoothstreaming) thêm hỗ trợ cho các giao thức phát trực tuyến tương ứng. Kiến trúc này cho phép các ứng dụng chỉ bao gồm các thành phần cần thiết, giảm thiểu kích thước APK.
ExoPlayer 2 (phiên bản chính hiện tại) được phát hành vào năm 2018 và mang lại sự đại tu lớn về API: giới thiệu Player Interface, hỗ trợ Compose thông qua AndroidX Media3, cải thiện xử lý lỗi và các thuật toán chọn rành thích ứng. Từ phiên bản 2.19 (2024), ExoPlayer trở thành một phần của thư viện AndroidX Media, đơn giản hóa việc tích hợp và cập nhật thông qua trình quản lý phụ thuộc tiêu chuẩn của Android.
Ở trung tâm của ExoPlayer là thành phần ExoPlayerImpl, quản lý vòng đời phát lại. Nó chứa MediaSource (nguồn đa phương tiện), TrackSelector (chọn rành), LoadControl (quản lý bộ đệm) và danh sách Renderer (bộ kết xuất cho video, âm thanh, phụ đề và siêu dữ liệu). Mỗi thành phần có thể được thay thế bằng triển khai tùy chỉnh thông qua Builder hoặc phương thức nhà máy.
Để kết xuất video, ExoPlayer sử dụng SurfaceView, TextureView hoặc SphericalSurfaceView (cho video 360 độ). Lựa chọn được khuyến nghị là SurfaceView, vì nó cung cấp khả năng tăng tốc phần cứng và tiêu thụ điện tối thiểu. Đối với Jetpack Compose, thư viện AndroidX Media3 cung cấp thành phần `AndroidView`, bao bọc SurfaceView và `Media3Compose` thử nghiệm với tích hợp Compose gốc.
ExoPlayer cung cấp nhiều tính năng vượt xa một trình phát đa phương tiện thông thường. Các khả năng chính bao gồm hỗ trợ tất cả các giao thức phát trực tuyến phổ biến, hệ thống DRM linh hoạt, chuyển đổi tốc độ bit thích ứng (ABR) và công cụ phân tích phát lại.
| Tính năng | Mô tả | Mô-đun |
|---|---|---|
| DASH | Phát trực tuyến thích ứng theo chuẩn MPEG | exoplayer-dash |
| HLS | HTTP Live Streaming từ Apple | exoplayer-hls |
| SmoothStreaming | Phát trực tuyến thích ứng từ Microsoft | exoplayer-smoothstreaming |
| RTSP | Giao thức phát trực tuyến thời gian thực cho live | exoplayer-rtsp |
| Widevine | Bảo vệ nội dung DRM | exoplayer-drm |
| Concatenation | Ghép nhiều tệp đa phương tiện | exoplayer-core |
| Ads | Tích hợp IMA SDK cho quảng cáo | exoplayer-ima |
ABR (Adaptive Bitrate) trong ExoPlayer được triển khai thông qua giao diện AdaptiveTrackSelection. Theo mặc định, AdaptiveTrackSelectionFactory được sử dụng, tạo ra DefaultAdaptiveTrackSelection — một thuật toán cân bằng xem xét băng thông mạng và kích thước bộ đệm. Đối với các trường hợp cụ thể, có thể kết nối các triển khai thay thế: BOLA (giảm thiểu chuyển đổi), RandomAdaptiveTrackSelection (thử nghiệm) hoặc triển khai tùy chỉnh thông qua giao diện TrackSelection.
BandwidthMeter — một thành phần quan trọng khác chịu trách nhiệm đo băng thông mạng. Theo mặc định, DefaultBandwidthMeter được sử dụng, thu thập thống kê về tất cả các yêu cầu HTTP của trình phát. Nhà phát triển có thể mở rộng nó để tính đến các yếu tố bổ sung: loại mạng (Wi-Fi, 4G, 5G), tín hiệu tháp di động hoặc chi phí dữ liệu cho người dùng.
ExoPlayer hỗ trợ Widevine (L1, L3), PlayReady và ClearKey DRM. Việc lấy giấy phép được cấu hình thông qua DrmSessionManager, tương tác với máy chủ cấp phép. Đối với video cao cấp (4K HDR), cần hỗ trợ phần cứng Widevine L1, cung cấp bảo vệ ở cấp độ chip và ngăn chặn chụp màn hình. Việc lựa chọn hệ thống DRM phụ thuộc vào nền tảng mục tiêu: Widevine được sử dụng trên Android và Chromecast, PlayReady trên Xbox và Windows, FairPlay trên iOS và Apple TV. ExoPlayer tự động xác định hệ thống DRM khả dụng dựa trên tệp MPD và không yêu cầu cấu hình thủ công cho các trường hợp cơ bản.
Việc kết nối ExoPlayer với một dự án Android được thực hiện thông qua các phụ thuộc Gradle. Từ phiên bản 2.19, ExoPlayer là một phần của AndroidX Media (androidx.media3), đảm bảo tương thích với Jetpack Compose và các thành phần AndroidX khác. Hãy xem tích hợp từng bước trong Kotlin.
Thêm các mô-đun ExoPlayer vào tệp build.gradle (Module). Bộ tối thiểu bao gồm core, ui và mô-đun cho giao thức phát trực tuyến cần thiết. Để phát nội dung DASH, cần exoplayer-dash, cho 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"
}
Tạo và cấu hình trình phát trong Activity hoặc Fragment. ExoPlayer sử dụng PlayerView (hoặc StyledPlayerView để tùy chỉnh) để hiển thị video và các điều khiển tích hợp sẵn. Cấu hình tối thiểu bao gồm tạo trình phát qua ExoPlayer.Builder và chuyển MediaItem với URI nguồn.
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()
}
}
Đối với ứng dụng sản xuất, cần xử lý các lỗi phát lại có thể xảy ra: lỗi mạng, định dạng không được hỗ trợ, lỗi cấp phép DRM. ExoPlayer cung cấp giao diện Player.Listener với các phương thức onPlayerError, onPlaybackStateChanged và onPlayWhenReadyChanged. Nên hiển thị cho người dùng thông báo lỗi có thông tin kèm tùy chọn thử lại.
Lựa chọn giữa ExoPlayer và MediaPlayer tích hợp sẵn là một câu hỏi phổ biến khi phát triển ứng dụng Android. MediaPlayer là một phần của Android SDK từ phiên bản 1.0, trong khi ExoPlayer là một thư viện yêu cầu phụ thuộc Gradle. Hãy xem sự khác biệt của chúng theo các tiêu chí chính.
| Tiêu chí | ExoPlayer | MediaPlayer |
|---|---|---|
| Kiến trúc | Mô-đun, hoàn toàn bằng Java/Kotlin | Lớp bọc trên thành phần C++ hệ thống |
| Phát trực tuyến | DASH, HLS, SmoothStreaming, RTSP | Chỉ tệp cục bộ và HLS (Android 9+) |
| Tùy chỉnh | Hoàn toàn (mọi thành phần đều thay thế được) | Tối thiểu (chỉ tham số) |
| Cập nhật | Qua Google Play hoặc APK (không phụ thuộc HĐH) | Chỉ qua cập nhật Android (OTA) |
| Kích thước APK | +1–3 MB (tùy mô-đun) | 0 (một phần của HĐH) |
| SDK tối thiểu | API 16+ (Android 4.1) | API 1+ |
| DRM | Widevine, PlayReady, ClearKey | Widevine (hạn chế) |
ExoPlayer vượt trội trong các kịch bản yêu cầu phát trực tuyến (DASH, HLS), tùy chỉnh giao diện người dùng, hỗ trợ DRM và độc lập với phiên bản Android. MediaPlayer phù hợp cho các ứng dụng đơn giản phát tệp đa phương tiện cục bộ, nơi kích thước APK là quan trọng và không có yêu cầu về phát trực tuyến thích ứng. Đối với các ứng dụng hiện đại có nội dung từ mạng, ExoPlayer là lựa chọn rõ ràng.
Ngoại lệ — các ứng dụng có SDK tối thiểu dưới API 16 (Android 4.1), hầu như không còn trên thị trường. Đối với tất cả các ứng dụng có targetSdk 33+ và SDK tối thiểu 21+, ExoPlayer không chỉ được ưa tiên mà còn cần thiết để hỗ trợ các định dạng hiện đại như AV1 và Dolby Vision thông qua các phần mở rộng thích hợp.
Đối với các ứng dụng sản xuất, việc tích hợp cơ bản ExoPlayer thường yêu cầu cấu hình bổ sung: quản lý bộ nhớ đệm, tối ưu hóa bộ đệm cho mạng di động, tích hợp phân tích và tùy chỉnh lựa chọn rành âm thanh. Hãy xem các kịch bản sử dụng nâng cao.
CacheDataSourceFactory cho phép lưu vùng đệm các phân đoạn đã tải xuống vào bộ nhớ cục bộ, tiết kiệm lưu lượng khi xem lại và cho phép phát ngoại tuyến. ExoPlayer sử dụng SimpleCache từ thư viện exoplayer-cas — bộ nhớ đệm dựa trên tệp có hỗ trợ loại bỏ LRU và giới hạn kích thước.
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()
Trong các ứng dụng di động, việc xử lý chuyển đổi giữa Wi-Fi và mạng di động là rất quan trọng. ExoPlayer cung cấp ConnectivityManager để theo dõi trạng thái mạng. Khi mất kết nối, nên không dừng trình phát mà chuyển nó sang trạng thái PAUSED trong khi giữ nguyên vị trí. Sau khi khôi phục kết nối, hãy tiếp tục phát lại bằng cách tải lại các phân đoạn.
Với sự ra mắt của AndroidX Media3, thư viện đã có hỗ trợ thử nghiệm cho Jetpack Compose. Thành phần `AndroidView` bao bọc SurfaceView hoặc PlayerView, đảm bảo tương thích với phân cấp Compose. Để tích hợp sâu hơn, thư viện `androidx.media3:media3-ui-compose` được sử dụng, cung cấp các điều khiển trình phát tương thích 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 } }
)
}
Câu hỏi thường gặp
ExoPlayer hỗ trợ Android API 16+ (Android 4.1 Jelly Bean). Tuy nhiên, đối với DASH và HLS với các phân đoạn fMP4, nên sử dụng API 21+ (Android 5.0 Lollipop). Các mô-đun DRM (Widevine) yêu cầu API 19+ và giải mã HEVC phần cứng khả dụng từ API 21.
Có, ExoPlayer rất phù hợp cho âm thanh. Đối với phát chỉ âm thanh, không cần SurfaceView hoặc PlayerView. ExoPlayer sẽ tự động chọn bộ kết xuất âm thanh và hoạt động trong nền. Để phát nền, nên sử dụng MediaSessionService để tích hợp với các điều khiển hệ thống.
TrackSelector trong ExoPlayer quản lý việc chọn rành âm thanh. Để chuyển đổi, hãy sử dụng player.getCurrentTracks().groups và player.setTrackSelectionParameters() chỉ định ngôn ngữ âm thanh ưa thích. Đối với các luồng DASH và HLS có nhiều rành âm thanh, việc chuyển đổi diễn ra mà không làm gián đoạn phát lại.
Có, ExoPlayer hỗ trợ phụ đề nhúng (trong vùng chứa MP4, WebM) và bên ngoài ở các định dạng TTML, SRT, VTT và CEA-608. Đối với phụ đề bên ngoài, SingleSampleMediaSource hoặc MergingMediaSource được sử dụng để hợp nhất với luồng video. Hiển thị phụ đề có kiểu cách được cấu hình thông qua CaptionStyleCompat.
Đối với phát trực tuyến độ trễ thấp, hãy cấu hình LoadControl với các giá trị bộ đệm mục tiêu nhỏ hơn: sử dụng DefaultLoadControl.Builder().setTargetBufferBytes(1024 * 512).setBufferDurationsMs(500, 2000, 500, 1000) cho HLS LL và DASH LL. Đồng thời đặt minPlaybackSpeed = 1.02 để đổ đầy bộ đệm tăng tốc khi bị tụt lại so với phát trực tiếp.
Tóm tắt
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm