c++ - OSX MetalKit CVMetalTextureCacheCreateTextureFromImage失败,状态:-6660

标签 c++ macos macos-high-sierra metalkit core-video

我正在尝试首先从 RAW 内存中制作CVPixelBuffer然后是MTLTexture中的CVPixelBuffer,但是
运行以下代码后,我总是出错

CVMetalTextureCacheCreateTextureFromImage failed, status: -6660 0x0



这个错误是从哪里来的?
    id<MTLTexture> makeTextureWithBytes(id<MTLDevice> mtl_device, 
                                        int width, 
                                        int height, 
                                        void *baseAddress, int bytesPerRow)
    {

    CVMetalTextureCacheRef textureCache = NULL;

    CVReturn status = CVMetalTextureCacheCreate(kCFAllocatorDefault, nullptr, mtl_device, nullptr, &textureCache);
    if(status != kCVReturnSuccess || textureCache == NULL)
    {
        return nullptr;
    }

    NSDictionary* cvBufferProperties = @{
        (__bridge NSString*)kCVPixelBufferOpenGLCompatibilityKey : @YES,
        (__bridge NSString*)kCVPixelBufferMetalCompatibilityKey : @YES,
    };

    CVPixelBufferRef pxbuffer = NULL;

    status = CVPixelBufferCreateWithBytes(kCFAllocatorDefault,
                                          width,
                                          height,
                                          kCVPixelFormatType_32BGRA,
                                          baseAddress,
                                          bytesPerRow,
                                          releaseCallback,
                                          NULL/*releaseRefCon*/,
                                          (__bridge CFDictionaryRef)cvBufferProperties,
                                          &pxbuffer);

    if(status != kCVReturnSuccess || pxbuffer == NULL)
    {
        return nullptr;
    }

    CVMetalTextureRef cvTexture = NULL;   

    status = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
                                                       textureCache,
                                                       pxbuffer,
                                                       nullptr,
                                                       MTLPixelFormatBGRA8Unorm,
                                                       1920,
                                                       1080,
                                                       0,
                                                       &cvTexture);

    if(status != kCVReturnSuccess || cvTexture == NULL)
    {
        std::cout << "CVMetalTextureCacheCreateTextureFromImage failed, status: " << status << " " << cvTexture << std::endl;
        return nullptr;
    }
    id<MTLTexture> metalTexture = CVMetalTextureGetTexture(cvTexture);

    CFRelease(cvTexture);

    return metalTexture;
}

最佳答案

IOSurface不支持CVPixelBuffer时,会发生错误。但是,您不能从字节制作IOSurface支持的CVPixelBuffer。因此,尽管设置了kCVPixelBufferMetalCompatibilityKey,但CVPixelBufferCreateWithBytes(及其平面对应项)仍不会使用IOSurface支持缓冲区。

两种解决方法(可能的第三种)

  • 创建一个空的CVpixelBuffer并使用memcpy。您需要在每个循环中创建一个新的pixelbuffer,因此建议使用PixelBufferPool。
  • CVPixelBufferPoolRef pixelPool; // initialised prior
    void *srcBaseAddress;  // initialised prior
    
    CVPixelBufferRef currentFrame; 
    CVPixelBufferPoolCreatePixelBuffer(nil, pixelPool, &currentFrame);
    
    CVPixelBufferLockBaseAddress(currentFrame,0);
    void *cvBaseAddress=CVPixelBufferGetBaseAddress(currentFrame);
    size_t size= CVPixelBufferGetDataSize(currentFrame);
    memcpy(cvBaseAddress,srcBaseAddress,size);
    
  • 完全跳过CVPixelBuffer并直接写入MTLTexture内存;只要金属支持您的像素格式。但是,由于可能要渲染为RGB显示,因此可以编写自己的金属内核以转换为RGB。请记住首先使用metalTextureDescriptor制作纹理。
  • id<MTLDevice> metalDevice; // You know how to get this
    unsigned int width; // from your source image data
    unsigned int height;// from your source image data
    unsigned int rowBytes; // from your source image data
    
    MTLTextureDescriptor *mtd = [MTLTextureDescriptor 
    texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRG422 
            width:width
            height:height
            mipmapped:NO];
    
    id<MTLTexture> mtlTexture = [metalDevice newTextureWithDescriptor:mtd];
    
    
    [mtlTexture replaceRegion:MTLRegionMake2D(0,0,width,height) 
            mipmapLevel:0
            withBytes:srcBaseAddress
            bytesPerRow:rowBytes];
    

    第三种方法可能是将CVPixelBuffer转换为CIImage,并使用金属支持的CIContext。像这样的东西;
    id<MTLDevice> metalDevice;
    CIContext* ciContext = [CIContext contextWithMTLDevice:metalDevice
            options:[NSDictionary dictionaryWithObjectsAndKeys:@(NO),kCIContextUseSoftwareRenderer,nil]
        ];
    CIImage *inputImage = [[CIImage alloc] initWithCVPixelBuffer:currentFrame];
    
    [ciContext render:inputImage 
        toMTLTexture:metalTexture 
        commandBuffer:metalCommandBuffer
        bounds:viewRect
        colorSpace:colorSpace];
    

    我成功地使用它来直接渲染到CAMetalLayer的可绘制纹理,但是没有足够的运气来渲染中间纹理(不是我非常努力地使其工作),希望其中的一项对您有用。

    关于c++ - OSX MetalKit CVMetalTextureCacheCreateTextureFromImage失败,状态:-6660,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60303458/

    相关文章:

    c++ - 如何消除警告 LNK4221?

    objective-c - 卡住和恢复 Cocoa 任务或线程?

    python - macOS Sierra/Python2.7.13 URLError : <urlopen error EOF occurred in violation of protocol (_ssl. c:661)>

    c++ - MacOS High Sierra : make: no rule to make target 上的 Cassandra C++ 驱动程序

    macos - 如果从今年开始停产,如何使用 Homebrew 软件安装php 5.6?

    c++ - 查找摊销时间复杂度

    c++ - 如何使用 Visual Studio 2012 和 Windows SDK 7.1 编译 VC++ 2010 项目

    c++ - 某些输入的 Bison/Flex 奇怪结果

    ruby-on-rails - 电源服务器 : serving external domain via POW_EXT_DOMAINS

    更新 macOS 后 Xcode 更新卡住