我正在使用 OpenGL 对1280x720快速视频的每一帧进行一些图像处理。然后回读帧并从这些帧创建新视频。问题是需要从 OpenGL (使用 glTexImage2D 和 glReadPixels )转移大量数据,导致速度非常慢过程
目前,我正在使用 kCVPixelFormatType_32BGRA 作为 AVAssetReaderTrackOutput 实例的像素格式。为了减少时间消耗,我想使用16位像素格式。不幸的是,在调用 AVAssetReaderTrackOutput的copyNextSampleBuffer 方法时,更改为这种格式会给我空帧。有没有人有在AV Foundation中使用16位像素格式的经验?
如果我无法让AV基金会为我更改格式,我想我可以“手动”将32位转换为16位,也许使用NEON指令?任何帮助表示赞赏。
答案 0 :(得分:1)
进一步修订,现在这是社区维基,因为我在单独回答这个问题时犯了很多错误,这是有道理的。
虽然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及以上版本,并且可以花费2倍于SGX iOS设备上可用的8个纹理单元。
YCbCr是一个颜色空间,分别代表颜色为亮度(Y)和颜色(CbCr)。根据经验证明,可以以低于亮度的频率对彩色通道进行采样,而无需任何人能够分辨。像素格式的'420'部分描述了每4个Y分量得到的Cb和Cr成分的数量 - 基本上它告诉你每Y个样本得到一个Cb样本和一个Cr样本。因此你有一个用于描述四个像素的总共六个字节,对于12比特/像素而不是RGB中的24比特/像素。这可以节省50%的存储空间。
出于总体目的,您可能会产生额外费用,因为它是两次上传而不是一次。如果你想避免依赖纹理读取,你还需要使用三种变化,我认为新交所仅限于其中的八种。