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 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также