- Исправление ошибок «Открытый HTTP-трафик не разрешён»
- Исправление ошибок «SSLHandshakeException», «CertPathValidatorException» и «ERR_CERT_AUTHORITY_INVALID»
- Почему некоторые медиафайлы не поддаются поиску?
- Почему в некоторых MP3-файлах поиск неточен?
- Почему в моем видео медленный поиск?
- Почему некоторые файлы MPEG-TS не воспроизводятся?
- Почему в некоторых файлах MPEG-TS отсутствуют субтитры?
- Почему некоторые файлы MP4/FMP4 воспроизводятся некорректно?
- Почему некоторые потоки завершаются ошибкой с кодом ответа HTTP 301 или 302?
- Почему некоторые потоки завершаются ошибкой UnrecognizedInputFormatException?
- Почему setPlaybackParameters не работает должным образом на некоторых устройствах?
- Что означают ошибки «Доступ к проигрывателю осуществляется через неверный поток»?
- Как исправить ошибку «Неожиданная строка статуса: ICY 200 OK»?
- Как узнать, является ли воспроизводимая трансляция прямой трансляцией?
- Как сделать так, чтобы аудио воспроизводилось, когда приложение работает в фоновом режиме?
- Почему ExoPlayer поддерживает мой контент, а библиотека ExoPlayer Cast — нет?
- Почему контент не воспроизводится, но ошибка не возникает?
- Как мне загрузить библиотеку декодирования и использовать ее для воспроизведения?
- Можно ли воспроизводить видео YouTube напрямую с помощью ExoPlayer?
- Воспроизведение видео прерывается
- Ошибки нестабильного API-анализа
Исправление ошибок «Открытый HTTP-трафик не разрешён»
Эта ошибка возникает, если ваше приложение запрашивает HTTP-трафик в открытом тексте (то есть http://
вместо https://
), когда его конфигурация сетевой безопасности это не допускает. Если ваше приложение предназначено для Android 9 (уровень API 28) или выше, HTTP-трафик в открытом тексте отключен конфигурацией по умолчанию.
Если вашему приложению требуется работа с открытым HTTP-трафиком, вам необходимо использовать конфигурацию сетевой безопасности, которая это разрешает. Подробнее см. в документации по сетевой безопасности Android. Чтобы включить весь открытый HTTP-трафик, просто добавьте android:usesCleartextTraffic="true"
в элемент application
файла AndroidManifest.xml
вашего приложения.
Демонстрационное приложение ExoPlayer использует конфигурацию сетевой безопасности по умолчанию, поэтому оно не допускает HTTP-трафик в открытом виде. Вы можете включить его, следуя инструкциям выше.
Исправление ошибок «SSLHandshakeException», «CertPathValidatorException» и «ERR_CERT_AUTHORITY_INVALID»
SSLHandshakeException
, CertPathValidatorException
и ERR_CERT_AUTHORITY_INVALID
указывают на проблему с SSL-сертификатом сервера. Эти ошибки не относятся только к ExoPlayer. Подробнее см. в документации по SSL для Android .
Почему некоторые медиафайлы не поддаются поиску?
По умолчанию ExoPlayer не поддерживает поиск в медиафайлах, для которых единственным способом точного поиска является сканирование и индексация всего файла. ExoPlayer считает такие файлы неподлежащими поиску. Большинство современных форматов медиаконтейнеров включают метаданные для поиска (например, индекс образца), имеют чётко определённый алгоритм поиска (например, интерполированный бисекторный поиск для Ogg) или указывают, что их содержимое имеет постоянный битрейт. В таких случаях ExoPlayer может эффективно выполнять поиск и поддерживает его.
Если вам требуется поиск, но у вас есть медиафайлы, которые невозможно найти, рекомендуем преобразовать контент в более подходящий формат контейнера. Для файлов MP3, ADTS и AMR вы также можете включить поиск, предполагая, что битрейт файлов постоянный, как описано здесь .
Почему в некоторых MP3-файлах поиск неточен?
Файлы MP3 с переменным битрейтом (VBR) принципиально не подходят для случаев, требующих точного поиска. Этому есть две причины:
- Для точного поиска формат контейнера в идеале должен обеспечивать точное сопоставление времени и байта в заголовке. Это сопоставление позволяет проигрывателю сопоставить запрошенное время поиска с соответствующим смещением байта и начать запрос, анализ и воспроизведение медиафайлов с этого смещения. Заголовки, доступные для задания такого сопоставления в MP3 (например, заголовки XING), к сожалению, часто неточны.
- Для форматов контейнеров, которые не обеспечивают точного сопоставления времени и байтов (или вообще какого-либо сопоставления времени и байтов), точный поиск всё ещё возможен, если контейнер включает в поток абсолютные временные метки сэмплов. В этом случае проигрыватель может сопоставить время поиска с наилучшим предположением соответствующего смещения байтов, начать запрашивать медиаданные с этого смещения, проанализировать первую абсолютную временную метку сэмпла и фактически выполнить направленный двоичный поиск по медиаданным, пока не найдёт нужный сэмпл. К сожалению, MP3 не включает в поток абсолютные временные метки сэмплов, поэтому такой подход невозможен.
По этим причинам единственный способ выполнить точный поиск в MP3-файле VBR — это просканировать весь файл и вручную построить сопоставление времени и байтов в плеере. Эту стратегию можно включить с помощью флага FLAG_ENABLE_INDEX_SEEKING
, который можно установить в DefaultExtractorsFactory
с помощью setMp3ExtractorFlags
. Обратите внимание, что он плохо масштабируется для больших MP3-файлов, особенно если пользователь пытается выполнить поиск почти до конца потока вскоре после начала воспроизведения, что требует от плеера ожидания полной загрузки и индексации потока перед выполнением поиска. В ExoPlayer мы решили в данном случае оптимизировать скорость, а не точность, поэтому FLAG_ENABLE_INDEX_SEEKING
по умолчанию отключен.
Если вы контролируете воспроизводимые медиафайлы, мы настоятельно рекомендуем использовать более подходящий формат контейнера, например MP4. Нам не известны случаи, когда MP3 был бы оптимальным выбором.
Почему в моем видео медленный поиск?
Когда проигрыватель переходит на новую позицию воспроизведения в видео, ему необходимо сделать две вещи:
- Загрузите данные, соответствующие новой позиции воспроизведения, в буфер (это может не потребоваться, если эти данные уже буферизованы).
- Очистите видеодекодер и начните декодирование с I-кадра (ключевого кадра), предшествующего новой позиции воспроизведения, поскольку большинство форматов сжатия видео используют внутрикадровое кодирование . Чтобы обеспечить точность поиска (то есть воспроизведение должно начаться точно с позиции поиска), все кадры между предыдущим I-кадром и позицией поиска должны быть декодированы и немедленно удалены (без отображения на экране).
Задержку, вызванную (1), можно уменьшить, увеличив объем данных, буферизуемых проигрывателем в памяти, или предварительно кэшируя данные на диск .
Задержку, вызванную (2), можно уменьшить, либо снизив точность поиска с помощью ExoPlayer.setSeekParameters
, либо перекодировав видео для более частых I-кадров (что приведет к увеличению размера выходного файла).
Почему некоторые файлы MPEG-TS не воспроизводятся?
Некоторые файлы MPEG-TS не содержат разделителей единиц доступа (AUD). По умолчанию ExoPlayer использует AUD для экономичного определения границ кадров. Аналогично, некоторые файлы MPEG-TS не содержат ключевых кадров IDR. По умолчанию ExoPlayer учитывает только эти ключевые кадры.
При попытке воспроизвести файл MPEG-TS без ключевых кадров AUD или IDR ExoPlayer, по всей видимости, зависнет в состоянии буферизации. Для воспроизведения таких файлов можно использовать FLAG_DETECT_ACCESS_UNITS
и FLAG_ALLOW_NON_IDR_KEYFRAMES
соответственно. Эти флаги можно установить для DefaultExtractorsFactory
с помощью setTsExtractorFlags
или для DefaultHlsExtractorFactory
с помощью конструктора . Использование флага FLAG_DETECT_ACCESS_UNITS
не имеет побочных эффектов, за исключением больших вычислительных затрат по сравнению с определением границ кадров на основе AUD. Использование флага FLAG_ALLOW_NON_IDR_KEYFRAMES
может привести к временному визуальному искажению изображения в начале воспроизведения и сразу после поиска при воспроизведении некоторых файлов MPEG-TS.
Почему в некоторых файлах MPEG-TS отсутствуют субтитры?
Некоторые файлы MPEG-TS содержат дорожки CEA-608, но не объявляют их в метаданных контейнера, поэтому ExoPlayer не может их обнаружить. Вы можете вручную указать дорожки субтитров, предоставив DefaultExtractorsFactory
список ожидаемых форматов субтитров, включая каналы доступности, которые можно использовать для их идентификации в потоке MPEG-TS:
Котлин
val extractorsFactory = DefaultExtractorsFactory() .setTsSubtitleFormats( listOf( Format.Builder() .setSampleMimeType(MimeTypes.APPLICATION_CEA608) .setAccessibilityChannel(accessibilityChannel) // Set other subtitle format info, such as language. .build() ) ) val player: Player = ExoPlayer.Builder(context, DefaultMediaSourceFactory(context, extractorsFactory)).build()
Ява
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory() .setTsSubtitleFormats( ImmutableList.of( new Format.Builder() .setSampleMimeType(MimeTypes.APPLICATION_CEA608) .setAccessibilityChannel(accessibilityChannel) // Set other subtitle format info, such as language. .build())); Player player = new ExoPlayer.Builder(context, new DefaultMediaSourceFactory(context, extractorsFactory)) .build();
Почему некоторые файлы MP4/FMP4 воспроизводятся некорректно?
Некоторые файлы MP4/FMP4 содержат списки редактирования, которые переписывают временную шкалу медиафайлов, пропуская, перемещая или повторяя списки сэмплов. ExoPlayer частично поддерживает применение списков редактирования. Например, он может задерживать или повторять группы сэмплов, начинающихся с синхронизирующего сэмпла, но не обрезает аудиосэмплы и не добавляет преролл для сэмплов, которые не начинаются с синхронизирующего сэмпла.
Если вы видите, что часть медиафайла неожиданно отсутствует или повторяется, попробуйте установить Mp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS
или FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS
, что заставит экстрактор полностью игнорировать списки редактирования. Эти значения можно задать в DefaultExtractorsFactory
с помощью setMp4ExtractorFlags
или setFragmentedMp4ExtractorFlags
.
Почему некоторые потоки завершаются ошибкой с кодом ответа HTTP 301 или 302?
Оба кода ответа HTTP 301 и 302 указывают на перенаправление. Краткое описание можно найти в Википедии . Когда ExoPlayer отправляет запрос и получает ответ с кодом статуса 301 или 302, он обычно следует перенаправлению и начинает воспроизведение в обычном режиме. Единственным случаем, когда это не происходит по умолчанию, являются кросс-протокольные перенаправления. Кросс-протокольное перенаправление — это перенаправление с HTTPS на HTTP или наоборот (или, реже, между другой парой протоколов). Вы можете проверить, вызывает ли URL кросс-протокольное перенаправление, с помощью инструмента командной строки wget следующим образом:
wget "https://yourserver.example.com/test.mp3" 2>&1 | grep Location
Вывод должен выглядеть примерно так:
Location: https://secondserver.example.net/test.mp3 [following]
Location: http://thirdserver.example.org/test.mp3 [following]
В этом примере два перенаправления. Первое — с https://yourserver.example.com/test.mp3
на https://secondserver.example.net/test.mp3
. Оба перенаправления — HTTPS, поэтому это не кросс-протокольное перенаправление. Второе — с https://secondserver.example.net/test.mp3
на http://thirdserver.example.org/test.mp3
. Это перенаправление с HTTPS на HTTP и поэтому является кросс-протокольным перенаправлением. ExoPlayer не будет следовать этому перенаправлению в настройках по умолчанию, что означает, что воспроизведение не удастся.
При необходимости вы можете настроить ExoPlayer для отслеживания кросс-протокольных перенаправлений при создании экземпляров DefaultHttpDataSource.Factory
, используемых в вашем приложении. Подробнее о выборе и настройке сетевого стека можно узнать здесь .
Почему некоторые потоки завершаются ошибкой UnrecognizedInputFormatException?
Этот вопрос касается сбоев воспроизведения следующего вида:
UnrecognizedInputFormatException: None of the available extractors
(MatroskaExtractor, FragmentedMp4Extractor, ...) could read the stream.
Существует две возможные причины этой ошибки. Наиболее распространённая причина — попытка воспроизвести контент DASH (mpd), HLS (m3u8) или SmoothStreaming (ism, isml), но проигрыватель пытается воспроизвести его как прогрессивный поток. Для воспроизведения таких потоков необходимо использовать соответствующий модуль ExoPlayer . Если URI потока не заканчивается стандартным расширением файла, вы также можете передать MimeTypes.APPLICATION_MPD
, MimeTypes.APPLICATION_M3U8
или MimeTypes.APPLICATION_SS
в setMimeType
MediaItem.Builder
, чтобы явно указать тип потока.
Вторая, менее распространённая причина — ExoPlayer не поддерживает формат контейнера медиафайла, который вы пытаетесь воспроизвести. В этом случае ошибка работает как задумано, однако вы можете отправить запрос на добавление функции в наш баг-трекер , указав информацию о формате контейнера и тестовом потоке. Перед отправкой нового запроса найдите существующий запрос на добавление функции.
Почему setPlaybackParameters не работает должным образом на некоторых устройствах?
При запуске отладочной сборки приложения на Android M и более ранних версиях Android могут наблюдаться перебои в производительности, слышимые артефакты и высокая загрузка процессора при использовании API setPlaybackParameters
. Это связано с тем, что важная для этого API оптимизация отключена для отладочных сборок, работающих на этих версиях Android.
Важно отметить, что эта проблема затрагивает только отладочные сборки. Она не затрагивает релизные сборки, для которых оптимизация всегда включена. Следовательно, релизы, предоставляемые вами конечным пользователям, не должны быть затронуты этой проблемой.
Что означают ошибки «Доступ к проигрывателю осуществляется через неверный поток»?
См. заметку о потоках на странице начала работы.
Как исправить ошибку «Неожиданная строка статуса: ICY 200 OK»?
Эта проблема может возникнуть, если ответ сервера содержит строку статуса ICY, а не строку, совместимую с HTTP. Строки статуса ICY устарели и не должны использоваться, поэтому, если вы управляете сервером, вам следует обновить его для предоставления ответа, совместимого с HTTP. Если это невозможно, то использование библиотеки ExoPlayer OkHttp решит проблему, поскольку она корректно обрабатывает строки статуса ICY.
Как узнать, является ли воспроизводимая трансляция прямой трансляцией?
Вы можете запросить метод isCurrentWindowLive
проигрывателя. Кроме того, можно проверить isCurrentWindowDynamic
, чтобы узнать, является ли окно динамическим (то есть обновляется ли оно со временем).
Как сделать так, чтобы аудио воспроизводилось, когда приложение работает в фоновом режиме?
Чтобы обеспечить непрерывное воспроизведение звука, когда приложение работает в фоновом режиме, выполните следующие действия:
- Вам необходимо запустить службу переднего плана . Это не позволит системе завершить ваш процесс для освобождения ресурсов.
- Вам необходимо заблокировать
WifiLock
иWakeLock
. Они гарантируют, что система будет поддерживать Wi-Fi-модем и процессор в активном состоянии. Это легко сделать с помощьюExoPlayer
, вызвавsetWakeMode
, который автоматически заблокирует и снимет необходимые блокировки в нужное время.
Важно снять блокировки (если не используется setWakeMode
) и остановить службу, как только перестанет воспроизводиться звук.
Почему ExoPlayer поддерживает мой контент, а библиотека ExoPlayer Cast — нет?
Возможно, контент, который вы пытаетесь воспроизвести, не поддерживает CORS . Для воспроизведения фреймворка Cast требуется, чтобы контент поддерживал CORS.
Почему контент не воспроизводится, но ошибка не возникает?
Возможно, устройство, на котором вы воспроизводите контент, не поддерживает определённый формат медиа-сэмплов. Это можно легко проверить, добавив EventLogger
в качестве прослушивателя к вашему плееру и найдя в Logcat строку, похожую на эту:
[ ] Track:x, id=x, mimeType=mime/type, ... , supported=NO_UNSUPPORTED_TYPE
NO_UNSUPPORTED_TYPE
означает, что устройство не может декодировать формат медиа-образца, заданный параметром mimeType
. Информацию о поддерживаемых форматах медиа-образцов см. в документации по форматам медиа Android . Как загрузить библиотеку декодирования и использовать её для воспроизведения? Также может быть полезно.
Как мне загрузить библиотеку декодирования и использовать ее для воспроизведения?
- Большинство библиотек декодеров требуют ручной проверки и сборки зависимостей, поэтому убедитесь, что вы выполнили инструкции из файла README для соответствующей библиотеки. Например, для библиотеки ExoPlayer FFmpeg необходимо следовать инструкциям в файле libraries/decoder_ffmpeg/README.md , включая передачу флагов конфигурации для включения декодеров для любых форматов, которые вы хотите воспроизводить.
- Для библиотек с нативным кодом убедитесь, что вы используете правильную версию Android NDK, указанную в файле README, и обращайте внимание на любые ошибки, возникающие во время настройки и сборки. После выполнения инструкций, описанных в файле README, в подкаталоге
libs
пути к библиотеке для каждой поддерживаемой архитектуры должны появиться файлы.so
- Чтобы попробовать воспроизведение с использованием библиотеки в демонстрационном приложении , см. раздел «Включение встроенных декодеров» . Инструкции по использованию библиотеки в вашем приложении см. в файле README.
- Если вы используете
DefaultRenderersFactory
, при загрузке декодера в Logcat должна появиться строка журнала уровня информации, например «Loaded FfmpegAudioRenderer». Если её нет, убедитесь, что приложение зависит от библиотеки декодирования. - Если вы видите журналы уровня предупреждения от
LibraryLoader
в Logcat, это означает, что загрузка нативного компонента библиотеки не удалась. В этом случае проверьте, правильно ли вы выполнили шаги, описанные в файле README библиотеки, и не возникло ли ошибок при выполнении инструкций.
Если у вас всё ещё возникают проблемы с использованием библиотек декодирования, проверьте наличие недавних проблем в системе отслеживания проблем Media3. Если вам нужно сообщить о новой проблеме, связанной со сборкой нативной части библиотеки, приложите полный вывод командной строки, полученный в результате выполнения инструкций README, чтобы помочь нам диагностировать проблему.
Можно ли воспроизводить видео YouTube напрямую с помощью ExoPlayer?
Нет, ExoPlayer не может воспроизводить видео с YouTube, например, по URL-адресам вида https://www.youtube.com/watch?v=...
. Вместо этого следует использовать API YouTube IFrame Player , который является официальным способом воспроизведения видео YouTube на Android.
Воспроизведение видео прерывается
Устройство может не декодировать контент достаточно быстро, например, если битрейт или разрешение контента превышают его возможности. Для достижения хорошей производительности на таких устройствах может потребоваться использовать контент более низкого качества.
Если вы столкнулись с заиканием видео на устройстве под управлением Android версии от Android 6.0 (уровень API 23) до Android 11 (уровень API 30) включительно, особенно при воспроизведении контента с защитой DRM или высокой частотой кадров, вы можете попробовать включить асинхронную очередь буферов .
Ошибки нестабильного API-анализа
Media3 гарантирует двоичную совместимость для части API. Части, не гарантирующие двоичную совместимость, отмечены аннотацией @UnstableApi
. Чтобы подчеркнуть это различие, использование нестабильных символов API приводит к ошибке lint, если только они не аннотированы аннотацией @OptIn
.
Аннотация @UnstableApi
ничего не говорит о качестве или производительности API, а лишь о том, что он не «заморожен на уровне API».
У вас есть два варианта обработки нестабильных ошибок API lint:
- Перейдите на использование стабильного API, обеспечивающего тот же результат.
- Продолжайте использовать нестабильный API и аннотируйте использование с помощью
@OptIn
, как показано далее.
Добавьте аннотацию @OptIn
Android Studio может помочь вам добавить аннотацию:

Вы также можете вручную аннотировать определенные места использования в Kotlin:
import androidx.annotation.OptIn
import androidx.media3.common.util.UnstableApi
@OptIn(UnstableApi::class)
fun functionUsingUnstableApi() { ... }
А также на Java:
import androidx.annotation.OptIn;
import androidx.media3.common.util.UnstableApi;
@OptIn(markerClass = UnstableApi.class)
private void methodUsingUnstableApis() { ... }
Целые пакеты можно включить, добавив файл package-info.java
:
@OptIn(markerClass = UnstableApi.class)
package name.of.your.package;
import androidx.annotation.OptIn;
import androidx.media3.common.util.UnstableApi;
Целые проекты могут быть включены путем подавления конкретной ошибки lint в их файле lint.xml
:
<?xml version="1.0" encoding="utf-8"?>
<lint>
<issue id="UnsafeOptInUsageError">
<option name="opt-in" value="androidx.media3.common.util.UnstableApi" />
</issue>
</lint>
Также существует аннотация kotlin.OptIn
, которую не следует использовать. Важно использовать аннотацию androidx.annotation.OptIn
.