Привет, мир!

этот пост не является руководством по использованию MediaCodec для кодирования / декодирования, вместо этого это контрольный список вещей, на которые следует обратить внимание, когда качество видео резко ухудшается после кодирования / декодирования без каких-либо четких объяснений.

Основы

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

Что такое кодирование?

Кодирование - это процесс преобразования заданного файла видео (нескольких изображений) в двоичный.

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

Текущий стандартный алгоритм кодирования видео - H.264 или MPEG-4 Part 10. Однако появился новый менее поддерживаемый стандарт под названием Высокоэффективное кодирование видео (HEVC), также известный как H.265 и MPEG-H Part 2.

HEVC предлагает от 25% до 50% лучшее сжатие данных при том же уровне качества видео или существенно улучшенное качество видео при том же битрейте.

https://en.wikipedia.org/wiki/High_Efficiency_Video_Coding

Что такое декодирование?

Это в основном противоположность кодировщика. Он «декодирует» закодированные видео с помощью кодеков. Он воссоздает видео из двоичного формата - он берет сжатый видеофайл и выводит воспроизводимый контейнер (.MOV, .FLV, .MP4, .OGG, .WMV, WebM), который может воспроизводиться видеопроигрывателями.

Хорошо, но что такое кодек?

Кодек расшифровывается как Co der / Dec oder. Видеокодек - это аппаратное устройство или какое-либо программное обеспечение, которое выполняет сжатие и распаковку видеофайлов.

Кодеки определяют размер видео, скорость, качество и многое другое.

Контрольный список

Итак, теперь, когда мы разобрались с основами, давайте перейдем к контрольному списку качества видео на Android (порядок не имеет значения).

1. Проверьте битрейт

Битрейт видео - это количество данных в битах, которые обрабатываются / сжимаются в секунду. Обычно от этого зависит размер и качество видео. Чем выше битрейт, тем лучше качество, но при этом увеличивается и размер файла.

Причина, по которой битрейт влияет на размер файла, заключается в том, что размер файла определяется как (килобит в секунду) x продолжительность. 1 байт в секунду соответствует 8 бит / с.

Битрейт устанавливается при создании MediaFormat для кодировщика, который выглядит примерно так:

MediaFormat.createVideoFormat(mimeType, width, height).apply {
    setInteger(MediaFormat.KEY_BIT_RATE, bitRate) 
    // .. some other configs
}

2. Проверьте частоту кадров и интервал I-кадров (или внутрикадрового).

Частота кадров - это скорость отображения изображений в видео. Например, видели ли вы или видели когда-нибудь, как кто-то рисует картинки в правом нижнем углу записной книжки и листает страницы, создавая своего рода анимированное изображение? Частота кадров будет зависеть от того, насколько быстро эти страницы переворачиваются.

Интервал I-кадра настраивает количество неполных кадров (P-кадров), которые встречаются между полными кадрами (I-кадры) в видеопотоке. Например, в сцене, где открывается дверь и через нее проходит человек, видеокодер сохраняет только движения двери и человека. Стационарный фон, который встречается в предыдущих частичных кадрах, не кодируется, потому что в этой части сцены не произошло никаких изменений. Стационарный фон кодируется только в полных кадрах. Частичные кадры улучшают степень сжатия видео за счет уменьшения размера видео. По мере увеличения интервала I-кадра количество неполных кадров увеличивается между полными кадрами. Более высокие значения рекомендуются только в сетях с высокой надежностью.

https://support.pelco.com/s/article/Definition-of-the-I-Frame-Interval-1538586573328

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

MediaFormat.createVideoFormat(mimeType, width, height).apply {
    // On LOLLIPOP, media format must not contain a KEY_FRAME_RATE. 
    if (Build.VERSION.SDK_INT != Build.VERSION_CODES.LOLLIPOP) {
        setInteger(MediaFormat.KEY_FRAME_RATE, frameRate)
    }

    setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iFrameRateInterval)
}

На Build.VERSION_CODES.LOLLIPOP format не должен содержать MediaFormat # KEY_FRAME_RATE. Используйте format.setString(MediaFormat.KEY_FRAME_RATE, null), чтобы удалить все существующие настройки частоты кадров в формате.

https://developer.android.com/reference/android/media/MediaCodecInfo.CodecCapabilities.html#isFormatSupported(android.media.MediaFormat)

Комбинация частоты кадров и интервала i-кадра определяет, как часто I-кадры (также называемые кадрами синхронизации) появляются в закодированном выводе. Кодировщик MediaCodec не пропускает кадры. Если вы хотите уменьшить частоту кадров, вам придется сделать это вручную, отправив на него меньшее количество кадров. Для получения дополнительной информации см. Этот пост на StackOverflow.

3. Убедитесь, что используемый кодировщик имеет аппаратное ускорение.

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

Как проверить, аппаратно ли ускорен кодек?

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

private fun isCodecHardwareAccelerated(codec: MediaCodec): Boolean {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        codec.codecInfo.isHardwareAccelerated
    } else {
        if (codec.name.startsWith("OMX.google.")) {
            // This is a software codec false
            false
        } else {
            // it is a hardware codec true
            true
        }
    }
}

4. Проверить профиль / уровень.

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

TL;DR

Стандарт определяет несколько наборов возможностей, которые называются профилями , ориентированными на определенные классы приложений. Они объявляются с использованием кода профиля (profile_idc) и иногда набора дополнительных ограничений, применяемых в кодировщике. Код профиля и указанные ограничения позволяют декодеру распознавать требования для декодирования этого конкретного битового потока. (И во многих системных средах разрешено использовать только один или два профиля, поэтому декодерам в этих средах не нужно заботиться о распознавании менее часто используемых профилей.) Безусловно, наиболее часто используемым профилем является High Profile.

Уровни профиля ;:

Поскольку этот термин используется в стандарте, « level » - это определенный набор ограничений, которые указывают степень требуемой производительности декодера для профиля. Например, уровень поддержки в профиле определяет максимальное разрешение изображения, частоту кадров и скорость передачи данных, которые может использовать декодер. Декодер, соответствующий данному уровню, должен иметь возможность декодировать все потоки битов, закодированные для этого уровня и всех более низких уровней.

Так, например, все устройства должны поддерживать профили SD (стандартного разрешения). Это означает, что все устройства ДОЛЖНЫ поддерживать кодирование / декодирование как минимум 320 X 240 px с частотой кадров 20 fps и битрейтом 384 Кбит / с. Для получения дополнительной информации см. Таблицу для H.264 ниже.

Согласно документации по совместимости исходного кода Android, все устройства, поддерживающие H.264, ДОЛЖНЫ поддерживать базовый профиль уровня 3 и должны поддерживать профили кодирования SD. Подробнее об этих стандартах профиля см. Здесь.

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

Дополнительно

Получение всех доступных кодировщиков и декодеров

Чтобы получить все кодеки, которые «подходят для обычного (из буфера) декодирования или кодирования», просто выполните следующие действия:

val mediaCodecList = MediaCodecList(MediaCodecList.REGULAR_CODECS)

ПРИМЕЧАНИЕ. Это кодеки, которые возвращаются до API 21 с использованием устаревших статических методов ».

Получить все кодеки, даже те, которые не подходят для обычного (из буфера) декодирования или кодирования. К ним относятся, например, кодеки, которые работают только со специальными входными или выходными поверхностями, такие как кодеки только для защищенных или туннелируемых кодеков.

Просто сделайте:

val mediaCodecList = MediaCodecList(MediaCodecList.ALL_CODECS)

Я настоятельно рекомендую просто использовать MediaCodecList.REGULAR_CODECS, так как это гарантировано, что они будут работать почти во всех сценариях.

Чтобы проверить, является ли кодек кодировщиком или декодером, вы можете просто сделать:

MediaCodecList(MediaCodecList.REGULAR_CODECS).codecInfos.forEach { 
    if (it.isEncoder) {
        // encoder ;)
    } else {
        // decoder
    }
}

Получить поддерживаемые размеры

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

Есть способы проверить, поддерживается ли нужный нам размер.

Например, если мы хотим получить всю поддерживаемую ширину для определенной высоты, мы можем сделать:

val capabilities = encoder.codecInfo.getCapabilitiesForType(mime)
capabilities.videoCapabilities.getSupportedWidthsFor(height)

Я настоятельно рекомендую заглянуть ЗДЕСЬ, чтобы узнать больше о том, что можно проверить.

Заключение

Мир кодирования / декодирования мультимедиа не так прост, и для получения желаемого результата требуется комбинация нескольких различных конфигураций, я надеюсь, что этот контрольный список обеспечивает достойную отправную точку, где искать, если есть сомнения, и дает вам немного больше понимание.

До следующего раза, оставайся морозным!

Первоначально опубликовано на https://josiassena.com 6 апреля 2020 г.