7

我必须使用 Freescale iMX53 处理器(OpenGL ES 2.0,EGL)上的 AMD GPU 将 YUV420P 图像转换并显示为 RGB 颜色空间。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(...) 失败。如果我将“attribs”中的相应行更改为:

EGL_IMAGE_FORMAT_FSL、EGL_FORMAT_RGB_565_FSL、

然后可以将图像分配给 OpenGL ES 纹理,但不适合保存 8 位数据 (Y/U/V) 或 YUV420/YV12 数据。搜索网络(包括飞思卡尔社区论坛)我还没有找到任何解决方案。

如何创建一个图像:

  • 快速创建;
  • 最终可以分配给一个已经存在的缓冲区(给定物理地址或虚拟地址);
  • 可用于片段/顶点着色器程序中进行 YUV --> RGB 转换;

约束是为了避免由于性能原因不必要的 memcpy(...)s。

4

1 回答 1

8

我已经在 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);

尽管飞思卡尔 i.MX53 平台的这一特性使得视频的 YUV 到 RGB 色彩空间转换速度极快,但它确实存在一些限制:

  1. 它只支持这 3 种 YUV 格式。
  2. eglCreateImageKHR() 必须分配缓冲区。没有办法让它使用现有的缓冲区。Freescale 确认 NULL 指针不能是其他任何东西,这在技术上违反了 Khronos 规范。

飞思卡尔已经在 i.MX6 平台上解决了这些问题,尽管架构确实不同。希望这可以帮助。

于 2014-02-13T18:51:22.887 回答