Разработчик 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

Выполнено: 0 / 5

Сравнение HLS и DASH: что выбрать

Выбор протокола обычно диктует серверная сторона, но понимать различия полезно. Ниже — сравнение по ключевым признакам без привязки к конкретным реализациям.

КритерийHLSDASH
Файл описания потокаПлейлист .m3u8Манифест .mpd (XML)
Разработчик стандартаAppleMPEG (открытый стандарт)
Модуль ExoPlayer2exoplayer-hlsexoplayer-dash
Класс MediaSourceHlsMediaSourceDashMediaSource
Типичный сценарийШирокая совместимость, Apple-устройстваГибкие конфигурации, крупные платформы

Многие сервисы отдают оба формата одновременно: HLS — для совместимости с экосистемой Apple, DASH — для остальных клиентов. На Android технически работают оба, поэтому приоритет стоит отдавать тому формату, который стабильнее отдаёт ваш конкретный CDN, а не абстрактным рекомендациям.

📊 Какой формат стриминга вы используете в своём приложении?
Только HLS
Только DASH
Оба формата
Пока только выбираю

Типичные ошибки и их диагностика

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