【问题标题】:How to draw cropped bitmap using the Metal API or Accelerate Framework?如何使用 Metal API 或 Accelerate Framework 绘制裁剪的位图?
【发布时间】:2015-04-23 02:57:38
【问题描述】:

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

-(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)怎么样?那会更简单吗?

【问题讨论】:

    标签: ios core-graphics accelerate-framework metal vimage


    【解决方案1】:

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

    - (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)
    

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

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

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

    【讨论】:

    • 你可以很容易地从 CVMetalTextureRef 到 CGImageRef 再到 CVPixelBufferRef,但如果你需要实时性能,我在同一个泡菜中(试图弄清楚如何获得 CVPixelBufferRef)
    【解决方案2】:

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

    CG 可以通过 CGImageCreateWithImageInRect() 自己完成此操作

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-08
      • 2013-06-18
      • 2012-08-30
      • 2015-05-05
      • 2020-01-30
      • 1970-01-01
      相关资源
      最近更新 更多