我在iOS上以120 fps进行实时视频处理,并希望首先在GPU上预处理图像(下采样,转换颜色等在CPU上不够快),然后使用OpenCV在CPU上后处理帧。
使用Metal在GPU和CPU之间共享相机Feed的最快方法是什么?
换句话说,管道看起来像:
CMSampleBufferRef -> MTLTexture or MTLBuffer -> OpenCV Mat
我正在转换CMSampleBufferRef - > MTLTexture以下方式
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
// textureRGBA
{
size_t width = CVPixelBufferGetWidth(pixelBuffer);
size_t height = CVPixelBufferGetHeight(pixelBuffer);
MTLPixelFormat pixelFormat = MTLPixelFormatBGRA8Unorm;
CVMetalTextureRef texture = NULL;
CVReturn status = CVMetalTextureCacheCreateTextureFromImage(NULL, _textureCache, pixelBuffer, NULL, pixelFormat, width, height, 0, &texture);
if(status == kCVReturnSuccess) {
textureBGRA = CVMetalTextureGetTexture(texture);
CFRelease(texture);
}
}
我的金属着色器完成后,我将MTLTexture转换为OpenCV
cv::Mat image;
...
CGSize imageSize = CGSizeMake(drawable.texture.width, drawable.texture.height);
int imageByteCount = int(imageSize.width * imageSize.height * 4);
int mbytesPerRow = 4 * int(imageSize.width);
MTLRegion region = MTLRegionMake2D(0, 0, int(imageSize.width), int(imageSize.height));
CGSize resSize = CGSizeMake(drawable.texture.width, drawable.texture.height);
[drawable.texture getBytes:image.data bytesPerRow:mbytesPerRow fromRegion:region mipmapLevel:0];
一些观察结果:
1)不幸的是MTLTexture.getBytes
似乎很贵(将数据从GPU复制到CPU?)并且在我的iphone 5S上大约需要5ms,这在处理~100fps时太多了
2)我注意到有些人使用MTLBuffer代替MTLTexture,方法如下:
metalDevice.newBufferWithLength(byteCount, options: .StorageModeShared)
(见:Memory write performance - GPU CPU Shared Memory)
然而,CMSampleBufferRef
和随附的CVPixelBufferRef
由CoreVideo管理。
答案 0 :(得分:5)
最快的方法是使用MTLBuffer支持的MTLTexture;它是一种特殊的MTLTexture,它与MTLBuffer共享内存。但是,您的C处理(openCV)将运行一两帧,这是不可避免的,因为您需要将命令提交到GPU(编码)并且GPU需要渲染它,如果您使用waitUntilCompleted来确保GPU完成后只是嚼起CPU而浪费。
所以过程将是:首先你创建MTLBuffer然后你使用MTLBuffer方法" newTextureWithDescriptor:offset:bytesPerRow:"创建特殊的MTLTexture。您需要事先创建特殊的MTLTexture(作为实例变量),然后您需要设置一个标准渲染管道(比使用计算着色器更快),它将采用从CMSampleBufferRef创建的MTLTexture并将其传递到您的特殊MTLTexture中,通过你可以缩小规模,并在一次通过必要的颜色转换。然后你将命令缓冲区提交给gpu,在后续的传递中你可以调用[theMTLbuffer contents]来获取指向特殊MTLTexture的字节的指针,以便在openCV中使用。
任何强制停止CPU / GPU行为的技术都将无效,因为等待的时间有一半,即CPU等待GPU完成,GPU也必须等待下一次编码(当GPU正在工作,你希望CPU编码下一帧并执行任何openCV工作,而不是等待GPU完成)。
此外,当人们通常提到实时处理时,他们通常指的是一些具有实时反馈(可视化)的处理,所有来自4s及以上的现代iOS设备都具有60Hz的屏幕刷新率,因此提供任何反馈比这更快没有意义但是如果你需要2帧(120Hz)来制作1(60Hz)那么你必须有一个自定义计时器或修改CADisplayLink。