I'm using CVPixelBufferCreateWithBytes(_:_:_:_:_:_:_:_:_:_:) to read a 24-bit BMP from disk:
var data = try! Data(contentsOf: url.appendingPathExtension(for: .bmp))
data.withUnsafeMutableBytes { (unsafeMutableRawBufferPointer: UnsafeMutableRawBufferPointer) in
var pixelBuffer: CVPixelBuffer?
CVPixelBufferCreateWithBytes(
kCFAllocatorDefault,
imageWidth,
imageHeight,
kCVPixelFormatType_24RGB,
unsafeMutableRawBufferPointer.baseAddress!,
bytesPerRow,
nil, nil, nil,
&pixelBuffer
)
}
I need to convert it to JPEG, but all the methods I've tried leak, i.e.:
try! UIImage(ciImage: CIImage(cvPixelBuffer: pixelBuffer!))
.jpegData(compressionQuality: 0.0)!
.write(to: someUrl)
and:
try! CIContext().writeJPEGRepresentation(
of: CIImage(cvPixelBuffer: pixelBuffer!),
to: someUrl,
colorSpace: CGColorSpaceCreateDeviceRGB()
)
autoreleasepool doesn't help:
autoreleasepool {
var pixelBuffer: CVPixelBuffer?
CVPixelBufferCreateWithBytes(
kCFAllocatorDefault,
imageWidth,
imageHeight,
kCVPixelFormatType_24RGB,
unsafeMutableRawBufferPointer.baseAddress!,
bytesPerRow,
nil, nil, nil,
&pixelBuffer
)
try! UIImage(ciImage: CIImage(cvPixelBuffer: pixelBuffer!))
.jpegData(compressionQuality: 0.0)!
.write(to: someUrl)
}
And none of the *Release methods are available, they produce compiler errors like: 'CFRelease' is unavailable: Core Foundation objects are automatically memory managed.
The issue seems to be the pointer gets retained when any of the JPEG-related methods get called. This leaks:
let uiImage = UIImage(ciImage: CIImage(cvPixelBuffer: pixelBuffer!))
.jpegData(compressionQuality: 0.0)!
But this doesn't:
let uiImage = UIImage(ciImage: CIImage(cvPixelBuffer: pixelBuffer!))
Same with Core Image. This doesn't leak:
CIContext().createCGImage(CIImage(cvPixelBuffer: pixelBuffer!), from: CGRect(x: 0, y: 0, width: imageWidth, height: imageHeight))
But this does:
CIContext().writeJPEGRepresentation(
of: CIImage(cvPixelBuffer: pixelBuffer!),
to: someUrl,
colorSpace: CGColorSpaceCreateDeviceRGB()
)
I guess I need to release the memory by passing CVPixelBufferReleaseBytesCallback to seems to CVPixelBufferCreateWithBytes, but it's not clear to me how to use it in this case. Most examples suggests doing something like:
let releaseCallBack: CVPixelBufferReleaseBytesCallback = { _, pointer in
if let pointer = pointer {
free(UnsafeMutableRawPointer(mutating: pointer))
}
}
But it makes the autoreleasepool call to throw because it's trying to free memory that's not there any more, and removing it makes other objects to keep leaking. Manually calling deallocate on the point doesn't help either