首页 > 解决方案 > 相当于 MacOS 10.13 之前的 MPSImageLanczosScale

问题描述

我正在使用框架MPSImageLanczosScale来缩放图像纹理(从 开始CVPixelBufferRef) 。Metal该问题MPSImageLanczosScale仅从 10.13 开始可用。但我的应用程序从 10.11 开始支持。我不能停止支持较低的操作系统版本,因为仍然有很多用户使用这些版本。有没有其他方法可以使用 Metal(或使用任何其他方式)缩放图像?

注意:我使用的是 Metal,因为我需要基于 GPU 的图像缩放以避免任何 CPU 消耗。所以我正在寻找基于 GPU 的图像缩放解决方案。

包括当前的实现供您参考。

-(CVImageBufferRef)rescaleGPU:(CVImageBufferRef)sourceImageBuffer {
    CVReturn error;

    CGFloat backingScaleFactor = [[NSScreen mainScreen] backingScaleFactor];

    CVMetalTextureRef textureRef;
    error = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _videoTextureCache, sourceImageBuffer, NULL, MTLPixelFormatBGRA8Unorm, g_screenWidth * backingScaleFactor, g_screenHeight * backingScaleFactor, 0, &textureRef);

    id <MTLTexture> _metalTexture = CVMetalTextureGetTexture(textureRef);

    id<MTLTexture> _destinationTexture = [_device newTextureWithDescriptor:self.textureDescriptor];

    id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
    [self.scaleFilter encodeToCommandBuffer:commandBuffer sourceTexture:_metalTexture destinationTexture:_destinationTexture];

    id<MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder];
    [blitEncoder synchronizeTexture:_destinationTexture slice:0 level:0];
    [blitEncoder endEncoding];

    [commandBuffer commit];
    [commandBuffer waitUntilCompleted];
    

    void* destData = malloc(scaleHeight * scaleWidth * 4);

    [_destinationTexture getBytes:destData bytesPerRow:scaleWidth * 4 fromRegion:self.destinationRegion mipmapLevel:0];
    
    CVPixelBufferCreateWithBytes(kCFAllocatorDefault, scaleWidth, scaleHeight, kCVPixelFormatType_32BGRA, destData, scaleWidth * 4, NULL, NULL, NULL, &finalBuffer);

    CVBufferRelease(textureRef);
    [_destinationTexture release];
    free(destData);
    
    return finalBuffer;
}

标签: macosmetalimage-scalingcvpixelbuffer

解决方案


对于没有MPSImageLanczosScale. _ 它的质量会降低,但您不必自行调整大小,也不必放弃未更新其操作系统的现有用户。

使scaleFilter您的班级成员成为类型MPSImageScale*

if (@available(macOS 10.13, *))
{
    self.scaleFilter = [[MPSImageLanczosScale alloc] initWithDevice:device];
}
else 
{
    self.scaleFilter = [[MPSImageBilinearScale alloc] initWithDevice:device];
}

它们具有相同的基本接口MPSUnaryImageKernel,因此您不必更改代码的其他部分,至少据我所知。


推荐阅读