1

我正在实现一个裁剪视频帧的自定义视频合成器。目前我使用核心图形来做到这一点:

-(void)renderImage:(CGImageRef)image inBuffer:(CVPixelBufferRef)destination {
    CGRect cropRect = // some rect ...
    CGImageRef currentRectImage = CGImageCreateWithImageInRect(photoFullImage, cropRect);

    size_t width = CVPixelBufferGetWidth(destination);
    size_t height = CVPixelBufferGetHeight(destination);

    CGContextRef context = CGBitmapContextCreate(CVPixelBufferGetBaseAddress(destination),       // data
                                             width,
                                             height,
                                             8,                                              // bpp
                                             CVPixelBufferGetBytesPerRow(destination),
                                             CGImageGetColorSpace(backImage),
                                             CGImageGetBitmapInfo(backImage));

    CGRect frame = CGRectMake(0, 0, width, height);
    CGContextDrawImage(context, frame, currentRectImage);
    CGContextRelease(context);
}

我如何使用 Metal API 来做到这一点?它应该快得多,对吧?使用 Accelerate 框架(特别是 vImage)怎么样?那会更简单吗?

4

2 回答 2

3

好的,我不知道这对您是否有用,但仍然。查看以下代码:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
  CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);

  id<MTLTexture> textureY = nil;

  {
    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)
    {
      textureY = CVMetalTextureGetTexture(texture);
      if (self.delegate){
        [self.delegate textureUpdated:textureY];
      }
      CFRelease(texture);
    }
  }
}

我使用此代码转换CVPixelBufferRef为 MTLTexture。之后,您可能应该创建blitCommandEncoder并使用它

func copyFromTexture(sourceTexture: MTLTexture, sourceSlice: Int, sourceLevel: Int, sourceOrigin: MTLOrigin, sourceSize: MTLSize, toTexture destinationTexture: MTLTexture, destinationSlice: Int, destinationLevel: Int, destinationOrigin: MTLOrigin)

在其中,您可以选择裁剪的矩形并将其复制到其他纹理。

下一步是将生成的转换MTLTexturesCVPixelBufferRefs然后制作视频,不幸的是我不知道该怎么做。

真的很想听听你的想法。干杯。

于 2015-04-27T08:01:27.800 回答
2

因为它使用裸指针和未封装的数据,所以 vImage 将通过将指针移动到图像的左上角以指向新的左上角并相应地减小高度和宽度来“裁剪”事物。您现在有一个 vImage_Buffer ,它引用图像中间的一个区域。当然,您仍然需要将内容再次导出为文件或将其复制到注定要绘制到屏幕上的内容。参见例如 vImageCreateCGImageFromBuffer()。

CG 可以通过 CGImageCreateWithImageInRect() 自行完成

Metal 可以通过简单的计算复制内核、MTLBlitCommandEncoder blit 或将纹理 3D 渲染应用到具有适当坐标偏移的三角形集合来执行此操作。

于 2016-06-08T00:15:31.077 回答