Устранение неполадок


Исправление ошибок «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. Дополнительную информацию см. в документации Android по SSL .

Почему некоторые медиафайлы недоступны для поиска?

По умолчанию ExoPlayer не поддерживает поиск на носителях, где единственным способом выполнения точных операций поиска является сканирование и индексирование проигрывателем всего файла. ExoPlayer считает такие файлы недоступными для поиска. Большинство современных форматов медиа-контейнеров включают метаданные для поиска (например, индекс образца), имеют четко определенный алгоритм поиска (например, интерполированный поиск пополам для Ogg) или указывают, что их содержимое имеет постоянный битрейт. В этих случаях возможны эффективные операции поиска, которые поддерживаются ExoPlayer.

Если вам требуется поиск, но у вас есть недоступные для поиска носители, мы предлагаем преобразовать ваш контент для использования более подходящего формата контейнера. Для файлов MP3, ADTS и AMR вы также можете включить поиск при условии, что файлы имеют постоянный битрейт, как описано здесь .

Почему поиск в некоторых файлах MP3 неточен?

Файлы MP3 с переменным битрейтом (VBR) принципиально не подходят для случаев использования, требующих точного поиска. Для этого есть две причины:

  1. Для точного поиска формат контейнера в идеале обеспечивает точное сопоставление времени с байтами в заголовке. Это сопоставление позволяет проигрывателю сопоставить запрошенное время поиска с соответствующим смещением байта и начать запрашивать, анализировать и воспроизводить медиафайлы с этого смещения. Заголовки, доступные для указания этого сопоставления в MP3 (например, заголовки XING), к сожалению, часто неточны.
  2. Для форматов контейнеров, которые не обеспечивают точного сопоставления времени с байтами (или вообще никакого сопоставления времени с байтами), все равно возможно выполнить точный поиск, если контейнер включает в поток абсолютные временные метки выборки. В этом случае проигрыватель может сопоставить время поиска с наилучшим предположением о соответствующем смещении байта, начать запрашивать медиафайлы с этого смещения, проанализировать временную метку первой абсолютной выборки и эффективно выполнять управляемый двоичный поиск в медиафайлах, пока не найдет правильный образец. . К сожалению, MP3 не включает в поток абсолютные временные метки выборки, поэтому такой подход невозможен.

По этим причинам единственный способ выполнить точный поиск в MP3-файле VBR — это просканировать весь файл и вручную создать сопоставление времени к байту в проигрывателе. Эту стратегию можно включить с помощью FLAG_ENABLE_INDEX_SEEKING , который можно установить в DefaultExtractorsFactory с помощью setMp3ExtractorFlags . Обратите внимание, что он плохо масштабируется для больших файлов MP3, особенно если пользователь пытается найти конец потока вскоре после начала воспроизведения, что требует, чтобы проигрыватель ждал, пока он загрузится и проиндексирует весь поток, прежде чем выполнять поиск. . В этом случае в ExoPlayer мы решили оптимизировать скорость, а не точность, поэтому FLAG_ENABLE_INDEX_SEEKING по умолчанию отключен.

Если вы контролируете воспроизводимый медиафайл, мы настоятельно рекомендуем вам использовать более подходящий формат контейнера, например MP4. Нам не известны случаи использования, в которых MP3 был бы лучшим выбором медиаформата.

Почему поиск в моем видео медленный?

Когда проигрыватель ищет новую позицию воспроизведения в видео, ему необходимо сделать две вещи:

  1. Загрузите данные, соответствующие новой позиции воспроизведения, в буфер (это может не потребоваться, если эти данные уже помещены в буфер).
  2. Очистите видеодекодер и начните декодирование с I-кадра (ключевого кадра) перед новой позицией воспроизведения из-за внутрикадрового кодирования , используемого большинством форматов сжатия видео. Чтобы гарантировать точность поиска (то есть воспроизведение начинается точно с позиции поиска), все кадры между предыдущим I-кадром и позицией поиска должны быть декодированы и немедленно отброшены (без отображения на экране).

Задержку, вызванную (1), можно уменьшить либо за счет увеличения объема данных, буферизуемых в памяти проигрывателя, либо за счет предварительного кэширования данных на диск .

Задержку, вызванную (2), можно уменьшить, уменьшив точность поиска с помощью ExoPlayer.setSeekParameters или перекодировав видео, чтобы иметь более частые I-кадры (что приведет к увеличению выходного файла).

Почему некоторые файлы MPEG-TS не воспроизводятся?

Некоторые файлы MPEG-TS не содержат разделителей единиц доступа (AUD). По умолчанию ExoPlayer использует AUD для дешевого определения границ кадра. Аналогично, некоторые файлы MPEG-TS не содержат ключевых кадров IDR. По умолчанию это единственный тип ключевых кадров, рассматриваемый ExoPlayer.

ExoPlayer будет зависать в состоянии буферизации, когда его попросят воспроизвести файл MPEG-TS, в котором отсутствуют ключевые кадры AUD или IDR. Если вам нужно воспроизвести такие файлы, вы можете сделать это, используя 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.com/test.mp3" 2>&1  | grep Location

Вывод должен выглядеть примерно так:

Location: https://second.com/test.mp3 [following]
Location: http://third.com/test.mp3 [following]

В этом примере есть два перенаправления. Первое перенаправление — с https://yourserver.com/test.mp3 на https://second.com/test.mp3 :// Second.com/test.mp3. Оба протокола HTTPS, поэтому это не межпротокольное перенаправление. Второе перенаправление — с https://second.com/test.mp3 на http://third.com/test.mp3 . Это перенаправление с HTTPS на HTTP и, следовательно, является межпротокольным перенаправлением. ExoPlayer не будет следовать этому перенаправлению в своей конфигурации по умолчанию, что означает, что воспроизведение не удастся.

При необходимости вы можете настроить ExoPlayer для отслеживания межпротокольных перенаправлений при создании экземпляров DefaultHttpDataSource.Factory , используемых в вашем приложении. Узнайте о выборе и настройке сетевого стека здесь .

Почему некоторые потоки завершаются с ошибкой UnrecouncedInputFormatException?

Этот вопрос касается сбоев воспроизведения следующего вида:

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 of MediaItem.Builder , чтобы явно указать тип потока.

Вторая, менее распространенная причина заключается в том, что ExoPlayer не поддерживает формат контейнера носителя, который вы пытаетесь воспроизвести. В этом случае сбой работает так, как задумано, однако вы можете отправить запрос на функцию в нашу систему отслеживания проблем , включая подробную информацию о формате контейнера и тестовом потоке. Пожалуйста, найдите существующий запрос на функцию, прежде чем отправлять новый.

Почему setPlaybackParameters не работает должным образом на некоторых устройствах?

При запуске отладочной сборки вашего приложения на Android M и более ранних версиях вы можете столкнуться с нестабильной производительностью, звуковыми артефактами и высокой загрузкой ЦП при использовании API setPlaybackParameters . Это связано с тем, что оптимизация, важная для этого API, отключена для отладочных сборок, работающих на этих версиях Android.

Важно отметить, что эта проблема затрагивает только отладочные сборки. Это не влияет на выпускные сборки, для которых оптимизация всегда включена. Следовательно, эта проблема не должна затрагивать выпуски, которые вы предоставляете конечным пользователям.

Что означают ошибки «Обращение к проигрывателю осуществляется не в том потоке»?

См. примечание о цепочках на странице начала работы.

Как исправить «Неожиданная строка состояния: ICY 200 OK»?

Эта проблема может возникнуть, если ответ сервера включает строку состояния ICY, а не строку, совместимую с HTTP. Строки состояния ICY устарели и не должны использоваться, поэтому, если вы управляете сервером, вам следует обновить его, чтобы обеспечить ответ, совместимый с HTTP. Если вы не можете это сделать, то использование библиотеки ExoPlayer OkHttp решит проблему, поскольку она способна правильно обрабатывать строки состояния ICY.

Как я могу узнать, является ли воспроизводимый поток прямой трансляцией?

Вы можете запросить метод isCurrentWindowLive игрока. Кроме того, вы можете проверить isCurrentWindowDynamic чтобы узнать, является ли окно динамическим (то есть обновляется ли оно с течением времени).

Как продолжить воспроизведение звука, когда мое приложение находится в фоновом режиме?

Выполните следующие действия, чтобы обеспечить непрерывное воспроизведение звука, когда ваше приложение находится в фоновом режиме:

  1. Вам необходимо иметь работающую службу переднего плана . Это не позволит системе убить ваш процесс для освобождения ресурсов.
  2. Вам необходимо удерживать 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 необходимо следовать инструкциям в библиотеках/decoder_ffmpeg/README.md , включая передачу флагов конфигурации для включения декодеров для любых форматов, которые вы хотите воспроизводить.
  • Для библиотек с собственным кодом убедитесь, что вы используете правильную версию Android NDK, указанную в README, и следите за ошибками, возникающими во время настройки и сборки. После выполнения шагов, описанных в README, вы должны увидеть, что файлы .so появляются в подкаталоге libs пути к библиотеке для каждой поддерживаемой архитектуры.
  • Чтобы опробовать воспроизведение с использованием библиотеки в демонстрационном приложении , см. раздел «Включение встроенных декодеров» . Инструкции по использованию библиотеки из вашего собственного приложения см. в README библиотеки.
  • Если вы используете DefaultRenderersFactory , вы должны увидеть строку журнала информационного уровня, например «Loaded FfmpegAudioRenderer» в Logcat при загрузке декодера. Если это отсутствует, убедитесь, что приложение зависит от библиотеки декодирования.
  • Если вы видите журналы уровня предупреждений из 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 генерирует ошибку ворса, если они не помечены @OptIn .

Аннотация @UnstableApi ничего не говорит о качестве или производительности API, а только тот факт, что он не «заморожен API».

У вас есть два варианта обработки нестабильных ошибок API:

  • Переключитесь на использование стабильного API, который дает тот же результат.
  • Продолжайте использовать нестабильный API и комментируйте его использование с помощью @OptIn , как показано ниже.
Добавьте аннотацию @OptIn

Android Studio может помочь вам добавить аннотацию:

Снимок экрана: Как добавить аннотацию Optin
Рис. 2. Добавление аннотации @androidx.annotations.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 .