I am creating id<MTLTexture> object from CVPixelBufferRef the following way:
id<MTLTexture> CreateMTLTexrure(CVMetalTextureCacheRef texture_cache,
CVPixelBufferRef pixel_buffer,
MTLPixelFormat metal_pixel_format, size_t plane,
int height, int width) {
CVMetalTextureRef texture_ref;
CVReturn err = CVMetalTextureCacheCreateTextureFromImage(
kCFAllocatorDefault, texture_cache, pixel_buffer, NULL,
metal_pixel_format, width, height, plane, &texture_ref);
if (err != kCVReturnSuccess) {
// throw error
return nil;
}
id<MTLTexture> texture = CVMetalTextureGetTexture(texture_ref);
//
// Q: is it safe to do CVBufferRelease(texture_ref) here?
//
return texture;
}
When CVMetalTextureRef object should be released? Is it safe to release it after MTLTexture is obtained?
Yes it is safe. According to this sample code from Apple Documentation Archive, it is released right after it was assigned, like so:
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
CVReturn error;
CVImageBufferRef sourceImageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
size_t width = CVPixelBufferGetWidth(sourceImageBuffer);
size_t height = CVPixelBufferGetHeight(sourceImageBuffer);
CVMetalTextureRef textureRef;
error = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _videoTextureCache, sourceImageBuffer, NULL, MTLPixelFormatBGRA8Unorm, width, height, 0, &textureRef);
if (error)
{
NSLog(@">> ERROR: Couldnt create texture from image");
assert(0);
}
_videoTexture[_constantDataBufferIndex] = CVMetalTextureGetTexture(textureRef);
if (!_videoTexture[_constantDataBufferIndex]) {
NSLog(@">> ERROR: Couldn't get texture from texture ref");
assert(0);
}
CVBufferRelease(textureRef);
}
You could also look at the WebRTC source code from Google Chromium repository, they also release CVMetalTextureRef the same way.
- (BOOL)setupTexturesForFrame:(nonnull RTCVideoFrame *)frame {
RTC_DCHECK([frame.buffer isKindOfClass:[RTCCVPixelBuffer class]]);
if (![super setupTexturesForFrame:frame]) {
return NO;
}
CVPixelBufferRef pixelBuffer = ((RTCCVPixelBuffer *)frame.buffer).pixelBuffer;
id<MTLTexture> lumaTexture = nil;
id<MTLTexture> chromaTexture = nil;
CVMetalTextureRef outTexture = nullptr;
// Luma (y) texture.
int lumaWidth = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0);
int lumaHeight = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0);
int indexPlane = 0;
CVReturn result = CVMetalTextureCacheCreateTextureFromImage(
kCFAllocatorDefault, _textureCache, pixelBuffer, nil, MTLPixelFormatR8Unorm, lumaWidth,
lumaHeight, indexPlane, &outTexture);
if (result == kCVReturnSuccess) {
lumaTexture = CVMetalTextureGetTexture(outTexture);
}
// Same as CFRelease except it can be passed NULL without crashing.
CVBufferRelease(outTexture);
outTexture = nullptr;
// Chroma (CrCb) texture.
indexPlane = 1;
result = CVMetalTextureCacheCreateTextureFromImage(
kCFAllocatorDefault, _textureCache, pixelBuffer, nil, MTLPixelFormatRG8Unorm, lumaWidth / 2,
lumaHeight / 2, indexPlane, &outTexture);
if (result == kCVReturnSuccess) {
chromaTexture = CVMetalTextureGetTexture(outTexture);
}
CVBufferRelease(outTexture);
if (lumaTexture != nil && chromaTexture != nil) {
_yTexture = lumaTexture;
_CrCbTexture = chromaTexture;
return YES;
}
return NO;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With