- Как устранить ошибки, связанные с запретом незашифрованного 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://), когда конфигурация Network Security Configuration не разрешает его. Если ваше приложение поддерживает Android 9 (уровень API 28) или более поздние версии, трафик HTTP в виде открытого текста будет отключен в конфигурации по умолчанию.
Если ваше приложение должно работать с незашифрованным трафиком HTTP, вам необходимо использовать конфигурацию Network Security, которая разрешает это. Подробная информация приведена в документации по сетевой безопасности Android. Чтобы разрешить весь незашифрованный HTTP-трафик, добавьте android:usesCleartextTraffic="true" в элемент application файла AndroidManifest.xml вашего приложения.
В демонстрационном приложении ExoPlayer используется конфигурация Network Security Configuration по умолчанию, поэтому незашифрованный 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 с переменным битрейтом – просканировать весь файл и вручную создать в проигрывателе сопоставление времени и байтов. Эту стратегию можно включить с помощью параметра 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 без единиц доступа или ключевых кадров 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:
Kotlin
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()
Java
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. Оба URL используют протокол 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 и более ранних версий при использовании API setPlaybackParameters могут наблюдаться проблемы с производительностью, звуковые артефакты и высокая загрузка процессора. Это связано с тем, что для отладочных сборок, работающих на этих версиях Android, отключена оптимизация, важная для этого API.
Важно отметить, что эта проблема затрагивает только отладочные сборки. Это не влияет на релизные сборки, для которых оптимизация всегда включена. Поэтому эта проблема не должна затронуть версии, которые вы предоставляете конечным пользователям.
Что означают ошибки "Доступ к проигрывателю осуществляется в неправильном потоке"?
См. примечание о потоках на странице "Начало работы".
Как устранить ошибку "Неожиданная строка статуса: 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 для нужной библиотеки. Например, для библиотеки FFmpeg ExoPlayer необходимо следовать инструкциям в файле libraries/decoder_ffmpeg/README.md, в том числе передавать флаги конфигурации, чтобы включить декодеры для всех форматов, которые вы хотите воспроизводить.
- Если в библиотеках есть собственный код, убедитесь, что вы используете правильную версию Android NDK, указанную в файле README, и следите за ошибками, которые могут возникнуть во время настройки и сборки. После выполнения инструкций из файла README в подкаталоге
libsпути к библиотеке для каждой поддерживаемой архитектуры должны появиться файлы.so. - Чтобы попробовать воспроизведение с помощью библиотеки в демонстрационном приложении, ознакомьтесь с информацией о том, как включить встроенные декодеры. Инструкции по использованию библиотеки в собственном приложении можно найти в файле README.
- Если вы используете
DefaultRenderersFactory, то при загрузке декодера в Logcat должна появиться строка журнала уровня info, например "Loaded FfmpegAudioRenderer" (Загружен FfmpegAudioRenderer). Если его нет, убедитесь, что приложение зависит от библиотеки декодирования. - Если в Logcat вы видите журналы уровня предупреждения от
LibraryLoader, это означает, что не удалось загрузить нативный компонент библиотеки. Если это произошло, проверьте, правильно ли вы выполнили инструкции из файла README библиотеки и не было ли ошибок при выполнении инструкций.
Если у вас по-прежнему возникают проблемы с использованием библиотек декодирования, проверьте инструмент отслеживания ошибок Media3 на наличие недавних проблем. Если вы хотите сообщить о новой проблеме, связанной с созданием нативной части библиотеки, приложите к запросу полный вывод командной строки, полученный при выполнении инструкций из файла README. Это поможет нам диагностировать проблему.
Можно ли воспроизводить видео YouTube напрямую с помощью ExoPlayer?
Нет, ExoPlayer не может воспроизводить видео с YouTube, например URL в формате https://www.youtube.com/watch?v=.... Вместо этого используйте YouTube IFrame Player API – официальный способ воспроизведения видео YouTube на устройствах Android.
Видео воспроизводится с перебоями
Устройство может не успевать декодировать контент, если, например, битрейт или разрешение контента превышают возможности устройства. На таких устройствах для хорошей работы может потребоваться контент более низкого качества.
Если на устройстве с Android 6.0 (уровень API 23) или более поздней версией ОС, вплоть до Android 11 (уровень API 30), при воспроизведении видео наблюдаются перебои, особенно при просмотре контента с технологиями DRM или высокой частотой кадров, попробуйте включить асинхронную постановку буферов в очередь.
Нестабильные ошибки линтера API
Media3 гарантирует бинарную совместимость для подмножества API. Части, которые не гарантируют совместимость исполняемых файлов, отмечены значком @UnstableApi. Чтобы сделать разницу между ними более очевидной, при использовании нестабильных символов API возникает ошибка линтера, если они не аннотированы с помощью @OptIn.
Аннотация @UnstableApi не означает, что API имеет определенное качество или эффективность, а лишь то, что он не заморожен.
Есть два способа устранить ошибки линтера, связанные с нестабильным API:
- Перейдите на использование стабильной версии 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:
Kotlin
// In your package-info.kt
@OptIn(UnstableApi::class)
package name.of.your.package
import androidx.annotation.OptIn
import androidx.media3.common.util.UnstableApi
Java
// In your package-info.java
@OptIn(markerClass = UnstableApi.class)
package name.of.your.package;
import androidx.annotation.OptIn;
import androidx.media3.common.util.UnstableApi;
Чтобы отключить проверку для всего проекта, подавите определенную ошибку в файле 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.