• kCVPixelFormatType_32BGRA 格式的CMSampleBuffer sampebuffer 如何转化为 AVFrame


    import CoreMedia
    import libavutil
    import libavcodec
    
    func convertSampleBufferToAVFrame(_ sampleBuffer: CMSampleBuffer) -> AVFrame? {
        guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
            print("Failed to get pixel buffer from sample buffer.")
            return nil
        }
        
        // Lock the pixel buffer
        CVPixelBufferLockBaseAddress(pixelBuffer, [])
        
        let width = CVPixelBufferGetWidth(pixelBuffer)
        let height = CVPixelBufferGetHeight(pixelBuffer)
        let bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer)
        
        // Allocate an AVFrame and set its properties
        let frame = av_frame_alloc()!
        frame.pointee.format = AV_PIX_FMT_BGRA // Pixel format for 32BGRA
        frame.pointee.width = Int32(width)
        frame.pointee.height = Int32(height)
        
        // Allocate buffer for the frame data
        av_frame_get_buffer(frame, 0)
        
        // Copy data from the pixel buffer to the AVFrame
        let baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer)!.assumingMemoryBound(to: UInt8.self)
        for i in 0..<height {
            let src = baseAddress + i * bytesPerRow
            let dest = frame.pointee.data[0]! + i * frame.pointee.linesize[0]
            memcpy(dest, src, bytesPerRow)
        }
        
        // Unlock the pixel buffer
        CVPixelBufferUnlockBaseAddress(pixelBuffer, [])
        
        return frame
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    AV_PIX_FMT_BGRA 格式 AVFrame 的data 数据 如何存储分布的

    FFmpeg中,每种像素格式都由AVPixelFormat枚举表示。对于AV_PIX_FMT_BGRA像素格式:
    
    BGRA 分别代表蓝色、绿色、红色和Alpha(透明度)。
    AV_PIX_FMT_BGRA格式指定像素以BGRA的方式紧密存储。这意味着每个像素有4个字节:蓝色1字节,绿色1字节,红色1字节,和Alpha 1字节。
    在AVFrame结构中,data成员是指向实际图像数据平面的指针数组。由于AV_PIX_FMT_BGRA是打包的(不是平面的),所有数据都将在data[0]中。
    
    内存中的布局如下:
    
    Copy code
    B1, G1, R1, A1, B2, G2, R2, A2, B3, G3, R3, A3, ...
    其中B1、G1、R1 和 A1 代表第一个像素的蓝色、绿色、红色和Alpha值;B2、G2、R2 和 A2 代表第二个像素,依此类推。
    
    AVFrame的linesize成员表示每个平面每行的字节数。对于像AV_PIX_FMT_BGRA这样的打包格式,linesize[0]通常是宽度 * 每像素的字节数(对于BGRA,每像素是4字节)。但是,由于内存对齐或填充的考虑,实际的linesize[0]可能大于宽度 * 4。在导航数据中的行时,总是使用AVFrame中的linesize[0]
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    那么在做 smaplebuffer 转 AVFrame 的时候 为什么使用了

     // Use Swift's UnsafePointer for data copying
            for i in 0..<height {
                let src = baseAddress + i * bytesPerRow
                let dest = frame!.pointee.data.0! + i * Int(frame!.pointee.linesize.0)
                memcpy(dest, src, bytesPerRow)
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这个样的拷贝方式 而不是直接将 samplebuffe 的data 拷贝给 frame data.0 呢?

    这是因为图像数据在内存中不一定是连续存储的,特别是当图像的宽度不是内存对齐的倍数时。为了提高内存访问性能,图像每行的末尾可能会有一些填充字节,使得每行都对齐到某个字节边界(如4字节或8字节边界)。

    bytesPerRow是指示CMSampleBuffer中每行的真实字节数量。它可能等于图像宽度乘以每像素的字节数(对于BGRA是4字节),也可能更大,取决于是否有填充字节。

    frame!.pointee.linesize.0是AVFrame中每行的字节数量。它也可能包含填充字节,因此可能与图像的宽度乘以4不同。

    由于这两者可能不相等(尤其是在宽度不是对齐的倍数时),我们不能只简单地拷贝整块数据。而是需要逐行拷贝数据,确保每行的数据都被正确地复制到AVFrame中。

    简而言之,逐行拷贝是为了确保正确处理任何可能存在的行填充,并确保AVFrame的数据布局与CMSampleBuffer匹配

  • 相关阅读:
    ESP8266--Arduino开发(PWM)
    每日一题 2591. 将钱分给最多的儿童
    感悟“驱动力“
    语法糖
    微信红包封面小程序源码-后台独立版-带测评积分功能源码
    Spring Boot 配置读取顺序 apollo 配置读取顺序
    聊聊如何利用springcloud gateway实现简易版灰度路由
    Ubuntu工控机CAN卡驱动安装(手动安装)
    springboot整合log4j2
    多进程编程(三):消息队列
  • 原文地址:https://blog.csdn.net/Sico2Sico/article/details/133134806