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

17 篇文章 0 订阅
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
}

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]

那么在做 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)
        }

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

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

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

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是使用libyuv将NV21数据转换为BGRA8888格式的C代码示例: ```c #include "libyuv.h" void NV21ToBGRA(const uint8_t* src_y, int src_stride_y, const uint8_t* src_vu, int src_stride_vu, uint8_t* dst_bgra, int dst_stride_bgra, int width, int height) { libyuv::NV21ToARGB(src_y, src_stride_y, src_vu, src_stride_vu, dst_bgra, dst_stride_bgra, width, height); } ``` 其中,参数说明如下: - `src_y`:指向NV21数据中Y分量的指针。 - `src_stride_y`:Y分量的步长。 - `src_vu`:指向NV21数据中VU分量的指针。 - `src_stride_vu`:VU分量的步长。 - `dst_bgra`:指向转换后数据的指针。 - `dst_stride_bgra`:转换后数据的步长。 - `width`:图像宽度。 - `height`:图像高度。 调用示例: ```c int main() { uint8_t* src_y = ...; // 初始化NV21数据中Y分量 uint8_t* src_vu = ...; // 初始化NV21数据中VU分量 uint8_t* dst_bgra = ...; // 初始化目标数据 int width = ...; // 初始化图像宽度 int height = ...; // 初始化图像高度 int src_stride_y = width; int src_stride_vu = width; int dst_stride_bgra = width * 4; // BGRA8888格式,每像素4字节 NV21ToBGRA(src_y, src_stride_y, src_vu, src_stride_vu, dst_bgra, dst_stride_bgra, width, height); return 0; } ``` 注意,以上代码是使用libyuv库进行NV21到BGRA8888格式转换的一个简单示例,实际使用时需要根据具体需求进行调整。同时,需要在编译时链接libyuv库,以便使用其中的函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值