1

我正在使用 Siphon 框架尝试将视频帧从服务器推送到客户端应用程序。

Siphon 要求您使用 OpenGL 纹理而不是普通图像。

因此,我试图将 CGImageRef 渲染为纹理并将其发送到发布。

我正在创建我的 CGL 上下文:

CGLPixelFormatAttribute attribs[13] = {
    kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)kCGLOGLPVersion_3_2_Core, // This sets the context to 3.2
    kCGLPFAColorSize,     (CGLPixelFormatAttribute)24,
    kCGLPFAAlphaSize,     (CGLPixelFormatAttribute)8,
    kCGLPFAAccelerated,
    kCGLPFADoubleBuffer,
    kCGLPFASampleBuffers, (CGLPixelFormatAttribute)1,
    kCGLPFASamples,       (CGLPixelFormatAttribute)4,
    (CGLPixelFormatAttribute)0
};

CGLPixelFormatObj pix;
GLint npix;
CGLChoosePixelFormat(attribs, &pix, &npix);

CGLCreateContext(pix, 0, &_ctx);

我已经有一个我知道可以正确渲染为 NSImage 的 CGImageRef。

我正在渲染纹理:

CGLLockContext(cgl_ctx);

if (_texture) {
    glDeleteTextures(1, &_texture);
}

int width = 1920;
int height = 1080;

GLubyte* imageData = malloc(width * height * 4);
CGContextRef imageContext = CGBitmapContextCreate(imageData, width, height, 8, width * 4, CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
CGContextDrawImage(imageContext, CGRectMake(0.0, 0.0, width, height), image);
CGContextRelease(imageContext);

GLuint frameBuffer;
GLenum status;

glGenFramebuffersEXT(1, &frameBuffer);

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBuffer);
glGenTextures(1, &_texture);
glBindTexture(GL_TEXTURE_2D, _texture);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_TEXTURE_2D, imageData);

status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);

if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
    NSLog(@"OpenGL Error");
}

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

CGLUnlockContext(cgl_ctx);

渲染代码在不同的类中,但上下文应该是通过的,并且是相同的。

我在这个问题的几乎所有其他实例中都尝试了该建议,但无济于事。

4

2 回答 2

1

倒数第二个参数glTexImage2D是:

type
指定像素数据的数据类型。接受以下符号值: GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT, GL_FLOAT, GL_UNSIGNED_BYTE_3_3_2, GL_UNSIGNED_BYTE_2_3_3_REV, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_5_6_5_REV, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_4_4_4_4_REV, GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_SHORT_1_5_5_5_REV, GL_UNSIGNED_INT_8_8_8_8, GL_UNSIGNED_INT_8_8_8_8_REV, GL_UNSIGNED_INT_10_10_10_2, 和GL_UNSIGNED_INT_2_10_10_10_REV.

GL_TEXTURE_2D在那里没有意义,它应该是元素的任何数据类型imageData

您还应该使用glGetError或检查您的 OpenGL 错误ARB_debug_output。您会立即看到问题所在:

Source:OpenGL   Type:Error  ID:5    Severity:High   Message:GL_INVALID_ENUM in glTexImage2D(incompatible format = GL_RGBA, type = GL_TEXTURE_2D)
于 2015-06-09T23:05:42.627 回答
1

这段代码有几个问题。以下是使事情正常进行的关键:

  • 正如@orost 在较早的回答中所指出的那样,调用的类型参数glTexImage2D()无效。它应该是:

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,
                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    
  • 纹理永远不会作为 FBO 目标附加。设置 FBO 时,您需要:

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                           GL_TEXTURE_2D, _texture, 0);
    

还有一些项目可能不会阻止您运行它,但我还是建议您更改它们:

  • 如果要通过渲染来创建内容,则不需要为纹理指定数据。无论如何,您传递给的数据glTexImage2D()都是未初始化的,所以这并没有什么好处。正如我在上面显示的调用中所做的那样,作为 data 参数NULL传递干净得多。
  • 由于您使用的是 OpenGL 3.2,因此实际上没有必要使用EXTFBO 入口点的形式。这是 OpenGL 3.x 中的标准功能。EXT只要您始终如一地使用该表单,它就可能会起作用,但如果您将它与标准入口点混合使用,您可能会遇到丑陋的惊喜。
于 2015-06-10T02:18:29.243 回答