You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 03:36:03