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

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

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

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

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

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

Обновление:

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

Узким местом является то, как быстро масштабировать YUV с 1080p до 2K.


person NicotIne    schedule 15.06.2014    source источник
comment
Зачем вам нужно масштабироваться?   -  person Alex Cohn    schedule 15.06.2014
comment
@AlexCohn Это требование, и мне нужно иметь дело со специальным типом RGB (Pentile RGBW), который не распознается SurfaceFlinger, поэтому мне нужно сначала увеличить кадр и обработать каждый пиксель 2560x1600, а затем опубликовать кадр для отображения. Если я позволю Surfaceflinger увеличить масштаб, он потеряет часть информации. У вас есть какие-нибудь идеи по этому вопросу?   -  person NicotIne    schedule 16.06.2014
comment
Я считаю, что аппаратный преобразователь/масштабатор цвета будет выполнять свою работу намного быстрее и, вероятно, лучше, чем центральный процессор.   -  person Alex Cohn    schedule 16.06.2014
comment
Большое спасибо @AlexCohn, я пытаюсь найти аппаратное решение для этого. Я мог бы убедиться, что аппаратный композитор Android использует аппаратное обеспечение для масштабирования, но я не уверен, что мы могли бы сделать то же самое в Application.   -  person NicotIne    schedule 18.06.2014
comment
может быть, вы можете использовать OpenGL?   -  person Alex Cohn    schedule 18.06.2014
comment
Вы знакомы с OpenGL и программированием шейдеров? Это звучит как хорошая проблема для параллельного оборудования GPU. Дайте мне знать, если вы хотите пойти по этому пути, потому что это звучит интересно.   -  person Multimedia Mike    schedule 21.06.2014
comment
@AlexCohn Я не знаком с OpenGL --!, мне нужно погуглить некоторые документы.   -  person NicotIne    schedule 21.06.2014
comment
@MultimediaMike Я не совсем знаком с OpenGL и шейдером, думаю, с этого момента мне следует начать OpenGL и шейдер. У тебя есть какой-нибудь совет? Большое спасибо, ребята, ваши советы очень полезны для меня.   -  person NicotIne    schedule 21.06.2014
comment
Возможно, вы могли бы отредактировать вопрос, чтобы немного больше описать конвейер. Это мое первое знакомство с цветовым пространством RGBW (хотя я читаю об этом). Получаете ли вы обычное видео (например, H.264) и кадры в виде необработанного YUV, затем конвертируете YUV -> RGBW, затем масштабируете RGBW и затем выполняете блитирование? Или декодированное видео несет часть информации RGBW? Как декодируется видео? Программно или аппаратно?   -  person Multimedia Mike    schedule 22.06.2014
comment
@MultimediaMike Привет, Майк, я обновил вопрос, и у меня есть вопрос о RGBW, знаете ли вы, как добавить насыщенность при преобразовании yuv в rgbw? Или я должен добавить насыщенность на основе rgb? Я обнаружил, что rgbw теряет некоторую насыщенность после преобразования из NV12.   -  person NicotIne    schedule 25.06.2014


Ответы (3)


Я считаю, что примеры работают хорошо, поэтому позвольте мне привести этот пример программы, которая использует шейдеры 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, затем переходите к правильному преобразованию изображения, затем получайте действительно наивный апсемплер работает, а затем задействовать более сложный апсемплер.

person Multimedia Mike    schedule 25.06.2014

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

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

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

person WLGfx    schedule 23.06.2014
comment
На самом деле я протестировал метод sws_scale в ffmepg, для меня он немного медленный. Результат теста около 40мс на кадр от 1080р до 2К, так что думаю лучше если будет какое-то аппаратное решение. - person NicotIne; 25.06.2014
comment
Ага, отхожу от sws_scale для следующего обновления проекта. Я в основном конвертирую декодированный кадр в rgba и использую UV, чтобы обрезать текстуру для отображения. GL может выполнять аппаратное масштабирование при его отображении. Кадр 720x576 просто использует текстуру 1024x1024 и требует только одну загрузку на кадр. Вероятно, вы мало что можете сделать с фильтрацией, кроме опций, которые дает вам GL, но этого должно быть достаточно. Единственная проблема, которая у меня есть на данный момент, - это необходимость деинтерлейсинга каждого кадра, поэтому я ищу gsll, чтобы сделать это за меня. - person WLGfx; 29.06.2014

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

person jkj yuio    schedule 17.07.2014