Разработчик Android-приложения подключает ссылку на видеопоток, а плеер либо показывает чёрный экран, либо падает с ошибкой UnsupportedDrmException — чаще всего причина в том, что для формата HLS или DASH не подключён нужный модуль ExoPlayer2. Оба протокола — это способы адаптивной потоковой передачи видео, и ExoPlayer2 умеет работать с каждым из них, но только при корректной сборке зависимостей и правильно созданном MediaSource.
Ниже разберём, чем отличаются HLS и DASH, как устроена их поддержка в ExoPlayer2, какие зависимости нужны и как диагностировать типичные сбои воспроизведения. Материал ориентирован на разработчиков, которые впервые интегрируют стриминг в приложение или ищут причину конкретной ошибки.
Что такое HLS и DASH простыми словами
HLS (HTTP Live Streaming) — протокол потоковой передачи, разработанный Apple. Видео нарезается на короткие сегменты, а плеер получает плейлист в формате .m3u8, где перечислены эти сегменты и варианты качества. Плеер сам переключается между битрейтами в зависимости от скорости сети — это и называется адаптивным стримингом.
DASH (Dynamic Adaptive Streaming over HTTP) — открытый международный стандарт, решающий ту же задачу. Вместо m3u8-плейлиста используется XML-манифест с расширением .mpd (Media Presentation Description). DASH не привязан к экосистеме одной компании и гибче в настройке, поэтому его часто выбирают крупные видеосервисы.
- 📺 HLS — плейлист
.m3u8, исторически доминирует на устройствах Apple, широко поддерживается везде. - 📡 DASH — манифест
.mpd, открытый стандарт, популярен у стриминговых платформ. - 🔁 Оба протокола режут видео на сегменты и подстраивают качество под канал.
- 🔐 Оба поддерживают DRM-защиту контента (например, Widevine).
Для приложения разница практическая одна: от формата зависит, какой модуль ExoPlayer2 нужно подключить и какой класс MediaSource использовать.
Что такое ExoPlayer2 и почему его выбирают для стриминга
ExoPlayer2 — открытая медиабиблиотека от Google для Android, которая пришла на смену стандартному MediaPlayer. В отличие от системного плеера, она модульная: базовое ядро умеет мало, а поддержка конкретных форматов подключается отдельными зависимостями. Именно поэтому «голый» ExoPlayer не воспроизводит HLS или DASH, пока вы не добавите соответствующий модуль.
Библиотека активно развивается: актуальная линейка развития ведётся под именем Media3, где ExoPlayer сохранён как основной компонент. Название «ExoPlayer2» по-прежнему широко используется в документации и статьях, поэтому запрос «hls dash через exoplayer2» обычно означает именно эту связку — либо классическую библиотеку com.google.android.exoplayer2, либо её наследника Media3.
ExoPlayer2 — модульный плеер: HLS и DASH работают только после подключения соответствующих модулей, это самая частая причина «не играет поток».
Какие модули подключить для HLS и DASH
Для воспроизведения потоков нужны минимум три компонента: ядро, модуль формата и UI-компонент (если нужен готовый интерфейс плеера). В классической ветке ExoPlayer2 зависимости выглядят так:
implementation 'com.google.android.exoplayer:exoplayer-core:2.X.X'
implementation 'com.google.android.exoplayer:exoplayer-hls:2.X.X'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.X.X'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.X.X'
Версии всех модулей должны совпадать — смешивание разных релизов приводит к конфликтам и неочевидным сбоям. Точный номер актуальной версии проверяйте в официальном репозитории проекта, так как он регулярно обновляется.
⚠️ Внимание: если подключить только exoplayer-core и передать ссылку на m3u8-плейлист, приложение упадёт с ошибкой о неподдерживаемом источнике. Ядро не угадывает формат автоматически без соответствующего модуля.
Если планируете миграцию на Media3, имена артефактов меняются на androidx.media3:media3-exoplayer, media3-exoplayer-hls и media3-exoplayer-dash — логика подключения та же.
Создание MediaSource для HLS и DASH
После подключения модулей поток описывается через MediaSource. Для HLS используется HlsMediaSource, для DASH — DashMediaSource. Фабрика источника данных по умолчанию — DefaultHttpDataSource.
// HLS
MediaSource hlsSource = new HlsMediaSource.Factory(
new DefaultHttpDataSource.Factory())
.createMediaSource(MediaItem.fromUri("https://example.com/stream.m3u8"));
// DASH
MediaSource dashSource = new DashMediaSource.Factory(
new DefaultHttpDataSource.Factory())
.createMediaSource(MediaItem.fromUri("https://example.com/manifest.mpd"));
player.setMediaSource(hlsSource);
player.prepare();
player.play();
Вам не обязательно создавать источник вручную: если передать MediaItem с URI прямо в плеер, ExoPlayer попытается определить тип по расширению или MIME-типу. Однако явное указание setMimeType(MimeTypes.APPLICATION_M3U8) или MimeTypes.APPLICATION_MPD убирает неоднозначность, когда ссылка не содержит расширения — такое часто встречается у CDN с токенами в адресе.
☑️ Подключение потока в ExoPlayer2
Сравнение HLS и DASH: что выбрать
Выбор протокола обычно диктует серверная сторона, но понимать различия полезно. Ниже — сравнение по ключевым признакам без привязки к конкретным реализациям.
| Критерий | HLS | DASH |
|---|---|---|
| Файл описания потока | Плейлист .m3u8 | Манифест .mpd (XML) |
| Разработчик стандарта | Apple | MPEG (открытый стандарт) |
| Модуль ExoPlayer2 | exoplayer-hls | exoplayer-dash |
| Класс MediaSource | HlsMediaSource | DashMediaSource |
| Типичный сценарий | Широкая совместимость, Apple-устройства | Гибкие конфигурации, крупные платформы |
Многие сервисы отдают оба формата одновременно: HLS — для совместимости с экосистемой Apple, DASH — для остальных клиентов. На Android технически работают оба, поэтому приоритет стоит отдавать тому формату, который стабильнее отдаёт ваш конкретный CDN, а не абстрактным рекомендациям.
Типичные ошибки и их диагностика
Когда поток не играет, первым делом смотрите лог через слушатель Player.Listener — колбэк onPlayerError возвращает объект PlaybackException с кодом и вложенной причиной. Без анализа этого объекта диагностика превращается в гадание.
- 🚫 Source error / UnrecognizedInputFormatException — не подключён модуль формата или неверно определён тип потока. Проверьте зависимости и MIME-тип.
- 🌐 HttpDataSourceException — проблема сети или доступа: истёкший токен, неверные заголовки, блокировка по User-Agent. Проверьте, открывается ли ссылка в браузере или curl.
- 🔒 DrmSessionException — поток защищён DRM, а лицензия не получена. Нужна настройка
DrmSessionManagerс URL лицензионного сервера. - ⏱️ BehindLiveWindowException — плеер отстал от живого края трансляции. Обычно лечится вызовом
player.seekToDefaultPosition()и повторнымprepare().
⚠️ Внимание: cleartext-трафик (http:// вместо https://) на современных версиях Android по умолчанию блокируется. Если тестовый поток работает по http, либо переведите его на https, либо осознанно настройте networkSecurityConfig — но не оставляйте это в релизной сборке.
Как читать стек ошибки ExoPlayer2
В PlaybackException смотрите поле errorCode и цепочку getCause(). Внутренняя причина обычно точнее внешней: например, ParserException внутри Source error означает, что манифест скачался, но не распарсился — проверяйте валидность m3u8/mpd на стороне сервера.
Live-трансляции и низкая задержка
Отдельный случай — прямые эфиры. Live-потоки в HLS и DASH отличаются тем, что манифест постоянно обновляется: плеер периодически перезапрашивает плейлист, чтобы получить новые сегменты. ExoPlayer2 делает это автоматически, но для live-контента важно корректно обрабатывать отставание от «живого края».
Для снижения задержки существуют расширения протоколов — LL-HLS (Low Latency HLS) и LL-DASH. Их поддержка зависит и от версии библиотеки, и от сервера: если задержка критична (аукционы, ставки, интерактивные эфиры), проверяйте в документации конкретной версии ExoPlayer/Media3, какие механизмы низкой задержки реализованы, и убедитесь, что ваш стриминг-сервер их отдаёт.
Для live-потоков задавайте MediaItem с setLiveConfiguration — так можно управлять допустимым отставанием от живого края и поведением при переподключении.
Миграция на Media3: стоит ли обновляться
Классическая ветка com.google.android.exoplayer2 переведена в режим поддержки, а активная разработка идёт в AndroidX Media3. API во многом совпадает: ExoPlayer, MediaItem, HlsMediaSource и DashMediaSource сохранили свои имена, изменились в основном пакеты и имена артефактов.
Если проект новый — начинайте сразу с Media3. Если у вас работающее приложение на ExoPlayer2, срочной миграции не требуется, но планировать её стоит: новые функции и исправления появляются только в Media3. Перед миграцией сверьтесь с официальным гайдом по переходу, так как детали зависят от используемых компонентов.
Новые проекты начинайте с AndroidX Media3 — это прямой наследник ExoPlayer2 с тем же API для HLS и DASH.
Часто задаваемые вопросы
Что такое HLS и DASH простыми словами?
Это протоколы адаптивного стриминга: видео режется на короткие сегменты, а плеер скачивает их по HTTP и переключает качество под скорость сети. HLS использует плейлист .m3u8, DASH — XML-манифест .mpd.
Почему ExoPlayer2 не воспроизводит m3u8-ссылку?
Наиболее вероятная причина — не подключён модуль exoplayer-hls. Также проверьте MIME-тип у MediaItem, разрешение INTERNET в манифесте и доступность самой ссылки (токены, заголовки, https).
Можно ли одновременно поддерживать HLS и DASH в одном приложении?
Да. Подключите оба модуля и создавайте соответствующий MediaSource под каждый формат, либо позвольте плееру определять тип по MIME-типу MediaItem.
Поддерживает ли ExoPlayer2 DRM-защищённые потоки?
Да, при наличии модуля ядра и настройки DRM-конфигурации в MediaItem (например, Widevine с URL лицензионного сервера). Без корректной DRM-настройки защищённый поток выдаст DrmSessionException.
Чем Media3 отличается от ExoPlayer2?
Media3 — это новая ветка развития той же библиотеки под именем AndroidX. API для HLS и DASH практически сохранён, изменились пакеты и имена зависимостей. Активная разработка ведётся именно в Media3.