【问题标题】:Drawing YUV frames with OpenGL on mac在 mac 上使用 OpenGL 绘制 YUV 帧
【发布时间】:2011-07-18 09:31:12
【问题描述】:

我正在使用 ffmpeg 库解码视频并将解码的帧存储在数组中。现在我想用 OpenGL 在屏幕上绘制这些帧。我用谷歌搜索,发现苹果提供使用 GL_APPLE_ycbcr_422 格式进行有效绘图。所以我将 ffmpeg 中的解码帧切换为 PIX_FMT_YUYV422 格式(打包的 YUV 4:2:2、16bpp、Y0 Cb Y1 Cr),这似乎相当于 OpenGL 中的 GL_APPLE_ycbcr_422。现在我正在尝试使用此代码在表面上绘制框架:

GLsizei width = 2, height = 2;
uint8_t data[8] = {128,200,123,10,5,13,54,180}; 
GLuint texture_name;

glEnable(GL_TEXTURE_RECTANGLE_ARB);
assert(glGetError() == GL_NO_ERROR);

glGenTextures (1,&texture_name);
assert(glGetError() == GL_NO_ERROR);

glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_name);
assert(glGetError() == GL_NO_ERROR);    

glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_ARB, width * height * 2, (void*)data);
assert(glGetError() == GL_NO_ERROR);

glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_SHARED_APPLE);
assert(glGetError() == GL_NO_ERROR);

glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
assert(glGetError() == GL_NO_ERROR);

// not sure about code above    

glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
assert(glGetError() == GL_NO_ERROR);

glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
assert(glGetError() == GL_NO_ERROR);

glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
assert(glGetError() == GL_NO_ERROR);

glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
assert(glGetError() == GL_NO_ERROR);

glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
assert(glGetError() == GL_NO_ERROR);    

// end

glViewport(0, 0,  width,height);
assert(glGetError() == GL_NO_ERROR);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);                    
assert(glGetError() == GL_NO_ERROR);

glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, width, height, 0,
             GL_YCBCR_422_APPLE,GL_UNSIGNED_SHORT_8_8_APPLE,
             (void*)data);
assert(glGetError() == GL_NO_ERROR);

glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
                GL_YCBCR_422_APPLE,GL_UNSIGNED_SHORT_8_8_APPLE,
                (void*)data);
assert(glGetError() == GL_NO_ERROR);    

glMatrixMode(GL_PROJECTION); 
glLoadIdentity();

glScalef(1.0f, -1.0f, 1.0f);
glOrtho(0, width, 0, height, -1.0, 1.0);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glBegin(GL_QUADS);

glVertex3f(0, 0, -1.0f);
glVertex3f(width, 0, -1.0f);
glVertex3f(width, height, -1.0f);
glVertex3f(0, height, -1.0f);

glEnd();

但我没有看到正确的帧。相反,我看到我的显示器损坏的图片。所以我明白我对 OpenGL 的使用是不正确的,也许我不了解一些基本的东西。

请帮助纠正和理解我的错误。如果我应该使用 RTFM,请给我一个对我有帮助的链接,因为我没有找到任何有用的信息。

【问题讨论】:

  • 您可以发布您的glTexImage2D 电话吗?为纹理分配存储空间的那个。
  • 感谢您的回复!如果我理解,我不需要调用 glTexImage2D 因为这个函数只是从一种 pxl 格式转换为另一种格式。但如果你问它,那么我可能理解错了。实际上,我之前使用过 glTexImage2D 调用,参数如下: glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA8, width, height, 0, GL_YCBCR_422_APPLE,GL_UNSIGNED_SHORT_8_8_APPLE, vp->bitmap)
  • 你似乎是对的,我之前需要使用 glTexImage2D 调用。现在我正在使用它,但没有任何改变
  • 更新您的帖子以包含您的新代码。
  • 这可能是因为您使用的是大小合适的内部格式。尝试简单的GL_RGBA 而不是GL_RGBA8

标签: cocoa opengl ffmpeg


【解决方案1】:

这是我在我的一个应用程序中使用的,用于为从 CCD 相机拉出的 YUV 帧上传的数据设置 YUV 4:2:2 纹理目标:

glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_RECTANGLE_EXT);
glGenTextures(1, &textureName); 
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, textureName);
glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_EXT, videoImageSize.width * videoImageSize.height * 2, videoTexture);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_SHARED_APPLE);

glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA, videoImageSize.width, videoImageSize.height, 0, GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_REV_APPLE, videoTexture);      
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);

实际上传到纹理是通过以下方式完成的:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, textureName);
glTexSubImage2D (GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, videoImageSize.width, videoImageSize.height, GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_REV_APPLE, videoTexture);

在上面,videoTexture 是从相机捕获的 YUV 帧的原始字节的内存位置。我还在上面使用 Apple 的存储提示来加速上传,尽管我永远无法获得 GL_UNPACK_CLIENT_STORAGE_APPLE 优化来进一步加快上传速度。

这是从工作应用程序中复制并粘贴出来的,我看到的唯一真正区别是我在 getTexImage2D() 中使用 GL_RGBA 而不是 GL_RGB 以及使用 GL_UNSIGNED_SHORT_8_8_REV_APPLE 而不是 GL_UNSIGNED_SHORT_8_8_APPLE . ARB 和 EXT 矩形扩展在 Mac 上解析为相同的东西。

【讨论】:

  • 我试过你的代码来绘制几个像素,它似乎也不起作用。我在屏幕上看到的不是像素,而是不同图片的网格。
  • 改变了绘制方式...我现在只看到白色窗口,而不是我应该看到的 4 像素
  • @Oleg - 正如我所说,我上面的代码是从一个正常运行的、经过调整的应用程序中逐字粘贴的,所以如果你使用它,你的问题就在其他地方。也许您的纹理没有正确的坐标或者没有在屏幕上正确绘制。您是否尝试过使用简单的 RGBA 测试纹理,忽略所有 YUV 内容,只是为了验证您的实际绘图是否正确?
  • 感谢您的回复。实际上,我在代码中发现了一些错误并修复了它。现在我可以画框了,但似乎画不正确。我看到的不是不同的像素(见下文)。看起来我需要使用两个扩展的非幂,但我不确定问题出在哪里,因为我的纹理是二的幂(16x16)。这是我正在使用的代码pastebin.com/Pk6FkMnv。所以,我正在生成一个随机纹理,我放了一个断点并检查 data -variable 的所有值是否完全随机。
  • 这是我在屏幕上看到的内容:cl.ly/2E3n2M0a0v3d0g2X2M2Ncl.ly/1R3k29261i341K461m22cl.ly/1m423r2F03422d3V3d45。所以我得到了一些像素的混合,而不是它们的实际值。看起来它渲染它就像它有两个纹理的非幂的问题。但我不明白为什么?我使用的是 16x16 图片...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多