Преобразование специализированных видеокадров NV12 в RGB

У меня есть поток H264, декодированный с помощью Android MediaCodec. Когда я запрашиваю выходной MediaFormat, цветовой формат — 2141391875. Судя по всему, это специализированный вариант NV12, известный как HAL_PIXEL_FORMAT_NV12_ADRENO_TILED. Это на Nexus 7 (2013).

Я хочу взять эти данные и преобразовать их в RGB, чтобы создать растровое изображение. Я нашел сообщения StackOverflow для преобразования других форматов в RGB, а не в этот формат. Я пробовал код из этих других постов, результат - просто полосы цвета. (Чтобы просмотреть растровое изображение, я рисую на холсте, связанном с поверхностью, а также записываю его в формате JPEG — в обоих случаях он выглядит одинаково.)

Как я могу преобразовать эти конкретные данные в RGB?


person Paul Steckler    schedule 20.02.2015    source источник
comment
Пожалуйста, проверьте этот вопрос также: / . Один конвертер доступен на www.videolan.org/developers/vlc/modules/codec/omxil/qcom.c.   -  person Ganesh    schedule 21.02.2015


Ответы (1)


Десятичное число 2141391875 равно 0x7FA30C03 в шестнадцатеричном формате, что согласно этот заголовочный файл имеет номер OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka. Что означает то же самое, что и константа, которую вы нашли: это собственный цветовой формат Qualcomm.

Самый простой (и самый быстрый) способ преобразовать его — позволить OpenGL ES сделать всю работу за вас. См., например, ExtractMpegFramesTest, который декодирует видеокадры в SurfaceTexture, визуализирует текстуру на поверхности за пределами экрана. , а затем считывает пиксели с помощью glReadPixels(). Драйвер GLES выполнит преобразование RGB за вас.

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

person fadden    schedule 20.02.2015
comment
Код находится по адресу gitorious.org/atrix-aosp. /frameworks_base/source/ и git.videolan.org/?p=vlc.git;a=blob;f=modules/codec/omxil/qcom.c, которые показывают, как интерпретировать этот формат. - person mstorsjo; 21.02.2015
comment
В ExtractMpegFramesTest код настраивает кодек с поверхностью, полученной из OutputSurface. Затем, когда вы освобождаете выходной буфер, вы указываете true в качестве аргумента рендеринга. Но предположим, что я хочу использовать другой механизм рендеринга. Я настраиваю свой кодек без Surface, поэтому в выходном буфере у меня есть данные, полученные в результате декодирования ввода. Формат этих данных, по-видимому, зависит от аппаратного обеспечения. Я хотел бы отобразить эти данные на поверхности, но не передать их в MediaCodec::configure() или использовать какой-либо другой способ получения пикселей на экране. - person Paul Steckler; 24.02.2015
comment
Извините, я смотрел на EncodeDecodeTest, а не на ExtractMpegFramesTest, который вполне может делать то, что я хочу. - person Paul Steckler; 24.02.2015
comment
См. также Grafika (github.com/google/grafika), которая делает некоторые вещи с помощью камеры, например. youtube.com/watch?v=kH9kCP2T5Gg - person fadden; 24.02.2015
comment
В ExtractMpegFramesTest есть SurfaceTexture со связанной поверхностью, и код использует OpenGL ES для записи в SurfaceTexture. Такой подход дает возможность использовать glReadPixel и, в конечном итоге, сохранять кадр в файл изображения. Если все, что я хочу сделать, это отобразить кадр на экране, есть ли какое-либо преимущество OpenGL ES перед созданием поверхности в SurfaceView? Глядя на MediaCodec.java, похоже, что в этом случае он использует собственный код под названием SoftwareRenderer. - person Paul Steckler; 24.02.2015
comment
Внутреннее имя SurfaceTexture — GL Consumer. Поверхности — это очереди буферов с отношениями производитель-потребитель; SurfaceTexture — это экземпляр потребителя, который берет каждый графический буфер и преобразует его в текстуру GLES. Если вы собираетесь использовать SurfaceTexture, то GLES — наиболее естественный выбор для рендеринга. Для Surface не существует только программного потребителя буфера. Если все, что вы хотите сделать, это отобразить на экране, просто отправьте вывод декодера MediaCodec в SurfaceView или TextureView (см. примеры видеоплееров Grafika). Для более причудливых вещей см., например. текстура с камеры. - person fadden; 24.02.2015
comment
(См. source.android.com/devices/graphics/architecture.html для полная история) - person fadden; 24.02.2015
comment
Правильно, мой вопрос сводится к тому, есть ли разница в производительности (или другая) с использованием SurfaceTexture или Surface, доступного из SurfaceView, созданного с помощью макета. Я думаю, вы предполагаете, что нет. Спасибо, я прочитал эту прекрасную документацию. - person Paul Steckler; 25.02.2015
comment
MediaCodec к поверхности SurfaceView — наиболее эффективный путь — он должен быть без копирования. Для контента, защищенного DRM, это единственный возможный путь. MediaCodec в SurfaceTexture, а затем визуализация с помощью GLES на поверхности SurfaceView добавляет преобразование YUV в RGB и, возможно, блит-масштабирование, что делает его медленнее, но также обеспечивает гораздо большую гибкость в том, как визуализируется каждый кадр. Если все, что вы хотите сделать, это воспроизвести видео, вы должны отправить его прямо в SurfaceView. - person fadden; 25.02.2015