我正在 iOS 上进行 120 帧实时视频处理,并希望首先在 GPU 上预处理图像(降采样、转换颜色等),然后使用 OpenCV 在 CPU 上后处理帧。
使用 Metal,分享相机数据流在 GPU 和 CPU 之间的最快方法是什么?
换句话说,管道将如下所示:
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上大约需要5毫秒,当处理约100fps时这太多了。
2)我注意到一些人使用MTLBuffer代替MTLTexture并使用以下方法:metalDevice.newBufferWithLength(byteCount, options: .StorageModeShared)
(参见:Memory write performance - GPU CPU Shared Memory)
但是 CMSampleBufferRef
和相关的 CVPixelBufferRef
是由CoreVideo管理的。