Objective c 将CVOpenGLESTextureCacheCreateTextureFromImage移植到普通OpenGL ES方法

Objective c 将CVOpenGLESTextureCacheCreateTextureFromImage移植到普通OpenGL ES方法,objective-c,ios,opengl-es,core-video,Objective C,Ios,Opengl Es,Core Video,我正在开发一个应用程序,它将来自相机的视频帧输入到OpenGL ES纹理中,以创建一些效果。该应用程序使用核心视频及其许多方便的方法来创建OpenGL纹理和缓存 现在我想使用静态图像而不是视频缓冲区,我正在寻找标准的OpenGL方法来代替核心视频中可用的方法 例如: CVOpenGLESTextureRef CVOpenGLESTextureCacheRef CVOpenGLESTextureCacheCreateTextureFromImage() CVOpenGLESTextureGetT

我正在开发一个应用程序,它将来自相机的视频帧输入到OpenGL ES纹理中,以创建一些效果。该应用程序使用核心视频及其许多方便的方法来创建OpenGL纹理和缓存

现在我想使用静态图像而不是视频缓冲区,我正在寻找标准的OpenGL方法来代替核心视频中可用的方法

例如:

  • CVOpenGLESTextureRef
  • CVOpenGLESTextureCacheRef
  • CVOpenGLESTextureCacheCreateTextureFromImage()
  • CVOpenGLESTextureGetTarget()
  • CVOpenGLESTextureGetName()
  • CVOpenGLESTextureCacheFlush()
我可以用什么标准的OpenGL类型和方法来代替上面的代码从法线图像加载和创建纹理

谢谢

*编辑*

按照布拉德的建议,我取得了一些进展。。。但仍然不能正常工作。我认为问题在于着色器希望两个单独的纹理能够正常工作。一个用于Y平面,一个用于UV平面

这是用来设置它们的代码

// Y-plane
glActiveTexture(GL_TEXTURE0);
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _videoTextureCache, pixelBuffer, NULL, GL_TEXTURE_2D, GL_RED_EXT, _textureWidth, _textureHeight, GL_RED_EXT, GL_UNSIGNED_BYTE, 0, &_lumaTexture);
glBindTexture(CVOpenGLESTextureGetTarget(_lumaTexture), CVOpenGLESTextureGetName(_lumaTexture));
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

// UV-plane
glActiveTexture(GL_TEXTURE1);
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _videoTextureCache, pixelBuffer, NULL, GL_TEXTURE_2D, GL_RG_EXT, _textureWidth/2, _textureHeight/2, GL_RG_EXT, GL_UNSIGNED_BYTE, 1, &_chromaTexture);
glBindTexture(CVOpenGLESTextureGetTarget(_chromaTexture), CVOpenGLESTextureGetName(_chromaTexture));
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
所以我改成这样:

这是设置

glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &_lumaImageTexture);
glBindTexture(GL_TEXTURE_2D, _lumaImageTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glActiveTexture(GL_TEXTURE1);
glGenTextures(1, &_chromaImageTexture);
glBindTexture(GL_TEXTURE_2D, _chromaImageTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
下面是我如何创建它们的

// Y-plane
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _lumaImageTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _textureWidth, _textureHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

// UV-plane
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _chromaImageTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _textureWidth, _textureHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

我想问题出在glTexImage2D函数中的一个参数中。我尝试了不同的组合,得到了不同的结果。。。但从来都不是正确的方法:)

所有这些方法所做的就是为您提供一个与CVPixelBuffer相对应的OpenGL ES纹理。在iOS 5.0中引入这些之前,我们必须手动从CVPixelBuffer中获取像素数据并将其上传到纹理。对于从另一个源提取的静态图像,您将使用相同的过程(除非您想使用一些GLKit便利类)

下面是我用来上传静态图像的代码。首先,需要将图像放入BGRA字节数组:

if (shouldRedrawUsingCoreGraphics)
{
    // For resized image, redraw
    imageData = (GLubyte *) calloc(1, (int)pixelSizeToUseForTexture.width * (int)pixelSizeToUseForTexture.height * 4);

    CGColorSpaceRef genericRGBColorspace = CGColorSpaceCreateDeviceRGB();    
    CGContextRef imageContext = CGBitmapContextCreate(imageData, (int)pixelSizeToUseForTexture.width, (int)pixelSizeToUseForTexture.height, 8, (int)pixelSizeToUseForTexture.width * 4, genericRGBColorspace,  kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
    CGContextDrawImage(imageContext, CGRectMake(0.0, 0.0, pixelSizeToUseForTexture.width, pixelSizeToUseForTexture.height), newImageSource);
    CGContextRelease(imageContext);
    CGColorSpaceRelease(genericRGBColorspace);
}
else
{
    // Access the raw image bytes directly
    dataFromImageDataProvider = CGDataProviderCopyData(CGImageGetDataProvider(newImageSource));
    imageData = (GLubyte *)CFDataGetBytePtr(dataFromImageDataProvider);
}    
在上面的代码中,
newImageSource
是一个CGImageRef。这显示了用于提取位图数据的两种不同路径,第一种路径在我运行的每个基准测试中都出人意料地快

一旦有了它,您只需将其上载到OpenGL ES纹理:

    glBindTexture(GL_TEXTURE_2D, outputTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)pixelSizeToUseForTexture.width, (int)pixelSizeToUseForTexture.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);
这假设您已经使用以下内容创建了outputTexture:

    glActiveTexture(GL_TEXTURE0);
    glGenTextures(1, &outputTexture);
    glBindTexture(GL_TEXTURE_2D, outputTexture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // This is necessary for non-power-of-two textures
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
并且通过使用
+setCurrentContext:
将正确的EAGLContext与当前线程关联


如果我可以提出一个建议,为什么不看看为您处理所有这些,以便做图像处理任务?这可能会为您节省一些精力。

嗨,布拉德,我知道您的框架。。。真是太棒了!然而,我只是觉得对于这样简单的任务来说,开销太大了。我会试着按照你的建议去做,看看是否能先这样做。谢谢嘿,布拉德,谢谢!这是一种工作。。。我得到了纹理,唯一的问题是它是绿色的。这是因为纹理格式错误,并且没有包含每个通道所需的所有位吗?对不起,如果问题不是很精确。。。但我是一个完全不懂OpenGL的人。:)@Andrea-如果它是绿色的,但是图像仍然显示,并且没有填充一束对角线,那么输入图像的字节顺序可能有问题。它可能接受RGBA而不是BGRA,或ARGB或ABGR。我在位图上下文中使用的上述设置是专门为生成BGRA帧而选择的,用于稍后的纹理上载。请确保您没有使用其他上下文设置。我严格遵循了您的代码,但不幸的是它不起作用。我想我很清楚原因。请检查对我原始问题的编辑。。。我补充了更多细节。(我该怎么办?@yourname with yourname?@Andrea-是的,当然对于平面YUV来说,这不会像上面所描述的那样起作用。当你说“现在我想使用静态图像”时,我假设你是从UIImage源提取的,在那里你可以提取到BGRA图像缓冲区。你现在问的问题完全不同了。对于YUV平面源,需要将Y和UV纹理的
glTexImage2d()
参数替换为更新的第一个代码中显示的纹理缓存函数中的参数。请注意新的字节大小以及
GL_RED_EXT
GL_RG_EXT
纹理类型的使用。