Кодирование входного буфера для кодировщика Qualcomm AVC через Android MediaCodec

Я пытаюсь захватить представления Android в виде растровых изображений и сохранить их как файлы . mp4 файл.

Я использую MediaCodec для кодирования растровых изображений и MediaMuxer, чтобы мультиплексировать их в .mp4.

Используя цветовой формат YUV420p, я ожидаю, что входные буферы от 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).


person Android developer    schedule 10.10.2016    source источник


Ответы (1)


Есть несколько способов хранения YUV 420 в буферах; вам необходимо проверить выбранный вами формат отдельного пикселя. MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar и MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar на практике одинаковы и называются планарными или I420 для краткости, в то время как другие, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar и MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar, называются полуплоскими или NV12.

В полуплоскости вам не нужно разделять плоскости для U и V, но у вас есть одна единственная плоскость с парами чередующихся U, V.

См. https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java (строки 925-949 ) для примера заполнения буфера для полупланарных форматов.

person mstorsjo    schedule 10.10.2016
comment
Спасибо за вашу помощь еще раз. Что, если кодек поддерживает CodecCapabilities.COLOR_FormatYUV420Flexible? В документации сказано, что он может быть как плоским, так и полуплоским. Также не могли бы вы указать на некоторые другие ловушки, в которые я могу попасть, пытаясь обеспечить поддержку как можно большего количества кодеков? - person Android developer; 11.10.2016
comment
Если кодек поддерживает CodecCapabilities.COLOR_FormatYUV420Flexible и вы выбираете его, он позволяет кодировщику внутренне выбирать любой формат, который он хочет (при условии, что его можно описать как гибкий формат YUV420). Если вы используете это, вам нужно использовать MediaCodec.getInputImage, чтобы получить описание буфера (вместо старых getInputBuffers() или getInputBuffer()). Затем у вас есть три прямых ByteBuffers для каждой плоскости, а также общая строка и шаг пикселя, чтобы описать, как ее заполнить. - person mstorsjo; 11.10.2016
comment
Несмотря на то, что гибкий формат YUV 420 позволяет использовать действительно сумасшедшие форматы, я думаю, что на практике он все равно будет плоским и полуплоским, и они все равно будут отображаться через обычные пиксельные форматы. Так что, если вы заботитесь о поддержке более старых версий, вы на самом деле не много теряете, делая это так, как делаете (я до сих пор не видел устройства, которое не поддерживает планарный или полупланарный ввод, так как это то, что тест CTS тоже требует!). - person mstorsjo; 11.10.2016
comment
Таким образом, основное преимущество использования гибкого формата YUV заключается в том, что он абстрагируется от этих различий — если у вас есть производитель контента, который может работать с классом Image, это, вероятно, проще. Теоретически он также может работать лучше для заполнения буферов с необычными размерами (например, не кратными 16), хотя я не уверен, действительно ли это связано на практике - насколько я знаю, для него нет теста CTS. - person mstorsjo; 11.10.2016