1

我正在使用OpenGL对 1280x720 quicktime 视频的每一帧进行一些图像处理。然后读回这些帧,并从中创建一个新视频。问题是需要与OpenGL之间传输的大量数据(使用glTexImage2DglReadPixels),导致过程非常缓慢。

目前,我使用kCVPixelFormatType_32BGRA作为AVAssetReaderTrackOutput实例的像素格式。为了减少时间消耗,我想改用 16 位像素格式。不幸的是,在调用AVAssetReaderTrackOutput 的 copyNextSampleBuffer方法时,更改为这种格式会给我空帧。有没有人有在 AV Foundation 中使用 16 位像素格式的经验?

如果我不能让 AV Foundation 为我更改格式,我想我可以“手动”从 32 位转换为 16 位,也许使用 NEON 指令?任何帮助表示赞赏。

4

1 回答 1

1

进一步的修订,这现在是社区 wiki,因为我在单独回答这个问题时犯了很多错误,这是有道理的。

尽管 CoreGraphics 初步可以使用类似以下代码的方式为您执行 32 位到 16 位的转换,但它会报告“4 个整数位/分量;16 位/像素;3 分量颜色空间;kCGImageAlphaPremultipliedLast”是不受支持的参数组合。因此,CoreGraphics 似乎无法在内部理解 4 位/通道图像。

CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, buffer, width*height*4, NULL);
CGImageRef inputImage = CGImageCreate(  width, height,
                                        8, 32, width*4, 
                                        colourSpace, 
                                        kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big,
                                        dataProvider,
                                        NULL, NO,
                                        kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);

unsigned char *outputImage = (unsigned char *)malloc(width*height*2);
CGContextRef targetContext = CGBitmapContextCreate( outputImage,
                                                    width, height,
                                                    4, width*2,
                                                    colourSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGContextDrawImage(targetContext, CGRectMake(0, 0, width, height), inputImage);

/* uplopad outputImage to OpenGL here! */

CGContextRelease(targetContext);
CGImageRelease(inputImage);
CGColorSpaceRelease(colourSpace);
free(outputImage);

但是,根据文档:

支持的像素格式为 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange、kCVPixelFormatType_420YpCbCr8BiPlanarFullRange 和 kCVPixelFormatType_32BGRA,但在 iPhone 3G 上支持的像素格式为 kCVPixelFormatType_422YpCbCr8 和 kCVPixelFormatType_32BGRA。

因此,为了减小您收到的内容的大小,您可以切换到 YCbCr 颜色空间。当缓冲区返回双平面时(即,整个图像的所有 y 分量,然后所有 Cb 和 Cr 分量作为一个单独的块),您可以将它们作为两个单独的纹理上传到 OpenGL 并在着色器中重新组合,假设您很高兴将自己限制在 3GS 及更高版本,并且可以负担得起在 SGX iOS 设备上可用的 8 个纹理单元中的 2 个。

YCbCr 是一个颜色空间,将颜色分别表示为亮度(Y)和颜色(CbCr)。经验表明,颜色通道可以以低于亮度的频率进行采样,而任何人都无法分辨。像素格式的“420”部分描述了每 4 个 Y 分量有多少个 Cb 和 Cr 分量——本质上它告诉你每四个 Y 样本得到一个 Cb 样本和一个 Cr。因此你有一个总共六个字节来描述四个像素,对于 12 位/像素而不是 RGB 中的 24 位/像素。这样可以节省 50% 的存储空间。

出于 GL 的目的,您可能会产生额外的费用,因为它是两次上传而不是一次。如果你想避免依赖纹理读取,你还需要使用三个变量,我认为 SGX 仅限于其中的八个。

于 2011-05-25T10:46:05.937 回答