修改CVPixelBuffer绘制内容在macOS 11不生效的代码问题咨询
问题原因
- 像素缓冲区锁定权限错误:你当前使用
.readOnly只读模式锁定像素缓冲区,修改内容的写入操作在macOS 11中会被静默忽略,macOS 12的兼容性处理掩盖了这个错误,导致仅在低版本系统出现无输出问题。 - macOS坐标系翻转设置错误:Core Graphics原生坐标系原点在左下角,而绝大多数绘制逻辑默认遵循左上角原点的规则,你创建
NSGraphicsContext时flipped参数设为false,会导致绘制内容上下翻转,一旦超出可视范围就完全没有可见输出。 - 缺少上下文强制刷新操作:macOS 11不会自动将Core Graphics上下文的绘制内容同步到像素缓冲区的内存中,需要手动调用刷新方法将缓存的绘制操作落地。
- 硬编码像素格式存在兼容风险:你固定了字节序和alpha通道配置,如果输入的CMSampleBuffer像素格式不是BGRA,会导致CGContext创建失败,无法执行绘制。
修复后代码
#if os(macOS) import AppKit #else import UIKit #endif import CoreMedia extension CMSampleBuffer { func pixelBuffer(drawingHandler: ((CGRect) -> Void)? = nil) -> CVPixelBuffer? { guard let pixelBuffer = CMSampleBufferGetImageBuffer(self) else { return nil } guard let drawingHandler = drawingHandler else { return pixelBuffer } // 修改点1:使用读写权限锁定像素缓冲区 guard CVPixelBufferLockBaseAddress(pixelBuffer, []) == kCVReturnSuccess else { return pixelBuffer } let data = CVPixelBufferGetBaseAddress(pixelBuffer) let width = CVPixelBufferGetWidth(pixelBuffer) let height = CVPixelBufferGetHeight(pixelBuffer) let bitsPerComponent = 8 let bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer) let colorSpace = CGColorSpaceCreateDeviceRGB() let imageByteOrderInfo = CGImageByteOrderInfo.order32Little let imageAlphaInfo = CGImageAlphaInfo.premultipliedFirst if let ctx = CGContext(data: data, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: imageByteOrderInfo.rawValue | imageAlphaInfo.rawValue) { // Push #if os(macOS) // 修改点2:flipped设为true,匹配上层绘制的左上角坐标系习惯 let graphCtx = NSGraphicsContext(cgContext: ctx, flipped: true) NSGraphicsContext.saveGraphicsState() NSGraphicsContext.current = graphCtx #else UIGraphicsPushContext(ctx) #endif let rect = CGRect(x: 0, y: 0, width: width, height: height) drawingHandler(rect) // 修改点3:强制刷新上下文,将绘制内容同步到像素缓冲区 ctx.flush() // Pop #if os(macOS) NSGraphicsContext.restoreGraphicsState() #else UIGraphicsPopContext() #endif } // 修改点4:解锁参数对应修改为读写模式 CVPixelBufferUnlockBaseAddress(pixelBuffer, []) return pixelBuffer } }
注:如果需要兼容不同像素格式的CMSampleBuffer,可以通过
CVPixelBufferGetPixelFormatType获取实际像素格式,动态调整CGContext的bitmapInfo配置,避免硬编码导致的上下文创建失败问题。
内容的提问来源于stack exchange,提问作者scchn
相关产品推荐
相关产品推荐

