Android — Как эффективно масштабировать видеокадр с помощью NDK

Я делаю проект Android о работе с видеокадрами, мне нужно обработать каждый кадр, прежде чем отобразить его. Процесс включает масштабирование кадров с разрешения 1920×1080 до разрешения 2560×1440, преобразование цветового пространства и некоторую необходимую обработку изображений на основе RGB, и все эти работы должны быть завершены в течение 33 мс ~ 40 мс.

Я оптимизировал yuv-> rgb и другую обработку с помощью arm neon, они работали хорошо. Но мне нужно сначала масштабировать кадр с разрешения 1080p до 2k, теперь это узкое место в производительности.

Мой вопрос заключается в том, как эффективно масштабировать изображение с разрешения 1080p до 2k в течение 20 мс, у меня нет большого опыта работы с алгоритмом масштабирования, поэтому любые предложения полезны.
Могу ли я использовать arm neon для оптимизации существующего алгоритма?

Аппаратная среда:

  • Процессор: Samsung Exynos 5420
  • Память: 3 ГБ
  • Дисплей: 2560X1600 пикселей

Обновить:

Я опишу процесс декодирования, я использую MediaCodec для декодирования обычного видео (H.264) в YUV (NV12), декодер по умолчанию аппаратный, он очень быстрый. Затем я использую arm neon для конвертации NV12 в RGBW, а затем отправляю кадр RGBW на Surfaceflinger для отображения. Я просто использую обычный SurfaceView, а не GLSurfaceView.

Узким местом является быстрое увеличение YUV с 1080p до 2K.

4

Решение

Я считаю, что примеры работают хорошо, поэтому позвольте мне привести эту программу, которая использует шейдеры OpenGL для преобразования из YUV -> RGB: http://www.fourcc.org/source/YUV420P-OpenGL-GLSLang.c

Что я представляю для вашей программы:

  1. Аппаратное видео декодирует поток H.264 -> YUV массив
  2. Загрузить этот массив YUV как текстура в OpenGL; на самом деле вы загрузите 3 разные текстуры — Y, U и V
  3. Запустите фрагментный шейдер, который преобразует эти текстуры Y, U и V в изображение RGB (W); это создаст новую текстуру в видеопамяти
  4. Запустите новый фрагментный шейдер для текстуры, сгенерированной в предыдущем шаге, чтобы масштабировать изображение

Здесь может быть что-то вроде кривой обучения, но я думаю, что это выполнимо, учитывая описание вашей проблемы. Делайте это по одному шагу за раз: установите платформу OpenGL на место, попробуйте загрузить только текстуру Y и написать шейдер наивного фрагмента, который просто излучает пиксель в оттенках серого на основе образца Y, затем перейдите к правильному преобразованию изображения, а затем получите действительно наивный upsampler работает, а затем вводит в действие более сложный upsampler.

1

Другие решения

Я бы также порекомендовал opengles, в основном из-за проекта, над которым я сейчас работаю, а также воспроизведения видео. Для меня дисплей 1920 x 1080, поэтому я использую текстуру 2048 x 1024. Я получаю примерно 35 кадров в секунду на четырехъядерном плече7.

Используйте GLSurfaceView и свой собственный рендер. Если вы используете ffmpeg, то после декодирования видеокадров используйте sws_scale для масштабирования кадра, а затем просто загрузите его в текстуру opengl. Чем больше ваша текстура / дисплей, тем меньше кадров в секунду вы получите, поскольку загрузка каждого изображения в графический процессор занимает много времени.

В зависимости от ваших потребностей для декодирования вашего видеовхода вам придется исследовать. Для меня мне пришлось скомпилировать ffmpeg для Android и начать оттуда.

0

мои извинения за то, что поставили это в ответ. У меня недостаточно очков, чтобы комментировать.
Я хотел бы добавить, что вы можете столкнуться с ограничениями текстур OGL. Я пытался использовать OGL для противоположной проблемы; уменьшение масштаба с камеры в режиме реального времени. проблема в том, что максимальная текстура OGL составляет 2048×2048. Не уверен, что это верно для всех устройств. это ограничение было справедливо для новых комплектов, таких как N72013 и LG2. в конце концов, мне пришлось писать в NDK без OGL, оптимизируя его вручную.
удачи, хотя

0
По вопросам рекламы [email protected]