CVMetalTextureCacheCreateTextureFromImage 在 macOS 10.13 上返回 -6660
Posted
技术标签:
【中文标题】CVMetalTextureCacheCreateTextureFromImage 在 macOS 10.13 上返回 -6660【英文标题】:CVMetalTextureCacheCreateTextureFromImage returns -6660 on macOS 10.13 【发布时间】:2018-03-14 23:08:48 【问题描述】:我正在将屏幕从我的 iPhone 设备录制到我的 Mac。作为预览层,我直接从AVCaptureVideoDataOutput
收集样本缓冲区,从中创建纹理并使用Metal
渲染它们。我遇到的问题是在10.13
之前在macOS 中工作的代码在更新到10.13
后停止工作。即,
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(_currentSampleBuffer);
if (!imageBuffer) return;
CVPixelBufferLockBaseAddress(imageBuffer,0);
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
CVMetalTextureRef metalTexture = NULL;
CVReturn result = CVMetalTextureCacheCreateTextureFromImage(nil,
self.textureCache,
imageBuffer,
nil,
self.pixelFormat,
width,
height,
0,
&metalTexture);
if (result == kCVReturnSuccess)
self.texture = CVMetalTextureGetTexture(metalTexture);
返回result = -6660
,转换为通用kCVReturnError
,如on the official Apple docs和metalTexture = NULL
所示。
我使用的像素格式是MTLPixelFormatBGRG422
,因为来自相机的样本是2vuy
。
作为从sampleBuffer
创建metalTexture
的解决方法,我现在
像这样创建一个中间 NSImage
:
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(_currentSampleBuffer);
NSCIImageRep *imageRep = [NSCIImageRep imageRepWithCIImage:[CIImage imageWithCVImageBuffer:imageBuffer]];
NSImage *image = [[NSImage alloc] initWithSize:[imageRep size]];
[image addRepresentation:imageRep];
并从中创建一个MTLTexture
。这显然是直接使用CVMetalTextureCacheCreateTextureFromImage
的低劣解决方案。
再一次,有问题的代码在macOS < 10.13
中运行良好,我想知道是否有人有类似的问题,如果有,你有什么想法可以解决这个问题吗?
【问题讨论】:
【参考方案1】:我遇到了同样的问题,问题是在配置 AVCaptureVideoDataOutput
时没有要求金属兼容性。我猜系统开始在 macOS 10.13 中检查这一点,可能会在未请求时应用一些优化。
解决方案是将kCVPixelBufferMetalCompatibilityKey
添加到AVCaptureVideoDataOutput
的videoSettings
属性中。
在 Objective-C 中:
outputCapture.videoSettings = @
/* ... */
(NSString *)kCVPixelBufferMetalCompatibilityKey: @YES
;
在斯威夫特中:
outputCapture.videoSettings = [
/* ... */
kCVPixelBufferMetalCompatibilityKey as String: true
]
我认为这需要雷达,要求 Apple 在发生这种情况时至少打印一条警告消息。如果我得到它,我会更新它。
【讨论】:
太棒了,这行得通!我现在需要检查像素缓冲区中的输出格式,因为我得到了一个分割图像和奇怪的颜色。我将在另一个答案中发布我的解决方法以供将来参考。 谢谢!这对我有帮助,因为它也适用于您制作自己的 CVPixelBuffer 时:CVPixelBufferCreate
通过添加到属性字典:let attrs = [kCVPixelBufferMetalCompatibilityKey: kCFBooleanTrue, ...<others>... ] as CFDictionary
如果您按照本技术说明中的说明使用CVPixelBufferCreateWithBytes
或CVPixelBufferCreateWithPlanarBytes
创建了您的cvpixelbuffer,这将不起作用; developer.apple.com/library/archive/qa/qa1781/_index.html设置密钥无效。
EliaCereda 谢谢你,它帮助了我。【参考方案2】:
我找到了一个解决方法,它将2vuy
格式保留在像素缓冲区中,但不好的是您制作了影响性能的像素缓冲区数据的副本。我将其发布以供将来参考,或者如果其他人发现它有用。基本上我们拦截像素缓冲区,然后在复制数据时添加属性。
NSDictionary *attributes = @
@"iosurfaceCoreAnimationCompatibility": @YES
;
CVPixelBufferRef copy = NULL;
CVPixelBufferCreate(kCFAllocatorDefault,
CVPixelBufferGetWidth(pixelBuffer),
CVPixelBufferGetHeight(pixelBuffer),
CVPixelBufferGetPixelFormatType(pixelBuffer),
(__bridge CFDictionaryRef)attributes,
©);
CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
CVPixelBufferLockBaseAddress(copy, 0);
void *baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer);
void *copyBaseAddress = CVPixelBufferGetBaseAddress(copy);
memcpy(copyBaseAddress, baseAddress, CVPixelBufferGetDataSize(pixelBuffer));
CVPixelBufferUnlockBaseAddress(copy, 0);
CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
【讨论】:
【参考方案3】:另一种从CVPixelBufferRef
获得金属纹理的方法,您可以通过CIImage
并在金属设备上使用CIContext
(希望最大限度地减少 CPU 参与复制像素缓冲区);
确保您的目标金属纹理大小合适。
CIContext* ciContext = [CIContext contextWithMTLDevice:mtlDevice
options:[NSDictionary dictionaryWithObjectsAndKeys:@(NO),kCIContextUseSoftwareRenderer,nil]
];
id<MTLCommandBuffer> metalCommandBuffer=[mtlCommandQueue commandBufferWithUnretainedReferences];
CIImage* ciImage = [[CIImage alloc] initWithCVPixelBuffer:cvPixelBuffer];
[ciContext render:ciImage
toMTLTexture:metal_texture
commandBuffer:mtlCommandBuffer
bounds:[ciImage extent])
colorSpace:[ciImage colorSpace]];
【讨论】:
以上是关于CVMetalTextureCacheCreateTextureFromImage 在 macOS 10.13 上返回 -6660的主要内容,如果未能解决你的问题,请参考以下文章