Iphone CVOpenGLESTextureCacheCreateTextureFromImage而不是glReadPixels

Iphone CVOpenGLESTextureCacheCreateTextureFromImage而不是glReadPixels,iphone,objective-c,opengl-es-2.0,glreadpixels,Iphone,Objective C,Opengl Es 2.0,Glreadpixels,整整三天来,我一直在努力提高基于glReadPixels的AVAssetWriter的性能。我已经看过了苹果的RosyWriter和摄像头Ripple代码,还有Brad Larson的GPUImage,但我仍然摸不着头脑。我还尝试使用这些链接中列出的实现: …还有更多,但无论我怎么努力,我都无法让它发挥作用。要么视频最终没有被处理,要么它变成黑色,要么我得到各种错误。我不会在这里把所有的都讲一遍 为了简化我的问题,我想我应该专注于从屏幕上的openGL预览FBO抓取快照。如果我只需要一个实现

整整三天来,我一直在努力提高基于glReadPixels的AVAssetWriter的性能。我已经看过了苹果的RosyWriter和摄像头Ripple代码,还有Brad Larson的GPUImage,但我仍然摸不着头脑。我还尝试使用这些链接中列出的实现:

…还有更多,但无论我怎么努力,我都无法让它发挥作用。要么视频最终没有被处理,要么它变成黑色,要么我得到各种错误。我不会在这里把所有的都讲一遍

为了简化我的问题,我想我应该专注于从屏幕上的openGL预览FBO抓取快照。如果我只需要一个实现就可以了,那么我就可以完成剩下的工作了。我从上面的第一个链接尝试了实现,该链接如下所示:

CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, [glView context], 
                           NULL, &texCacheRef);

CFDictionaryRef empty = CFDictionaryCreate(kCFAllocatorDefault,
                           NULL,
                           NULL,
                           0,
                           &kCFTypeDictionaryKeyCallBacks,
                           &kCFTypeDictionaryValueCallBacks);

CFMutableDictionaryRef attrs = CFDictionaryCreateMutable(kCFAllocatorDefault,
                                  1,
                                  &kCFTypeDictionaryKeyCallBacks,
                                  &kCFTypeDictionaryValueCallBacks);

CFDictionarySetValue(attrs,
                     kCVPixelBufferIOSurfacePropertiesKey,
                     empty);

CVPixelBufferRef renderTarget = NULL;
CVPixelBufferCreate(kCFAllocatorDefault,
                    width,
                    height,
                    kCVPixelFormatType_32BGRA,
                    attrs,
                    &renderTarget);

CVOpenGLESTextureRef renderTexture;
CVOpenGLESTextureCacheCreateTextureFromImage (kCFAllocatorDefault,
                                              texCacheRef,
                                              renderTarget,
                                              NULL,
                                              GL_TEXTURE_2D,
                                              GL_RGBA,
                                              width,
                                              height,
                                              GL_BGRA,
                                              GL_UNSIGNED_BYTE,
                                              0,
                                              &renderTexture);

CFRelease(attrs);
CFRelease(empty);
glBindTexture(CVOpenGLESTextureGetTarget(renderTexture), CVOpenGLESTextureGetName(renderTexture));
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

GLuint renderFrameBuffer;
glGenRenderbuffers(1, &renderFrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, renderFrameBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                       GL_TEXTURE_2D, CVOpenGLESTextureGetName(renderTexture), 0);

//Is this really how I pull pixels off my context?
CVPixelBufferLockBaseAddress(renderTarget, 0);
buffer = (GLubyte *)CVPixelBufferGetBaseAddress(renderTarget);
CVPixelBufferUnlockBaseAddress(renderTarget, 0);
这里到底会发生什么?我的缓冲区最终是一堆零,所以我想我需要做一些额外的事情来从上下文中提取像素。。。或者我错过了什么

我想要实现的只是一个与我现在使用的更快的等价物:

int pixelsCount = w * h;
buffer = (GLubyte *) malloc(pixelsCount * 4);
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);


正如布拉德指出的,我误解了这个概念,没有做任何实际的渲染。当我添加它时,效果很好。

正如Brad指出的,我误解了这个概念,没有进行任何实际渲染。添加时效果很好。

在上面的代码中没有显示任何实际渲染。一旦有了纹理支持的FBO,并且该FBO的纹理已由纹理缓存提供,则需要将内容渲染到该FBO中。只有这样,才能从用于备份FBO的纹理中读取像素数据。在从缓冲区读回像素数据之前,您可能需要插入一个
glFinish()
,以确保OpenGL ES有时间完成对纹理的渲染。啊,真不敢相信我错过了。我的印象是,渲染到主FBO就足够了,然后我可以从中提取类似于glReadPixels的内容。我只是试着用这个来代替我的FBO,结果成功了。谢谢!如果你把你的评论作为回应,我会接受的。虽然我让它工作起来了,但我仍然对CVOpenGlestExtextRecacheCreate调用有点困惑。这里传递的EAGLContext是来自我已经呈现到的另一个FBO…还是可以使用新的上下文只呈现一次(直接呈现到上面代码中的那个)?只要我使用另一个上下文,我只会在缓冲区中返回零。与glReadPixel方法相比,写入资产的时间大约为glReadPixel方法的3/4。在上面的代码中没有显示任何实际渲染。一旦有了纹理支持的FBO,并且该FBO的纹理已由纹理缓存提供,则需要将内容渲染到该FBO中。只有这样,才能从用于备份FBO的纹理中读取像素数据。在从缓冲区读回像素数据之前,您可能需要插入一个
glFinish()
,以确保OpenGL ES有时间完成对纹理的渲染。啊,真不敢相信我错过了。我的印象是,渲染到主FBO就足够了,然后我可以从中提取类似于glReadPixels的内容。我只是试着用这个来代替我的FBO,结果成功了。谢谢!如果你把你的评论作为回应,我会接受的。虽然我让它工作起来了,但我仍然对CVOpenGlestExtextRecacheCreate调用有点困惑。这里传递的EAGLContext是来自我已经呈现到的另一个FBO…还是可以使用新的上下文只呈现一次(直接呈现到上面代码中的那个)?只要我使用另一个上下文,我只会在缓冲区中返回零。与glReadPixel方法相比,写出资产的时间大约是glReadPixel方法的3/4。我遇到的问题与您遇到的问题相同。我的屏幕是黑色的。。。你能告诉我如何解决这个问题吗?我的问题是我在提取缓冲区之前没有进行渲染。换句话说,我没有打电话给glDrawArrays。谢谢回复!我尝试放置这样的
gldrawArray(GL\u三角形\u条,0,4)我的项目中的代码,它仍然无法工作。我还提到了github上的GPUImage项目,我认为这对我来说可能有些困难。您可以给出一些关于渲染细节的提示吗?源代码更好…谢谢。没有你的代码很难解释。您是否使用glReadPixels,但不使用上述技术?如果是这样,您基本上需要执行与glReadPixel方法相同的所有步骤。这不是渲染的替代品。如果没有,您应该首先将目标放在使用glReadPixels上。这是一个简单得多的方法。是的,当使用glReadPixel时,它是成功的。有人说使用纹理缓存会更快,但这对我不起作用。我把代码发进去。如果可能的话,您可以看一下吗?在我的代码中,游戏开始时将调用
initdata
,并且在每个更新帧中将调用
powersmart\u callback
。在该功能中,屏幕将保存为图片。现在使用这种方法,图片将成功保存,但屏幕仍然是黑色的…你能帮我吗?我遇到了与你相同的问题。我的屏幕是黑色的。。。你能告诉我如何解决这个问题吗?我的问题是我在提取缓冲区之前没有进行渲染。换句话说,我没有打电话给glDrawArrays。谢谢回复!我尝试放置这样的
gldrawArray(GL\u三角形\u条,0,4)我的项目中的代码,它仍然无法工作。我还提到了github上的GPUImage项目,我认为这对我来说可能有些困难。您可以给出一些关于渲染细节的提示吗?源代码更好…谢谢。很好