I am doing something similar to this post
Within an AVCaptureDataOutputSynchronizerDelegate method, I create a pixelBuffer using CVPixelBufferCreate with the following attributes: kCVPixelBufferIOSurfacePropertiesKey as String: true, kCVPixelBufferIOSurfaceOpenGLESTextureCompatibilityKey as String: true
When I copy the data from the vImagePixelBuffer "rotatedImageBuffer", I get the following error:
Thread 10: EXC_BAD_ACCESS (code=1, address=0x14caa8000)
I get the same error with memcpy and data.copyBytes (not running them at the same time obviously).
If I use CVPixelBufferCreateWithBytes, I do not get this error. However, CVPixelBufferCreateWithBytes does not let you include attributes (see linked post above).
I am using vImage because I need the original CVPixelBuffer from the camera output and a rotated version with a different color scheme.
// Copy to pixel buffer
let attributes: NSDictionary = [
true : kCVPixelBufferIOSurfacePropertiesKey,
true : kCVPixelBufferIOSurfaceOpenGLESTextureCompatibilityKey,
]
var colorBuffer: CVPixelBuffer?
let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(rotatedImageBuffer.width), Int(rotatedImageBuffer.height), kCVPixelFormatType_32BGRA, attributes, &colorBuffer)
//let status = CVPixelBufferCreateWithBytes(kCFAllocatorDefault, Int(rotatedImageBuffer.width), Int(rotatedImageBuffer.height), kCVPixelFormatType_32BGRA, rotatedImageBuffer.data, rotatedImageBuffer.rowBytes, nil, nil, attributes as CFDictionary, &colorBuffer) // does NOT produce error, but also does not have attributes
guard status == kCVReturnSuccess, let colorBuffer = colorBuffer else {
print("Failed to create buffer")
return
}
let lockFlags = CVPixelBufferLockFlags(rawValue: 0)
guard kCVReturnSuccess == CVPixelBufferLockBaseAddress(colorBuffer, lockFlags) else {
print("Failed to lock base address")
return
}
let colorBufferMemory = CVPixelBufferGetBaseAddress(colorBuffer)!
let data = Data(bytes: rotatedImageBuffer.data, count: rotatedImageBuffer.rowBytes * Int(rotatedImageBuffer.height))
data.copyBytes(to: colorBufferMemory.assumingMemoryBound(to: UInt8.self), count: data.count) // Fails here
//memcpy(colorBufferMemory, rotatedImageBuffer.data, rotatedImageBuffer.rowBytes * Int(rotatedImageBuffer.height)) // Also produces the same error
CVPixelBufferUnlockBaseAddress(colorBuffer, lockFlags)
Found an answer - CVPixelBufferCreate isn't that efficient so it runs on a few frames and then crashes.
You can include attributes using a CVPixelBufferPool, which apparently is designed for streaming frames and managing the buffers in memory
Also realized the format for the attributes dictionary was wrong
private var colorPixelBufferPool: CVPixelBufferPool!
private var pixelBufferPool_isPrepared = false
...
// within delegate
if !pixelBufferPool_isPrepared {
var videoDescription: CMFormatDescription
do {
videoDescription = try CMVideoFormatDescription(imageBuffer: videoBuffer)
} //videoBuffer is the original CVPixelBuffer
catch {
print("Failed video description")
return
}
let inputDimensions = CMVideoFormatDescriptionGetDimensions(videoDescription)
let outputPixelBufferAttributes: [String: Any] = [
kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA,
kCVPixelBufferWidthKey as String: Int(inputDimensions.height), // rotated 90 degrees
kCVPixelBufferHeightKey as String: Int(inputDimensions.width), // rotated 90 degrees
kCVPixelBufferIOSurfaceOpenGLESTextureCompatibilityKey as String: true,
kCVPixelBufferIOSurfacePropertiesKey as String: [:]
]
let poolAttributes = [kCVPixelBufferPoolMinimumBufferCountKey as String: 2]
var cvPixelBufferPool: CVPixelBufferPool?
// Create a pixel buffer pool with the same pixel attributes as the input format description
CVPixelBufferPoolCreate(kCFAllocatorDefault, poolAttributes as NSDictionary?, outputPixelBufferAttributes as NSDictionary?, &cvPixelBufferPool)
guard let pixelBufferPool = cvPixelBufferPool else {
assertionFailure("Allocation failure: Could not create pixel buffer pool")
return
}
colorPixelBufferPool = pixelBufferPool
pixelBufferPool_isPrepared = true
}
...
// let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(rotatedBuffer.width), Int(rotatedBuffer.height), kCVPixelFormatType_32BGRA, attributes, &colorBuffer) // throws error eventually, not efficient
let status = CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, colorPixelBufferPool!, &colorBuffer) // works!