WebRTC на Android: как включить аппаратное кодирование на нескольких устройствах

Для видеозвонков в приложениях Badoo и Bumble мы используем WebRTC с кодеком H.264. Опираясь на соответствующую документацию, можно подумать, что этот кодек должен без проблем работать на любом устройстве Android, начиная с Android 5.0. Однако на практике все пошло не так. В этой статье рассматриваются особенности реализации аппаратного кодирования кодека H.264 в WebRTC и способы его включения на нескольких устройствах.

Почему H.264?

При подключении через WebRTC все устройства, участвующие в сеансе, передают разные параметры связи, в том числе видео- и аудиокодеки. Если устройство поддерживает несколько кодеков (например, VP8 и H.264), сначала перечислены кодеки с наивысшим приоритетом для платформы. Эти кодеки используются на этапе согласования в WebRTC, после которого остаются только кодеки, поддерживаемые всеми устройствами. См. Подробный пример таких данных в этом документе.

Для видеозвонков, если одно из устройств не поддерживает кодек H.264, то оба устройства могут переключиться, например, на кодек VP8, что не зависит от аппаратной реализации устройства. Однако наше приложение работает на разных устройствах, в том числе на смартфонах предыдущих поколений. Вот почему мы хотели использовать аппаратное кодирование для видеосвязи, где это возможно, потому что оно снижает нагрузку на процессор и потребляет меньше энергии батареи, что важно для устаревших устройств. Также на многих устройствах поддерживается аппаратное кодирование H.264, в отличие от упомянутого выше VP8.

Поддержка H.264 на Android

Согласно описанию поддержки мультимедийных форматов, декодирование H.264 Baseline Profile должно работать на всех устройствах Android, а кодирование должно работать на устройствах начиная с Android 3.0. Badoo и Bumble поддерживают устройства, начиная с Android 5.0. Таким образом, мы не должны были столкнуться с какими-либо проблемами. Но оказалось, что все не так просто, потому что мы обнаружили множество особенностей в устройствах, даже с версией 5.x.

В чем может быть причина?

Как известно, при разработке нового Android-устройства любой производитель должен пройти Набор для тестирования совместимости. Он работает на ПК, подключенном к устройству, и результаты необходимо отправить в Google для подтверждения того, что устройство соответствует требованиям ОС Android. Только после этого устройство можно будет запустить на рынок.

Что касается этого набора, нас интересуют мультимедийные тесты, а точнее тесты кодирования и декодирования видео. Я выбрал EncodeDecodeTest, MediaCodecTest, DecoderTest и EncoderTest, поскольку они включены во все версии Android, начиная с 4.3. Счетчик SLOC в этих тестах выглядит следующим образом:

До версии 4.3 большинство этих тестов просто не существовало, а для версий 5 и 7 их количество значительно выросло. По этой причине можно с уверенностью сказать, что до Android 4.3 Google не проверял соответствие устройств своей собственной спецификации кодирования и декодирования видео, а только приступил к реализации этой проверки версии 5.0.

Тогда можно было бы подумать, что с 5.0 все должно было быть в порядке с кодированием. Однако в свете моего предыдущего опыта декодирования потокового видео на Android это было не так. Количество тем по кодировке, перечисленных в группе Google обсуждение-webrtc, было достаточным доказательством.

В поисках скрытых ловушек мы использовали открытый код WebRTC. Давайте посмотрим на это поближе.

Поддержка H.264 в WebRTC

Начнем с HardwareVideoEncoderFactory.

Здесь мы видим метод с понятным именем isHardwareSupportedInCurrentSdkH264:

Как видим, поддержка аппаратного кодирования на Android включена только для чипсетов Qualcomm и Exynos. Так почему же стандартная реализация WebRTC не поддерживает другие наборы микросхем? Скорее всего, это можно объяснить особенностями реализации аппаратных кодеков разных производителей. Эти особенности часто можно выявить только на этапе производства, так как не всегда удается найти конкретное устройство.

Все описания кодеков хранятся в файле media_codecs.xml. Например, вот этот файл для Pixel XL и HUAWEI P8 lite. При получении списка кодеков с помощью метода getCodecInfos () объекта MediaCodecList этот файл анализируется, и возвращаются сохраненные в нем кодеки. Этот процесс и точность заполнения этого файла производителем покрываются в CTS с помощью MediaCodecListTest, количество SLOC которого увеличилось со 160 в Android 4.3 до 740 в Android 10.

В Badoo мы изменили код метода isHardwareSupportedInCurrentSdkH264 и заменили разрешенный список кодеков на блок-лист префиксов программных кодеков, перечисленных в WebRTC:

static final String[] SOFTWARE_IMPLEMENTATION_PREFIXES = {“OMX.google.”, “OMX.SEC.”};

Но нельзя просто реализовать поддержку всех кодеков без учета особенностей производства. Из названий тем из Discussion-webrtc, посвященных аппаратному кодированию на Android, очевидно, что что-то обязательно пойдет не так. В большинстве случаев ошибки возникают на этапе настройки кодека.

Параметры конфигурации кодека

Инициализация кодека для кодирования выглядит следующим образом:

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

  • DynamicBitrateAdjuster - регулирует битрейт в зависимости от объема данных.
  • FramerateBitrateAdjuster - регулирует битрейт в соответствии с частотой кадров.

Таким образом, нам нужно выбрать разные способы настройки битрейта для каждого кодека. Рассмотрим подробнее особенности настройки параметров инициализации аппаратных кодеков.

Разрешение потока

После получения объекта MediaCodecInfo для каждого кодека мы можем более подробно изучить кодек, получив информацию о его возможностях в классе CodecCapabilities. Таким образом, мы можем узнать, поддерживает ли этот кодек выбранное разрешение и частоту кадров или нет. Если он поддерживает эти параметры, их можно смело устанавливать.

Однако в некоторых случаях это правило не действует. Мы обнаружили, что кодеки с «OMX.MARVELL». префиксы были закодированы неправильно, что в некоторых случаях приводило к появлению зеленых полос по краям экрана, когда разрешение потока отличалось от 4: 3, а сам кодек утверждал, что выбранное разрешение и частота кадров поддерживаются.

Режим битрейта

Стандартный режим для всех видеокодеков - постоянный битрейт. Однако однажды нам пришлось использовать переменный битрейт:

format.setInteger(MediaFormat.KEY_BITRATE_MODE, VIDEO_ControlRateVariable);

Это произошло на устройстве Lenovo A1000 с набором микросхем от Spreadtrum (теперь известный как Unisoc), начинающимся с OMX.sprd. Поиск в Интернете привел нас к посту шестилетней давности о Firefox OS, в котором были описаны как проблема, так и ее решение.

Цветовой формат

При использовании кодека в режиме байтового буфера необходимо выбрать правильный формат. Обычно это выполняется с помощью следующей функции:

Грубо говоря, мы всегда должны выбирать первый из поддерживаемых цветовых форматов.

Однако для кодеков HUAWEI, начинающихся с OMX.IMG.TOPAZ., OMX.hisi. и OMX.k3. префиксов не получилось. После долгих поисков мы нашли решение: независимо от формата, возвращаемого этими кодеками, следует использовать формат COLOR_FormatYUV420SemiPlanar. Разобраться в этом нам помогла ветка на одном китайском форуме.

Регулировка битрейта

Стандартный код WebRTC содержит следующее:

Как видно из этого кода, регулировка битрейта отключена для всех наборов микросхем, кроме Exynos. Однако это относится только к Qualcomm, поскольку стандартный код поддерживает только Exynos и Qualcomm. После некоторого экспериментирования с различными значениями этого параметра и выполнения некоторых поисков в Интернете мы обнаружили, что его также следует включить для кодеков с «OMX.MTK». префиксы. Кроме того, это должно быть сделано для кодеков HUAWEI с «OMX.IMG.TOPAZ.», «OMX.hisi.» и «OMX.k3.» префиксы. Причина этого связана с тем фактом, что эти кодеки не используют временные метки кадра для регулировки битрейта, поскольку они предполагают, что все кадры прибывают с той же скоростью, которая была изначально установлена ​​во время настройки кодека.

В заключение рассмотрим полученный нами список кодировщиков для Android 5.0 и 5.1. Они были для нас интересны в первую очередь потому, что в более поздних версиях Android дела идут лучше, а количество нетипичных кодеков сокращается.

Это показано на графике ниже. Чтобы более отчетливо показать редкие случаи, используется логарифмическая шкала.

Как мы видим, большинство устройств имеют наборы микросхем Spreadtrum, MediaTek, HUAWEI и MARVELL, и именно поэтому наши изменения помогли включить аппаратное кодирование на этих устройствах.

Заключение

Хотя мы и предсказывали, что на некоторых устройствах будут проблемы при работе с H.264, Android снова нас удивил. Как видно из нашей пользовательской статистики, все еще используется множество устройств, произведенных в период с 2014 по 2016 год, которые они либо не могут, либо не могут обновить. Хотя ситуация с обновлениями ОС для новых устройств Android сейчас намного лучше, чем несколько лет назад, процент устройств предыдущего поколения, которые все еще используются, довольно медленно снижается, поэтому нам явно придется поддерживать их на долгое время впереди.

В настоящее время WebRTC активно развивается Google, так как он используется в проекте Stadia (вот подробное видео об этом). По этой причине он будет продолжать улучшаться и, скорее всего, станет стандартом для реализации видеозвонков. Надеюсь, эта статья поможет вам разобраться в специфике работы с H.264 и WebRTC и что эти знания пригодятся в ваших собственных проектах.