Opengl es OpenGL ES中YUV420到RGB转换的纹理

Opengl es OpenGL ES中YUV420到RGB转换的纹理,opengl-es,gpu,rgb,yuv,egl,Opengl Es,Gpu,Rgb,Yuv,Egl,我必须在飞思卡尔iMX53处理器(OpenGL ES 2.0,EGL)上使用AMD GPU将YUV420P图像转换并显示为RGB颜色空间。Linux操作系统,没有X11。为了实现这一点,我应该能够创建一个保存YUV420P数据的适当图像:可以是YUV420P/YV12图像类型,也可以是3个简单的8位图像,每个组件(Y、U、V)一个 glTexImage2D被排除在外,因为它的速度很慢,YUV420P帧是实时视频解码的结果@25FPS,而glTexImage2D无法保持所需的帧速率 还有一种选择:

我必须在飞思卡尔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_图像_格式_FSL、EGL_格式_RGB_565_FSL、

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

如何创建符合以下条件的图像:

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

约束是为了避免由于性能原因而产生不必要的memcpy(…)。

我已经在I.MX53上为几种YUV格式实现了这一点,并且它工作得非常好。我发表了一篇关于它的文章,尽管它被推广到了更多的Android平台:

我怀疑您的问题是没有绑定到正确的纹理目标。应该是这样的:

glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, hEglImage[iTextureIndex]);

glBindTexture(GL_TEXTURE_EXTERNAL_OES, hTexture[iIndex]);   
EGLIMAGEAttribute应该是以下属性之一:

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颜色空间转换速度极快,但它确实存在一些限制:

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

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

    非常感谢您的帮助,这已经证明是非常宝贵的信息。我对OpenGL(ES)还比较陌生,甚至在解决这么简单的问题时,我都会记住许多新的细节,这让我感到困惑。我的YUV420-->RGB转换器现在可以工作了,但效率不高,因为它使用3个EGL_格式的YUV_YV12_FSL图像来保存Y、U和V分量。在片段着色器代码中,我无法从单个EGL_格式_YUV_YV12_FSL纹理中正确获取Y、U和V分量,而这另一种方法正好有效……顺便说一句,我很难过,在iMX53上,我无法将现有缓冲区的地址传递给eglCreateImageKHR()。也许我会从相反的方向来解决这个问题:我创建许多图像,并将这些图像的物理地址传递给VPU,以将解码后的帧放入其中。我不确定它是否能工作(例如VPU需要DMA内存)…我就是这么做的。让EGL分配缓冲区,然后使用这些缓冲区从VPU接收解码帧。我发现它消除了使用IPU的必要性,并且工作得更好。CPU使用率非常低。您可以修改飞思卡尔的gstreamer isink插件或mxc vpu测试单元测试。未成功。Y、Cb和Cr的VPU帧缓冲区地址来自eglQueryImageFSL。VPU解码一帧,我从eglQueryImageFSL提供的虚拟地址到视频帧缓冲区进行memcpy,它只是一遍又一遍地显示相同的垃圾。Phy地址从0x00100000(1MB)开始,可能是GPU内存区域内的偏移量?现在我只需将这些地址传递给VPU……好的,我已经找到了!:)必须使用“gpu_nommu”内核选项,因此物理地址将是全系统可访问的(不仅仅是gpu使用其MMU)。