像素格式、CVPixelBufferRefs和glReadPixels

7
我正在使用glReadPixels将数据读入CVPixelBufferRef中。我将CVPixelBufferRef用作AVAssetWriter的输入。不幸的是,像素格式似乎不匹配。
我认为glReadPixels返回的像素数据是RGBA格式,而AVAssetWriter想要ARGB格式的像素数据。最好的方法是将RGBA转换为ARGB
到目前为止,我尝试过以下方法:
  • 位操作,类似于argb = (rgba >> 8) | (rgba << 24)
  • 使用CGImageRef作为中间步骤
位操作不起作用,因为CVPixelBufferRef似乎不支持下标。使用CGImageRef作为中间步骤确实有效...但我宁愿不要多出50行可能会影响性能的代码。

2
你是如何获取CVPixelBufferRef的?你是否调用了CVPixelBufferCreate?如果是这样,你将pixelFormatType参数传递为什么?你将哪种格式传递给glReadPixels? - rob mayoff
我正在将 kCVPixelFormatType_32ARGB 传递给 CVPixelBufferCreate。我将 GL_RBGA 传递给 glReadPixels。我尝试将 RBGA 格式传递给 CVPixelBufferCreate,但它没有起作用(要么颜色不正确,要么应用程序崩溃)。 - MrDatabase
5个回答

7
关于位操作,您可以获得指向像素缓冲区原始数据的指针:
CVPixelBufferLockBaseAddress(buffer, 0);
size_t stride = CVPixelBufferGetBytesPerRow(buffer);
char *data = (char *)CVPixelBufferGetBaseAddress(buffer);
for (size_t y = 0; y < CVPixelBufferGetHeight(buffer); ++y) {
    uint32_t *pixels = (uint32_t *)(data + stride * y);
    for (size_t x = 0; x < CVPixelBufferGetWidth(buffer); ++x)
        pixels[x] = (pixels[x] >> 8) | (pixels[x] << 24);
}
CVPixelBufferUnlockBaseAddress(buffer, 0);

7
更好的方法是使用简单的片段着色器在渲染图像时高效地在GPU上进行交换,而不是使用CPU进行交换组件。最好的方法是使用iOS5 CoreVideo CVOpenGLESTextureCache完全删除复制阶段,允许您直接渲染到CVPixelBufferRef,消除了对glReadPixels的调用。 p.s. 我很确定AVAssetWriter希望数据以BGRA格式提供(实际上它可能希望以yuv格式提供,但那是另一个故事)。
更新:至于链接,文档似乎仍然受NDA保护,但有两个可自由下载的示例代码可用: GLCameraRippleRosyWriter 头文件本身包含良好的文档,Mac版本非常相似(CVOpenGLTextureCache),因此您应该有足够的资料开始。

1
如果您拥有ADC登录凭据,您可以获取文档,并添加一些示例代码来回答。 - Rhythmic Fistman
最好的方法是通过使用iOS5 CoreVideo CVOpenGLESTextureCache完全删除复制阶段,这允许您直接渲染到CVPixelBufferRef,消除了对glReadPixels的调用。很遗憾,我找不到任何关于这个备受期待的功能的文档。 - Or Arbel
阅读头文件:CVOpenGLESTextureCache.h - Rhythmic Fistman
我做了,它说:“从现有的CVImageBuffer创建一个CVOpenGLESTexture对象”。这正好与我们想要的相反 :( - kevlar
https://dev59.com/Qmkw5IYBdhLWcg3w8O-o - jonahb
显示剩余3条评论

2
这可能有些冒险,但您尝试过在glReadPixels中使用GL_BGRA,并在CVPixelBufferCreate中使用kCVPixelFormatType_32BGRA吗?
我建议这样做是因为技术问答 QA1501没有列出任何RGBA格式作为支持的格式。

不幸的是,将GL_BGRA传递给glReadPixels会导致输出像素数据全部为零 :-( - MrDatabase

1
    glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, _buffer);
    CVPixelBufferRef buffer = NULL;
    CVReturn ret = CVPixelBufferCreateWithBytes(kCFAllocatorDefault,_size.width,_size.height,kCVPixelFormatType_32BGRA,glubyte,_size.width*4,NULL,NULL,NULL,&buffer);

1

glReadPixels(0, 0, w*s, h*s, GL_BGRA, GL_UNSIGNED_BYTE, buffer);

在 glReadPixels 中使用 GL_BGRA。 我已经试过了,它可以正常工作。


你在输出缓冲区中得到了非零数据吗? - MrDatabase

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接