#android #encoding #codec #android-mediacodec #qualcomm
#Android #кодирование #кодек #android-mediacodec #qualcomm
Вопрос:
Я пытаюсь записать представления Android в виде растровых изображений и сохранить их в виде файла .mp4.
Я использую MediaCodec для кодирования растровых изображений и MediaMuxer для мультиплексирования их в .mp4.
Используя формат YUV420p color, я ожидаю, что входные буферы от MediaCodec будут иметь размер resWidth * resHeight * 1.5
, но Qualcomm OMX.qcom.video.encoder.avc
дает мне больше (независимо от того, какое разрешение я выберу). Я считаю, что он хочет, чтобы я сделал некоторое выравнивание в моем потоке входных байтов, но я понятия не имею, как узнать, что именно он ожидает от меня.
Это то, что я получаю, когда я плотно упаковываю свои данные во входные буферы на Nexus 7 (2013) с использованием кодека Qualcomm: https://www.youtube.com/watch?v=JqJD5R8DiC8
И это видео сделано тем же приложением, которое работает на Nexus 10 (кодек OMX.Exynos.AVC.Encoder
): https://www.youtube.com/watch?v=90RDXAibAZI
Похоже, что в неисправном видео с плоскостью яркости все в порядке, но то, что произошло с плоскостью цветности, для меня загадка.
Я подготовил минимальный (2 класса) пример рабочего кода, раскрывающий эту проблему: https://github.com/eeprojects/MediaCodecExample
Вы можете получить видео, показанные выше, просто запустив это приложение (будут такие же артефакты, если ваше устройство использует кодек Qualcomm).
Ответ №1:
Существует несколько способов хранения YUV 420 в буферах; вам необходимо проверить выбранный вами формат отдельных пикселей. MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar
и MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar
на практике одинаковы, называются planar или I420 для краткости, в то время как другие, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar
, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar
и MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar
называются полуплоскостными или NV12.
В semiplanar вам не нужно разделять плоскости для U и V, но у вас есть одна плоскость с парами чередующихся U, V.
См . https://android.googlesource.com/platform/cts/ /jb-mr2-release/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java (строки 925-949) для примера о том, как заполнить буфер для полуплоскостных форматов.
Комментарии:
1. Еще раз спасибо за вашу помощь. Что, если кодек все же поддерживает
CodecCapabilities.COLOR_FormatYUV420Flexible
? В документации говорится, что он может быть как плоским, так и полуплоскостным. Также не могли бы вы указать на некоторые другие ловушки, в которые я могу попасть, пытаясь обеспечить поддержку как можно большего количества кодеков?2. Если кодек поддерживает
CodecCapabilities.COLOR_FormatYUV420Flexible
и вы выбираете его, он позволяет кодеру внутренне выбирать любой формат, который он хочет (при условии, что его можно описать как гибкий формат YUV420). Если вы используете это, вам нужно использоватьMediaCodec.getInputImage
, чтобы получить описание буфера (вместо старогоgetInputBuffers()
илиgetInputBuffer()
). Затем у вас есть три прямыхByteBuffers
для каждой плоскости, а также общая строка и шаг пикселя, чтобы описать, как ее заполнить.3. Несмотря на то, что гибкий формат YUV 420 допускает действительно сумасшедшие форматы, я думаю, что на практике он все равно будет плоским и полуплоскостным, и они все равно будут отображаться в обычных пиксельных форматах. Так что, если вы заботитесь о поддержке старых версий, вы на самом деле мало что теряете, делая это так, как делаете (я до сих пор не видел устройства, которое не поддерживает ни плоский, ни полуплоскостный ввод, поскольку это то, что требует тест CTS!).
4. Таким образом, основное преимущество использования гибкого формата YUV заключается в том, что он абстрагирует эти различия — если у вас есть производитель контента, который может работать с
Image
классом, это, вероятно, проще. Теоретически он также может лучше работать для заполнения буферов необычных размеров (например, не кратных 16), хотя я не уверен, что это действительно подключено на практике — насколько я знаю, для этого нет теста CTS.