【问题标题】:Fast video capture at 640x480@60fps以 640x480@60fps 快速拍摄视频
【发布时间】:2015-03-12 17:44:27
【问题描述】:

我想使用最少的资源以 60fps 的速度捕捉视频,因为我需要每帧最多使用 16-20ms,并且大部分时间将被帧上的繁重计算占用。

我目前正在使用预设AVCaptureSessionPreset1280x720,但我想以640x480 进行计算,否则设备将跟不上。问题从这里开始:根据 Apple 允许开发人员执行的操作,我无法直接以 640x480@60fps 捕获,并且我当前的调整大小非常慢。

我正在使用金属内核着色器调整图像大小,但 98% 的时间(在 Instruments 中看到)都花在这两行上:

[_inputTexture replaceRegion:region mipmapLevel:0 withBytes:inputImage.data bytesPerRow:inputImage.channels() * inputImage.cols];
...
[_outputTexture getBytes:outputImage.data bytesPerRow:inputImage.channels() * outputImage.cols fromRegion:outputRegion mipmapLevel:0];

基本上在内存加载/存储指令中。这部分让我感到困惑,因为理论上 iPhone 上的内存是在 CPU 和 GPU 之间共享的。

你认为金属代码应该更快吗?我也有使用 Metal 的视频演示,它不会出汗(GPU 上约 1 毫秒,而调整大小最多需要约 20 毫秒)。

没有更快的调整图像大小的方法吗?您对 Image I/O 的体验如何?

更新:

当我将工作组的大小增加到 22x22x1 时,图像大小调整的性能从 GPU 的 20 毫秒提高到了 8 毫秒。仍然不是我想要的,但更好。

更新 2:

我切换到 CoreGraphics,它运行得足够快。见this post。

【问题讨论】:

  • 您的问题是 replaceRegion 和 getBytes 调用会复制大量内存。您可以通过直接渲染到由 CoreVideo 缓冲区支持的纹理中来完全避免这种开销。

标签: ios video-capture metal


【解决方案1】:

我认为您已经从 Capture 会话创建了 UIImage,并且您必须将其转换为金属纹理 (MTLTexture)。但你不应该这样做。下面是一个如何从 CaptureOutput 委托获取 MTLTexture 的示例:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
id<MTLTexture> inTexture = nil;
size_t width = CVPixelBufferGetWidth(pixelBuffer);
size_t height = CVPixelBufferGetHeight(pixelBuffer);

MTLPixelFormat pixelFormat = MTLPixelFormatBGRA8Unorm;

CVMetalTextureRef metalTextureRef = NULL;
CVReturn status = CVMetalTextureCacheCreateTextureFromImage(NULL, _textureCache, pixelBuffer, NULL, pixelFormat, width, height, 0, &metalTextureRef);
if(status == kCVReturnSuccess) {
    inTexture = CVMetalTextureGetTexture(metalTextureRef);
    CFRelease(metalTextureRef);
}
CVPixelBufferUnlockBaseAddress(pixelBuffer,0);
}

【讨论】:

  • 虽然不能调整大小和裁剪,对吗?另一个问题是我需要 CPU 访问图像来执行一些计算。
  • “我正在使用金属内核着色器调整图像大小” - 这意味着您调整 MTLTexture 的大小并获得调整大小的 MTLTexture。如我所见,您获得了 UIImage,然后将其转换为 MTLTexture,使用内核着色器对其进行转换,然后调整 MTLTexture 的大小,然后将其转换回 UIImage。在我的示例中,您只需要进行一次转换。
  • 为什么不使用 AVCaptureSessionPreset640x480?
  • 因为它不是 60fps 而是只有 30fps。调整大小不是为了显示,而是为了在 CPU 上运行计算,我使用 Metal 进行调整,因为我认为它更快。现在使用 CG,请参阅上次更新。
猜你喜欢
  • 2014-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-13
相关资源
最近更新 更多