Iphone 从视频读取帧时,如何转换为16位像素格式以在OpenGL ES 2.0中使用(AV Foundation)
我正在使用OpenGL对1280x720 quicktime视频的每一帧进行一些图像处理。然后将帧读回,并根据这些帧创建新的视频。问题是需要在OpenGL之间传输大量数据(使用glTexImage2D和glReadPixels),导致过程非常缓慢 目前,我正在使用kCVPixelFormatType_32BGRA作为我的AvassetraderTrackOutput实例的像素格式。为了减少时间消耗,我想改用16位像素格式。不幸的是,当调用AvassetraderTrackOutput的copyNextSampleBuffer方法时,更改为这种格式会给我带来空帧。有没有使用AV基础的16位像素格式的经验?Iphone 从视频读取帧时,如何转换为16位像素格式以在OpenGL ES 2.0中使用(AV Foundation),iphone,opengl-es,avfoundation,neon,Iphone,Opengl Es,Avfoundation,Neon,我正在使用OpenGL对1280x720 quicktime视频的每一帧进行一些图像处理。然后将帧读回,并根据这些帧创建新的视频。问题是需要在OpenGL之间传输大量数据(使用glTexImage2D和glReadPixels),导致过程非常缓慢 目前,我正在使用kCVPixelFormatType_32BGRA作为我的AvassetraderTrackOutput实例的像素格式。为了减少时间消耗,我想改用16位像素格式。不幸的是,当调用AvassetraderTrackOutput的copyN
<如果我不能让AV基金会改变我的格式,我想我可以从32位转换为16位“手动”,也许使用霓虹灯指令?非常感谢您的帮助。这是一个进一步的修订,现在是社区维基,因为我在回答这个问题时犯了很多错误,这是有意义的 尽管CoreGraphics表面上可以使用以下代码为您进行32位到16位的转换,但它报告“4整数位/分量;16位/像素;3分量颜色空间;KCGimageAlphaPremultipledLast”是不受支持的参数组合。因此,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ƤYPCBCRC8BIPLANARVIDERANGE,
kCVPixelFormatTypeƤYPCBCRC8BIPLANARFULLRANGE
和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分量——本质上它告诉你每4个Y分量有一个Cb和一个Cr样本。因此,你总共有6个字节来描述4个像素,在RGB中是12位/像素,而不是24位/像素。这将为您节省50%的存储空间
出于总账目的,您可能会产生额外的成本,因为这是两次上传,而不是一次上传。如果要避免依赖纹理读取,您还需要使用三个变量,我认为SGX仅限于其中八个。进一步修订,现在这是社区wiki,因为我在单独回答这个问题时犯了很多错误,这是有意义的 尽管CoreGraphics表面上可以使用以下代码为您进行32位到16位的转换,但它报告“4整数位/分量;16位/像素;3分量颜色空间;KCGimageAlphaPremultipledLast”是不受支持的参数组合。因此,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ƤYPCBCRC8BIPLANARVIDERANGE,
kCVPixelFormatTypeƤYPCBCRC8BIPLANARFULLRANGE
和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分量——本质上它告诉你每4个Y分量有一个Cb和一个Cr样本。因此,你总共有6个字节来描述4个像素,在RGB中是12位/像素,而不是24位/像素。这将为您节省50%的存储空间
出于总账目的,您可能会产生额外的成本,因为这是两次上传,而不是一次上传。如果要避免依赖纹理读取,还需要使用三个变量,我认为SGX仅限于其中八个。谢谢您的回答。你的意思是我可以提供32位的像素数据给glTexImage2D,它会自动转换成16位吗?如果是这种情况,那么必须更改哪些参数?我的调用看起来像glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,bufferWidth,bufferHeight,0,GL_BGRA,GL_UNSIGNED_BYTE,CVPixelBufferGetBaseAddress(imageBuffer));实际上,它将是2个纹理。一个纹理用于Y平面(GL_亮度),另一个纹理用于UV平面(GL_亮度_ALPHA)。那就是