I'm making a video with transparent background using HEVC with alpha, based on a bunch of NSImage
s, a CVPixelBuffer
pool and AVAssetWriter
. The NSImage
s are rendered by an SCNRenderer
's [snapshot][1]
method.
To turn the NSImage
s into CVPixelbuffer
s so I can append them to the pool, I first get a new pixel buffer from the pool, then use this code
CVPixelBufferLockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer)
let colorSpace = CGColorSpaceCreateDeviceRGB()
guard let context = CGContext(
data: pixelData,
width: Int(image.size.width),
height: Int(image.size.height),
bitsPerComponent: 8,
bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer),
space: colorSpace,
bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue
)
else { return }
let graphicsContext = NSGraphicsContext(cgContext: context, flipped: false)
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.current = graphicsContext
image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
NSGraphicsContext.restoreGraphicsState()
CVPixelBufferUnlockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
In the exported movie, the colors look good, and the transparency kicks in fine.
But all the frames are added on top of each other, as in the example below.
SIDE NOTE: The weird thing is that if I obtain the pixel buffer with Metal (using the SCNRenderer's render
method), but leave everything else as is, it works fine. That's why I'm suspecting that it might be my CGContext
that is acting up. Why don't I just use Metal, then? Would love to, but I can't get antialiasing.