Skip to content

Instantly share code, notes, and snippets.

@T1T4N
Last active November 7, 2023 15:29
Show Gist options
  • Save T1T4N/0ae90716b0c5d1bea39efe94512e1b72 to your computer and use it in GitHub Desktop.
Save T1T4N/0ae90716b0c5d1bea39efe94512e1b72 to your computer and use it in GitHub Desktop.
A format-agnostic way of converting CVPixelBuffer to Data and back
extension CVPixelBuffer {
public static func from(_ data: Data, width: Int, height: Int, pixelFormat: OSType) -> CVPixelBuffer {
data.withUnsafeBytes { buffer in
var pixelBuffer: CVPixelBuffer!
let result = CVPixelBufferCreate(kCFAllocatorDefault, width, height, pixelFormat, nil, &pixelBuffer)
guard result == kCVReturnSuccess else { fatalError() }
CVPixelBufferLockBaseAddress(pixelBuffer, [])
defer { CVPixelBufferUnlockBaseAddress(pixelBuffer, []) }
var source = buffer.baseAddress!
for plane in 0 ..< CVPixelBufferGetPlaneCount(pixelBuffer) {
let dest = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, plane)
let height = CVPixelBufferGetHeightOfPlane(pixelBuffer, plane)
let bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, plane)
let planeSize = height * bytesPerRow
memcpy(dest, source, planeSize)
source += planeSize
}
return pixelBuffer
}
}
}
extension Data {
public static func from(pixelBuffer: CVPixelBuffer) -> Self {
CVPixelBufferLockBaseAddress(pixelBuffer, [.readOnly])
defer { CVPixelBufferUnlockBaseAddress(pixelBuffer, [.readOnly]) }
// Calculate sum of planes' size
var totalSize = 0
for plane in 0 ..< CVPixelBufferGetPlaneCount(pixelBuffer) {
let height = CVPixelBufferGetHeightOfPlane(pixelBuffer, plane)
let bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, plane)
let planeSize = height * bytesPerRow
totalSize += planeSize
}
guard let rawFrame = malloc(totalSize) else { fatalError() }
var dest = rawFrame
for plane in 0 ..< CVPixelBufferGetPlaneCount(pixelBuffer) {
let source = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, plane)
let height = CVPixelBufferGetHeightOfPlane(pixelBuffer, plane)
let bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, plane)
let planeSize = height * bytesPerRow
memcpy(dest, source, planeSize)
dest += planeSize
}
return Data(bytesNoCopy: rawFrame, count: totalSize, deallocator: .free)
}
}
@T1T4N
Copy link
Author

T1T4N commented Sep 8, 2022

@ufogxl Sorry for confusing title, this is snippet is intended for planar pixel data, such as this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment