Skip to content

Instantly share code, notes, and snippets.

@T1T4N
Last active November 7, 2023 15:29
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • 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.

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