【问题标题】:texture for YUV420 to RGB conversion in OpenGL ESOpenGL ES 中 YUV420 到 RGB 转换的纹理
【发布时间】:2014-02-14 02:51:22
【问题描述】:

我必须使用 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。

【问题讨论】:

    标签: opengl-es gpu rgb yuv egl


    【解决方案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);
    

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

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

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

    【讨论】:

    • 非常感谢您的帮助,事实证明这是非常宝贵的信息。我对 OpenGL (ES) 相当陌生,并且对解决如此简单的问题必须牢记的许多新细节感到困惑。我的 YUV420 --> RGB 转换器现在可以工作了,虽然效率不是很高,因为使用 3 个 EGL_FORMAT_YUV_YV12_FSL 图像来保存 Y、U 和 V 分量。我无法在片段着色器代码中正确地从单个 EGL_FORMAT_YUV_YV12_FSL 纹理中获取 Y、U 和 V 分量,而这另一种方法可以正常工作...
    • 顺便说一句,我很遗憾在 iMX53 上我无法将现有缓冲区的地址传递给 eglCreateImageKHR()。也许我会从相反的方向解决这个问题:我创建了许多图像并将这些图像的物理地址传递给 VPU 以将解码的帧放入。我不确定它会起作用(例如,VPU 需要 DMA 内存)...
    • 我就是这么做的。让 EGL 分配缓冲区,然后使用这些缓冲区从 VPU 接收解码帧。我发现它消除了使用 IPU 的需要并且效果更好。 CPU使用率非常低。您可以修改飞思卡尔的 gstreamer isink 插件或 mxc-vpu-test 单元测试。
    • 没有成功。 Y、Cb 和 Cr 的 VPU 帧缓冲区地址来自 eglQueryImageFSL。 VPU 解码一帧,我从 eglQueryImageFSL 提供的虚拟地址到视频帧缓冲区执行 memcpy,它只是一遍又一遍地显示相同的垃圾。物理地址从 0x00100000 (1MB) 开始,也许它们是 GPU 内存区域内部的偏移量?现在我只需将这些地址传递给 VPU...
    • 好的,我想通了! :) 必须使用“gpu_nommu”内核选项,因此物理地址将可以在系统范围内访问(不仅是 GPU 使用其 MMU)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-03
    • 2014-10-23
    • 2012-02-19
    • 2011-09-27
    • 2014-05-16
    • 1970-01-01
    相关资源
    最近更新 更多