ExoPlayer — це відкрита медіаплеєрна бібліотека для Android, розроблена Google як альтернатива вбудованому MediaPlayer. ExoPlayer забезпечує відтворення аудіо та відео в різних форматах, включаючи DASH, HLS, SmoothStreaming та звичайні медіафайли, через єдиний API з підтримкою адаптивного стрімінгу. За даними Google I/O (2024), ExoPlayer використовується більш ніж у 60 000 Android-додатках, включаючи YouTube, Google TV та Netflix.
Головне
ExoPlayer — це бібліотека для відтворення мультимедіа під Android з відкритим вихідним кодом (Apache 2.0), перша версія якої була випущена 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 | Real-Time Streaming Protocol для live | 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()
}
}
Для production-додатків необхідна обробка можливих помилок відтворення: мережеві збої, непідтримувані формати, помилки 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 (незалежно від ОС) | Тільки через оновлення Android (OTA) |
| Розмір APK | +1-3 MB (залежно від модулів) | 0 (частина ОС) |
| Min 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 через відповідні розширення.
Для production-додатків базова інтеграція 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.
Для Low-Latency стрімінгу налаштуйте LoadControl з меншими цільовими значеннями буфера: використовуйте DefaultLoadControl.Builder().setTargetBufferBytes(1024 * 512).setBufferDurationsMs(500, 2000, 500, 1000) для HLS LL та DASH LL. Також вкажіть minPlaybackSpeed = 1.02 для прискореного заповнення буфера при відставанні від live-трансляції.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також