Skip to content

Instantly share code, notes, and snippets.

@T1T4N
Last active October 2, 2025 10:06
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)
}
}
@ufogxl
Copy link

ufogxl commented Jun 19, 2022

great but at #14

 for plane in 0 ..< CVPixelBufferGetPlaneCount(pixelBuffer) {
}

seems won't enter

@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.

@seyoung-hyun
Copy link

Thanks your code :)
Can I use your code in my commercial app?

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