4. RAW图格式详解:Bayer Pattern、位深打包与MIPI数据包解析

在Camera驱动开发中,RAW图是图像传感器最原始的“底片”。理解RAW图的格式,是正确配置DMA控制器、解析MIPI数据流以及进行后续ISP处理的前提。本章将深入剖析Bayer Pattern的排列逻辑、RAW10/RAW12的打包方式以及MIPI CSI-2数据包的结构。

4.1 Bayer Pattern:色彩世界的起点

绝大多数CMOS图像传感器使用Bayer滤色阵列来捕捉彩色信息。每个像素只记录红、绿、蓝中的一种颜色分量,通过特定的排列模式来模拟全彩视觉。最常见的模式是RGGB和GRBG。

核心概念: 每个像素的原始数据仅代表一种颜色分量,必须通过去马赛克算法插值出缺失的另外两个颜色分量,才能生成完整的RGB图像。

4.1.1 常见Bayer Pattern对比

Pattern 排列顺序(2x2单元) 常见应用场景 特点
RGGB 第一行:R G R G ...
第二行:G B G B ...
Sony、OmniVision等主流传感器 绿色像素数量是红/蓝的两倍,模拟人眼对绿色更敏感的特性
GRBG 第一行:G R G R ...
第二行:B G B G ...
部分Samsung、Onsemi传感器 与RGGB相比,绿色像素位置偏移,影响ISP的插值方向
BGGR 第一行:B G B G ...
第二行:G R G R ...
部分老式或特定传感器 与RGGB互为镜像,驱动配置时需注意
GBRG 第一行:G B G B ...
第二行:R G R G ...
较少见,特定定制传感器 与GRBG类似,但绿色和蓝色位置互换
调试提示: 在驱动中配置Bayer Pattern时,务必与传感器数据手册严格对齐。错误的Pattern配置会导致ISP输出的图像出现严重的颜色错乱(如绿色草地变成紫色)。

4.1.2 Bayer Pattern结构示意图

下图展示了RGGB和GRBG两种最常见模式的2x2像素单元结构。每个方格代表一个物理像素,字母代表该像素上覆盖的滤色片颜色。

Bayer Pattern 结构对比 RGGB Pattern R G G B Row 0 Row 1 GRBG Pattern G R B G Row 0 Row 1 注意:绿色像素数量是红/蓝的两倍,这是Bayer Pattern的核心特征。 驱动配置时,需根据传感器手册选择正确的Pattern枚举值。

4.2 RAW位深与打包格式

RAW数据的位深决定了每个像素的动态范围。常见的位深有RAW10(10-bit)和RAW12(12-bit)。由于MIPI CSI-2传输和DMA存储通常以字节(8-bit)为单位,因此需要特定的打包格式来高效存储这些非8-bit对齐的数据。

4.2.1 RAW10 打包格式

RAW10每个像素占用10-bit数据。为了在8-bit的字节流中传输,通常采用4像素打包成5字节的方式。这种格式称为“RAW10 Packed”。

  • 存储效率: 100%(无浪费字节)。
  • 打包规则: 4个像素(P0, P1, P2, P3)的10-bit数据,按位拼接成5个字节(B0, B1, B2, B3, B4)。
  • 位分布:
    • B0 = P0[9:2](高8位)
    • B1 = P1[9:2](高8位)
    • B2 = P2[9:2](高8位)
    • B3 = P3[9:2](高8位)
    • B4 = {P3[1:0], P2[1:0], P1[1:0], P0[1:0]}(每个像素的低2位,共8位)
驱动配置要点: 在配置DMA传输时,需要将帧宽度(width)乘以10/8来计算每行所需的字节数。例如,1920像素宽的RAW10图像,每行字节数为 1920 * 10 / 8 = 2400 字节。

4.2.2 RAW12 打包格式

RAW12每个像素占用12-bit数据。打包方式与RAW10类似,采用2像素打包成3字节的方式。

  • 存储效率: 100%(无浪费字节)。
  • 打包规则: 2个像素(P0, P1)的12-bit数据,按位拼接成3个字节(B0, B1, B2)。
  • 位分布:
    • B0 = P0[11:4](高8位)
    • B1 = P1[11:4](高8位)
    • B2 = {P1[3:0], P0[3:0]}(每个像素的低4位,共8位)

4.2.3 打包格式对比表

格式 位深 打包方式 每像素平均字节数 常见场景
RAW8 8-bit 1像素 = 1字节 1.0 低端摄像头、预览模式
RAW10 10-bit 4像素 = 5字节 1.25 主流手机、安防摄像头
RAW12 12-bit 2像素 = 3字节 1.5 工业相机、医疗影像
RAW16 16-bit 1像素 = 2字节 2.0 高动态范围(HDR)场景

4.2.4 RAW10 打包位分布示意图

下图展示了4个RAW10像素如何打包成5个字节。每个像素的高8位依次存放在前4个字节中,而每个像素的低2位则组合成第5个字节。

RAW10 4像素打包成5字节 像素数据 (10-bit each): P0 [9:0] P1 [9:0] P2 [9:0] P3 [9:0] 打包后字节 (8-bit each): B0 = P0[9:2] B1 = P1[9:2] B2 = P2[9:2] B3 = P3[9:2] B4 = {P3[1:0], P2[1:0], P1[1:0], P0[1:0]} 关键点:B4字节包含了4个像素的低2位,顺序为 P3, P2, P1, P0。 DMA传输时,每5个字节对应4个像素,需按此规则解析。

4.3 MIPI数据包解析

MIPI CSI-2协议定义了数据在D-PHY物理层上的传输格式。每一帧RAW图像数据被封装成多个数据包,通过差分信号线传输。理解数据包结构是正确解析RAW数据的关键。

4.3.1 MIPI CSI-2 数据包结构

一个标准的MIPI数据包由三部分组成:包首(Packet Header, PH)、数据负载(Payload)和包尾(Packet Footer, PF)。

  • 包首(4字节):
    • 数据标识符(Data Identifier, DI):1字节,包含虚拟通道号(VC, 2-bit)和数据类型(Data Type, 6-bit)。
    • 字计数(Word Count, WC):2字节,表示数据负载的字节数。
    • ECC(Error Correction Code):1字节,用于包首的纠错。
  • 数据负载(可变长度): 实际的RAW像素数据,按RAW10/RAW12打包格式排列。
  • 包尾(2字节): 校验和(Checksum),用于数据负载的完整性校验。

4.3.2 数据类型(Data Type)与RAW格式对应

MIPI CSI-2协议为不同的RAW格式定义了标准的数据类型值。驱动在解析数据包时,必须根据数据类型字段来判断负载的格式。

数据类型名称 数据类型值(Hex) 对应RAW格式 说明
RAW6 0x28 6-bit RAW 较少使用
RAW7 0x29 7-bit RAW 较少使用
RAW8 0x2A 8-bit RAW 常见于低端传感器
RAW10 0x2B 10-bit RAW 最常用格式之一
RAW12 0x2C 12-bit RAW 高精度应用
RAW14 0x2D 14-bit RAW 工业/医疗高端应用

4.3.3 MIPI数据包解析流程示意图

下图展示了从MIPI物理层接收数据到解析出RAW像素数据的完整流程。驱动需要依次解析包首、提取负载、校验包尾,最后根据数据类型进行解包。

MIPI CSI-2 数据包解析流程 1. 接收MIPI数据流 2. 解析包首 (PH) 3. 提取数据负载 (Payload) 4. 校验包尾 (PF) 5. 根据DT解包RAW数据 包首结构: DI (1B): VC + DT WC (2B): 负载长度 ECC (1B): 纠错码 包尾结构: Checksum (2B) 用于校验数据 完整性

4.4 实战:从MIPI数据包到DMA缓冲区

在驱动中,MIPI接收到的数据包经过DMA引擎直接搬运到系统内存中。驱动开发者需要理解以下关键点:

  1. DMA传输粒度: DMA通常以字节为单位传输,因此RAW10/RAW12的打包格式必须与DMA的传输宽度对齐。
  2. 帧同步: MIPI协议通过帧起始(FS)和帧结束(FE)包来标记一帧的开始和结束。驱动需要监听这些包来触发DMA传输完成中断。
  3. 行同步: 部分传感器会发送行起始(LS)和行结束(LE)包,用于标记每一行的边界。这对于DMA的“行模式”传输非常重要。
常见陷阱: 在解析RAW10数据时,如果DMA配置的每行字节数计算错误(例如忘记乘以10/8),会导致图像出现“斜纹”或“错位”现象。务必使用示波器或逻辑分析仪抓取MIPI数据,验证打包格式是否正确。

4.4.1 DMA缓冲区与RAW数据映射示例

假设一个分辨率为1920x1080的RAW10图像,DMA缓冲区中每行存储2400字节。驱动在中断处理函数中,需要将缓冲区地址传递给ISP或直接保存为文件。以下是一个简化的DMA传输完成回调函数示例:

static void sensor_dma_callback(void *arg)
{
    struct camera_device *cam = (struct camera_device *)arg;
    struct dma_buf *buf = cam->current_buf;
    u32 width = cam->fmt.width;   // 1920
    u32 height = cam->fmt.height; // 1080
    u32 bpp = cam->fmt.bpp;       // 10 (RAW10)
    
    // 计算每行字节数
    u32 bytes_per_line = width * bpp / 8; // 1920 * 10 / 8 = 2400
    
    // 验证缓冲区大小
    if (buf->size != bytes_per_line * height) {
        dev_err(cam->dev, "DMA buffer size mismatch!\n");
        return;
    }
    
    // 将缓冲区标记为就绪,等待ISP或应用层读取
    cam->frame_ready = true;
    wake_up_interruptible(&cam->wait_queue);
    
    // 重新启动DMA传输,准备下一帧
    start_dma_transfer(cam, buf);
}
调试技巧: 在开发初期,可以将DMA缓冲区中的原始数据直接保存为.raw文件,然后使用RawTherapee或dcraw等工具打开,验证Bayer Pattern和打包格式是否正确。如果图像颜色正常,说明MIPI解析和DMA传输均正确。