текстура для преобразования YUV420 в RGB в OpenGL ES

Я должен конвертировать и отображать изображения YUV420P в цветовое пространство RGB с помощью AMD GPU на процессоре Freescale iMX53 (OpenGL ES 2.0, EGL). ОС Linux, нет X11. Для этого я должен иметь возможность создать соответствующее изображение, содержащее данные YUV420P: это может быть либо тип изображения YUV420P/YV12, либо 3 простых 8-битных изображения, по одному для каждого компонента (Y, U, V).

glTexImage2D исключен, потому что он медленный, кадры YUV420P являются результатами декодирования видео в реальном времени @25FPS и с glTexImage2D мы не можем сохранить желаемую частоту кадров.

есть альтернатива: eglCreateImageKHR/glEGLImageTargetTexture2DOES. Единственная проблема заключается в том, что они не могут обрабатывать любой формат изображения, который подходит для данных YUV420/YV12.

EGLint attribs[] = {
  EGL_WIDTH, 800,
  EGL_HEIGHT, 480,
  EGL_IMAGE_FORMAT_FSL, EGL_FORMAT_YUV_YV12_FSL,
  EGL_NONE
};

EGLint const req_attribs[] = {
  EGL_RED_SIZE, 5,
  EGL_GREEN_SIZE, 6,
  EGL_BLUE_SIZE, 5,
  EGL_ALPHA_SIZE, 0,
  EGL_SAMPLES, 0,
  EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
  EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
  EGL_NONE
};

...

display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, NULL, NULL);
eglBindAPI(EGL_OPENGL_ES_API);
eglChooseConfig(display, req_attribs, config, ARRAY_SIZE(config), &num_configs);
ctx = eglCreateContext(display, curr_config, NULL, NULL);
surface = eglCreateWindowSurface(display, curr_config, fb_handle, NULL);

...

EGLImageKHR yuv_img = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NEW_IMAGE_FSL, NULL, attribs); 
eglQueryImageFSL(display, yuv_img, EGL_CLIENTBUFFER_TYPE_FSL, (EGLint *)&ptr);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, yuv_img);

glEGLImageTargetTexture2DOES(...) неудачи. Если я изменю соответствующую строку в "атрибутах" на это:

EGL_IMAGE_FORMAT_FSL, EGL_FORMAT_RGB_565_FSL,

тогда изображение может быть назначено Текстура OpenGL ES, но не подходит для хранения 8-битных данных (Y/U/V) или данных YUV420/YV12. Поиск в сети (включая Форум сообщества Freescale) я не нашел никакого решения для этого.

Как я могу создать образ, который:

  • быстро создать;
  • в конечном итоге может быть назначен уже существующему буферу (указан физический адрес или виртуальный адрес);
  • может использоваться в программе шейдеров фрагментов / вершин для выполнения YUV -- > преобразование RGB;

ограничение состоит в том, чтобы избежать ненужного memcpy(...) s по причинам производительности.

1 ответов


я реализовал это на i.MX53 для нескольких форматов YUV, и он работает очень хорошо. У меня есть опубликованная статья об этом, хотя она была обобщена, чтобы охватить больше платформ Android:

http://software.intel.com/en-us/articles/using-opengl-es-to-accelerate-apps-with-legacy-2d-guis

Я подозреваю, что ваша проблема заключается в том, что вы не привязка к нужной текстуры. Должно быть так:

glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, hEglImage[iTextureIndex]);

glBindTexture(GL_TEXTURE_EXTERNAL_OES, hTexture[iIndex]);   

и eglImageAttributes должен быть одним из следующих:

EGLint eglImageAttributes[] = {EGL_WIDTH, iTextureWidth, EGL_HEIGHT, iTextureHeight, EGL_IMAGE_FORMAT_FSL, EGL_FORMAT_YUV_YV12_FSL, EGL_NONE};
EGLint eglImageAttributes[] = {EGL_WIDTH, iTextureWidth, EGL_HEIGHT, iTextureHeight, EGL_IMAGE_FORMAT_FSL, EGL_FORMAT_YUV_NV21_FSL, EGL_NONE};
EGLint eglImageAttributes[] = {EGL_WIDTH, iTextureWidth, EGL_HEIGHT, iTextureHeight, EGL_IMAGE_FORMAT_FSL, EGL_FORMAT_YUV_UYVY_FSL, EGL_NONE};

hEglImage[iTextureIndex] = eglCreateImageKHR(eglDisplay, EGL_NO_CONTEXT, EGL_NEW_IMAGE_FSL, NULL, eglImageAttributes);

struct EGLImageInfoFSL EglImageInfo;
eglQueryImageFSL(eglDisplay, hEglImage[iTextureIndex], EGL_CLIENTBUFFER_TYPE_FSL, (EGLint *)&EglImageInfo);

хотя эта особенность Freescale i.Платформа MX53 делает преобразование цветового пространства YUV в RGB для видео чрезвычайно быстрым, у него есть несколько ограничений:

  1. он поддерживает только эти 3 формата YUV.
  2. eglCreateImageKHR () должен выделить буферы. Невозможно заставить его использовать существующие буферы. Freescale подтвердил, что нулевым указателем не может быть ничего другого, что технически нарушает спецификацию Хроноса.

Freescale решил эти проблемы на i.Платформа MX6, хотя архитектура действительно отличается. Надеюсь, это поможет.