在智能汽车快速发展的今天,车载摄像头作为环境感知、辅助驾驶的核心部件,其稳定性、实时性和安全性直接影响着整车的智能化体验。瑞芯微(Rockchip)凭借其高性能的SoC平台和完善的车载摄像头开发框架,为开发者提供了一套高效、可靠的车载摄像头解决方案。本文将基于瑞芯微车载摄像头开发指南,从驱动开发、中间件使用到应用层实战,全面解析RK平台车载摄像头的开发流程与技术要点,配套完整可落地的代码示例,手把手带你完成车载摄像头全链路开发。
一、系统整体架构:车载摄像头开发的基础框架

1.1系统模块与框架
瑞芯微车载摄像头系统是一套经过精心设计的中间件软件系统,旨在满足汽车行业严格的高效、安全和可靠性标准。整个系统采用分层设计,从底层硬件到上层应用全链路覆盖,核心模块如下:
|
层级
|
核心模块
|
核心职责
|
|
内核驱动层
|
SEDES驱动层
|
负责Maxim SerDes串行解串器、远端Sensor的驱动适配,实现长距离图像数据的采集、传输与解析
|
|
核心中间件层
|
RVCAM中间件
|
车载摄像头方案的核心,提供统一的摄像头数据管理、虚拟多摄多开、算法扩展、跨系统通信能力,屏蔽底层硬件差异
|
|
硬件抽象层
|
EVS HAL、Automotive HAL3
|
对接AAOS车载安卓标准框架,为倒车影像、环视、座舱相机应用提供标准化接口
|
|
应用层
|
EVS APP、Native/APK应用
|
实现倒车影像、360°环视、行车记录、DMS舱内监控等业务功能
|
1.2安全与质量标准
车载系统对安全性要求极高,瑞芯微车载摄像头系统完全符合汽车行业的安全标准,包括ISO26262功能安全标准,确保在各种工况下的稳定运行。
•编码规范:遵循MISRA-C/MISRA-C++编码规范,通过Google C++ Lint做代码审查,减少潜在缺陷;
•故障防护:内置FMEA故障模式与影响分析机制,支持摄像头热插拔检测、故障诊断与恢复;
•功能安全:以FuSa功能安全为核心设计,确保系统出现故障时能以安全方式响应。
1.3功能开发路线图
瑞芯微为车载摄像头系统规划了完善的功能开发路线,以满足不同车载场景的需求:
•已完成功能:YUV摄像头虚拟多摄映射、SerDes多路RAW + ISP支持;
•开发中功能:单SerDes多MIPI PHY输出、车辆电源管理事件订阅、摄像头热插拔支持;
•规划中功能:低延时系统优化、ISP HAL支持虚拟多摄、摄像头诊断功能、第三方摄像头接口扩展、SOME/IP车载服务、多传感器融合框架等。
二、SEDES驱动开发:摄像头数据传输的底层基石
车载摄像头与消费级摄像头最大的差异,在于通过SerDes芯片实现长距离同轴/双绞线传输,这也是车载摄像头开发的第一个核心门槛。瑞芯微提供了完整的Maxim Camera SerDes V3驱动框架,完美适配主流车规级SerDes芯片与Sensor组合。
2.1 Maxim Camera Serdes驱动概述
Maxim(美信)的GMSL SerDes是车载场景最常用的串行解串器方案,瑞芯微驱动已原生支持以下芯片组合:
|
近端解串器
|
远端串化器
|
远端Sensor
|
|
MAX96712、MAX96722、MAX96716、MAX96718
|
MAX9295、MAX96715、MAX96717
|
OV2311/OV2312、OX01F10、OX03J10、SC320AT、OS04A10
|
驱动基于Linux media框架设计,核心分为近端解串器(Local)驱动和远端设备(Remote)驱动两大部分,通过I2C-MUX技术实现远端多设备的独立控制,将多路摄像头数据通过不同MIPI VC通道隔离,最终输出给SoC的ISP/CIF模块。

2.1.1驱动目录结构
Maxim Camera Serdes驱动的目录结构清晰,所有代码均在内核源码的drivers/media/i2c/maxim/路径下,便于开发者适配和扩展:
kernel/drivers/media/i2c/maxim/├── Kconfig # 驱动总配置入口├── Makefile # 驱动总编译规则├──local/ # 近端解串器驱动│ ├── maxim2c/ # 双路解串器驱动(MAX96716/MAX96718)│ │ ├── Kconfig、Makefile│ │ ├── maxim2c_drv.c # 驱动入口、I2C设备管理│ │ ├── maxim2c_link.c # GMSL链路管理│ │ ├── maxim2c_video_pipe.c# 视频管道映射│ │ └── maxim2c_mipi_txphy.c# MIPI输出PHY配置│ └── maxim4c/ # 四路解串器驱动(MAX96712/MAX96722)│ └── 结构同maxim2c└── remote/ # 远端设备驱动├── Kconfig、Makefile├── max9295.c/max96715.c/max96717.c# 串化器驱动├── ov231x.c/ox03j10.c/sc320at.c # YUV Sensor驱动├── os04a10.c # RAW Sensor驱动参考└── dummy.c # 虚拟Sensor调试驱动
2.1.2 config宏配置
驱动功能的裁剪与使能,通过内核config宏配置完成,需要在芯片对应的defconfig文件中添加以下配置,可根据实际硬件选型裁剪:
# ========== Maxim SerDes 驱动总开关 ==========CONFIG_VIDEO_MAXIM_SERDES=y# ========== 近端解串器驱动使能 ==========# 4路解串器(MAX96712/MAX96722)CONFIG_VIDEO_MAXIM_DES_MAXIM4C=y# 2路解串器(MAX96716/MAX96718)CONFIG_VIDEO_MAXIM_DES_MAXIM2C=y# ========== 远端串化器驱动使能 ==========CONFIG_VIDEO_MAXIM_SER_MAX9295=yCONFIG_VIDEO_MAXIM_SER_MAX96715=yCONFIG_VIDEO_MAXIM_SER_MAX96717=y# ========== 远端Sensor驱动使能 ==========CONFIG_VIDEO_MAXIM_CAM_DUMMY=y # 调试用虚拟SensorCONFIG_VIDEO_MAXIM_CAM_SC320AT=y # 思特威SC320ATCONFIG_VIDEO_MAXIM_CAM_OV231X=y # 豪威OV2311/OV2312CONFIG_VIDEO_MAXIM_CAM_OX01F10=y # 安森美OX01F10CONFIG_VIDEO_MAXIM_CAM_OX03J10=y # 安森美OX03J10CONFIG_VIDEO_MAXIM_CAM_OS04A10=y # 豪威OS04A10(RAW Sensor)
2.2 DTS配置详解:硬件参数的关键配置
DTS(Device Tree Source)设备树配置,是SerDes驱动适配的核心,90%的驱动适配工作都集中在DTS配置上。瑞芯微官方提供了EVB板的参考配置,我们以RK3588M + MAX96712 4路解串器为例,拆解完整的DTS配置细节。
2.2.1 I2C Init Sequence的DTS配置
SerDes芯片的寄存器配置繁多,驱动提供了标准化的I2C初始化序列配置方式,无需修改驱动代码,直接在DTS中配置寄存器序列即可,解串器、串化器、Sensor均可使用该配置方式。
完整配置示例:
link-init-sequence {// 单个配置项的字节长度:reg地址长度 + 寄存器值长度 + mask长度 + 延时长度 = 2+1+1+1=5seq-item-size = <5>;reg-addr-len = <2>; // 寄存器地址长度:2表示16位地址reg-val-len = <1>; // 寄存器值长度:1表示8位数据// 配置序列格式:寄存器地址 寄存器值 掩码 延时(ms) 保留位init-sequence = [14D1030000// 配置VGA高增益,寄存器0x14D1写入0x031445000000// 关闭SSC扩频,寄存器0x1445写入0x00040A010000// 使能链路A,寄存器0x040A写入0x01];};
2.2.2解串器核心节点与Dummy Sensor配置
首先需要在SoC对应的I2C总线节点下,添加解串器的基础设备节点,将解串器抽象为虚拟Sensor设备,完成电源、时钟、GPIO、MIPI输出端口的基础配置。
完整配置示例:
/* 以RK3588M的I2C6总线为例,挂载MAX96712解串器 */&i2c6 {status ="okay";#address-cells = <1>;#size-cells = <0>;pinctrl-names ="default";pinctrl-0= <&i2c6m3_xfer>;/* MAX96712 4路解串器核心节点 */max96712_dphy3:max96712@29{compatible ="maxim4c,max96712";status ="okay";reg = <0x29>; // 解串器I2C 7位地址clock-names ="xvclk";clocks = <&max96712_dphy3_osc0 0>;// 外部时钟输入/* 电源域与电源配置 */power-domains = <&power RK3588_PD_VI>;rockchip,grf = <&sys_grf>;vcc1v2-supply = <&max96712_dphy3_vcc1v2>;// 1.2V电源vcc1v8-supply = <&max96712_dphy3_vcc1v8>;// 1.8V电源pwdn-supply = <&max96712_dphy3_pwdn_regulator>;// 掉电控制电源poc-supply = <&max96712_dphy3_poc_regulator>; // 远端摄像头PoC同轴供电/* GPIO与状态引脚配置 */pinctrl-names ="default";pinctrl-0= <&max96712_dphy3_errb>, <&max96712_dphy3_lock>;lock-gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;// 链路锁定状态引脚errb-gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_LOW>; // 错误中断引脚/* 摄像头模组标识(RK摄像头框架必填) */rockchip,camera-module-index = <0>;rockchip,camera-module-facing ="back";rockchip,camera-module-name ="default";rockchip,camera-module-lens-name ="default";/* ========== 1. 输出模式配置 ========== */support-mode-config {status ="okay";bus-format =;// 输出数据格式 sensor-width = <1920>; // 图像宽度sensor-height = <1440>; // 图像高度max-fps-numerator = <10000>;max-fps-denominator = <300000>;// 30fpsbpp = <16>; // 每像素比特数vc-array = <0x100x200x400x80>;// 4路摄像头映射到VC0-VC3};/* ========== 2. RAW Sensor ISP路由配置(多路RAW Sensor必填) ========== */// 使能后,远端Sensor的控制权交给ISP驱动,关闭则由解串器统一管理remote-routing-to-isp = <0>;/* ========== 3. MIPI输出端口绑定 ========== */port {max96712_dphy3_out: endpoint {remote-endpoint = <&mipi_dphy3_in_max96712>;// 绑定到SoC的MIPI DPHY3data-lanes = <1234>;// MIPI数据线数量};};/* ========== 4. GMSL链路配置(4路Link对应4个远端摄像头) ========== */gmsl-links {status ="okay";// Link A 链路配置(对应第1路摄像头)gmsl-link-config-0{status ="okay";link-id = <0>; // 链路ID:0=Link A,1=Link B,以此类推link-type = <1>; // 链路类型:0=GMSL1,1=GMSL2link-rx-rate = <1>; // 正向速率:0=3Gbps,1=6Gbpslink-tx-rate = <0>; // 反向速率:0=187.5Mbpslink-remote-cam = <&max96712_dphy3_cam0>;// 绑定远端摄像头节点// 链路专属初始化序列link-init-sequence {seq-item-size = <5>;reg-addr-len = <2>;reg-val-len = <1>;init-sequence = [14D10300001445000000];};};// Link B 链路配置(对应第2路摄像头)gmsl-link-config-1{status ="okay";link-id = <1>;link-type = <1>;link-rx-rate = <1>;link-tx-rate = <0>;link-remote-cam = <&max96712_dphy3_cam1>;};// Link C、Link D 配置以此类推...};/* ========== 5. 视频管道配置(实现链路数据到VC通道的映射) ========== */video-pipes {status ="okay";// 管道0:对应Link A的摄像头数据video-pipe-config-0{status ="okay";pipe-id = <0>;pipe-idx = <2>;link-idx = <0>;// 绑定到Link A(link-id=0)// 管道初始化序列:配置CSI2映射、VC通道、数据类型pipe-init-sequence {seq-item-size = <5>;reg-addr-len = <2>;reg-val-len = <1>;init-sequence = [09 0B070000// 使能Src/Dst映射092D150000// 映射到CSI2控制器1090D1e0000// 配置SRC0 VC=0,DT=YUV422 8bit09 0E 1e0000// 配置DST0 VC=0,DT=YUV422 8bit];};};// 管道1:对应Link B的摄像头数据,以此类推...};/* ========== 6. MIPI TXPHY输出配置 ========== */mipi-txphys {status ="okay";phy-mode = <0>;// PHY模式:0=2X4Lanes,1=4X2Lanesphy-force-clock-out= <1>;// 强制输出MIPI时钟,避免无摄像头时PHY不工作// PHY0配置mipi-txphy-config-0{status ="okay";phy-id = <0>;phy-type = <0>;// 0=DPHY,1=CPHYdata-lane-num = <4>;data-lane-map = <0x4>;};};/* ========== 7. 额外初始化序列(帧同步、GPIO等扩展配置) ========== */extra-init-sequence {seq-item-size = <5>;reg-addr-len = <2>;reg-val-len = <1>;init-sequence = [0817010000];};/* ========== 8. 远端设备I2C-MUX配置(核心!实现远端串化器/Sensor的I2C通信) ========== */i2c-mux {#address-cells = <1>;#size-cells = <0>;// Link A对应的远端I2C通道i2c@0{#address-cells = <1>;#size-cells = <0>;reg = <0>;// 对应link-id=0// 注意:串化器节点必须写在Sensor节点前面,保证驱动probe顺序max96712_dphy3_ser0:max96717@41{compatible ="maxim,ser,max96717";reg = <0x41>;// 映射后的I2C地址ser-i2c-addr-def = <0x40>;// 串化器默认上电地址// 串化器初始化序列ser-init-sequence {seq-item-size = <5>;reg-addr-len = <2>;reg-val-len = <1>;init-sequence = [03021000001417000000];};};// Link A对应的远端Sensor节点max96712_dphy3_cam0:sc320at@31{compatible ="maxim,smartsens,sc320at";reg = <0x31>;// 映射后的I2C地址cam-i2c-addr-def = <0x30>;// Sensor默认上电地址cam-remote-ser = <&max96712_dphy3_ser0>;// 绑定对应的串化器poc-supply = <&max96712_dphy3_poc_regulator>;// PoC供电// RK摄像头框架必填参数rockchip,camera-module-index = <0>;rockchip,camera-module-facing ="back";rockchip,camera-module-name ="default";rockchip,camera-module-lens-name ="default";// 端口配置(RAW Sensor需绑定到ISP节点)port {max96712_dphy3_cam0_out: endpoint {data-lanes = <1234>;};};};};// Link B对应的远端I2C通道i2c@1,以此类推...};};};
2.2.3 RAW Sensor专属DTS配置
如果使用RAW输出的Sensor,需要额外配置ISP路由,核心修改3处:
1.解串器节点添加remote-routing-to-isp = <1>,使能多路RAW Sensor路由;
2.远端Sensor的port节点添加remote-endpoint,链接到ISP的输入节点;
3.在SoC的rkcif_mipi_lvds节点添加camera-over-bridge属性,开启远端RAW Sensor模式。
2.3近端解串器驱动开发
瑞芯微已经完成了maxim4c(4路)和maxim2c(2路)解串器的完整驱动实现,常规场景无需修改驱动代码,仅需通过DTS配置即可完成适配。驱动核心能力包括:
•解串器的虚拟Sensor抽象与v4l2 subdev接口实现;
•GMSL链路管理、锁定状态检测、热插拔恢复;
•远端设备的上下电、开关流统一管理;
•MIPI TXPHY配置与CSI-2数据输出控制;
•内置测试彩条Pattern输出,可用于硬件通路调试。
如果需要自定义扩展,可直接修改对应驱动文件,核心API接口均在maxim4c_api.h/maxim2c_api.h中声明。
2.4远端摄像头驱动适配
对于YUV输出的摄像头模组,模组内部已完成ISP处理,上电后自动加载配置,直接使用官方适配好的Sensor驱动,或dummy驱动即可;对于RAW输出的Sensor,需要基于官方框架完成驱动适配,以下是适配的核心代码细节与8大关键改动点。
2.4.1 Kconfig与Makefile配置
首先在remote/目录下添加新Sensor的编译配置,避免和原生Sensor驱动冲突。
Kconfig配置示例(drivers/media/i2c/maxim/remote/Kconfig):
configVIDEO_MAXIM_CAM_OS04A10tristate"Maxim Remote Sensor OV OS04A10"depends onVIDEO_MAXIM_SERDESdepends onI2ChelpThisdriver supports the remoteOS04A10 sensor overMaximSerDes.Tocompilethisdriverasamodule, themodulewill be called maxim-os04a10.
Makefile配置示例(drivers/media/i2c/maxim/remote/Makefile):
给驱动模块加maxim-前缀,避免和原生OS04A10驱动重名maxim-os04a10-objs := os04a10.o(CONFIG_VIDEO_MAXIM_CAM_OS04A10) += maxim-os04a10.o
2.4.2驱动核心适配代码
和消费级Sensor驱动相比,SerDes远端Sensor驱动有8个核心改动点,以下是关键代码示例:
1.驱动名与compatible适配
添加maxim,前缀,避免和原生驱动冲突,示例如下:
staticconststructof_device_id os04a10_of_match[] = {{ .compatible ="maxim,ovti,os04a10"},// 必须加maxim前缀{/* sentinel */},};MODULE_DEVICE_TABLE(of, os04a10_of_match);staticstructi2c_driver os04a10_i2c_driver = {.driver = {.name ="maxim-os04a10",// 驱动名加前缀.pm = &os04a10_pm_ops,.of_match_table = of_match_ptr(os04a10_of_match),},.probe = &os04a10_probe,.remove= &os04a10_remove,};module_i2c_driver(os04a10_i2c_driver);
2.核心数据结构添加SerDes相关成员
structos04a10 {structv4l2_subdev sd;structmedia_pad pad;structregulator *poc_regulator;// PoC同轴供电,替代原生多电源structmaxim_remote_ser *serializer;// 绑定的串化器设备u8 cam_i2c_addr_def;// Sensor默认I2C地址u8 cam_i2c_addr_map;// 映射后的I2C地址// 其他原有Sensor参数...};
3. probe函数核心适配
probe阶段不再做MCLK、GPIO、电源的硬件配置,核心完成串化器绑定、PoC电源获取,不再做Chip ID检测(链路未初始化时I2C无法通信)。
staticintos04a10_probe(structi2c_client *client,conststructi2c_device_id *id){structdevice *dev = &client->dev;structos04a10 *sensor;intret;// 1. 分配驱动结构体sensor = devm_kzalloc(dev,sizeof(*sensor), GFP_KERNEL);if(!sensor)return-ENOMEM;// 2. 获取PoC供电 regulator(替代原生的多电源配置)sensor->poc_regulator = devm_regulator_get(dev,"poc");if(IS_ERR(sensor->poc_regulator)) {dev_err(dev,"Failed to get PoC regulatorn");returnPTR_ERR(sensor->poc_regulator);}// 3. 绑定远端串化器(核心!必须实现)sensor->serializer = maxim_remote_cam_bind_ser(dev);if(!sensor->serializer) {dev_err(dev,"Bind remote serializer failedn");return-ENODEV;}// 传递Sensor的I2C地址信息给串化器sensor->cam_i2c_addr_def =0x30;// 替换为你的Sensor默认地址sensor->serializer->cam_i2c_addr_def = sensor->cam_i2c_addr_def;sensor->serializer->cam_i2c_addr_map = client->addr;// 4. 初始化v4l2_subdev、media pad等框架代码// ... 原有Sensor的v4l2框架初始化代码,此处省略...dev_info(dev,"Maxim remote OS04A10 sensor probe successn");return0;}
4.电源上下电适配
移除原生的多电源、GPIO复位代码,改为PoC电源控制,示例如下:
staticint__os04a10_power_on(structos04a10 *sensor){intret;// 开启PoC同轴供电ret = regulator_enable(sensor->poc_regulator);if(ret) {dev_err(&sensor->sd.client->dev,"PoC power enable failedn");returnret;}// 等待电源稳定usleep_range(10000,12000);return0;}staticint__os04a10_power_off(structos04a10 *sensor){returnregulator_disable(sensor->poc_regulator);}
5.开关流接口适配(核心)
开流阶段才完成串化器初始化、Chip ID检测、Sensor寄存器配置,这是和消费级Sensor最大的区别。
开流函数完整示例:
staticint__os04a10_start_stream(structos04a10 *sensor){structi2c_client *client = v4l2_get_subdevdata(&sensor->sd);structdevice *dev = &client->dev;structmaxim_remote_ser *serializer = sensor->serializer;intret;// 1. 先初始化串化器ret = serializer->ser_ops->ser_module_init(serializer);if(ret) {dev_err(dev,"Serializer init failed, ret=%dn", ret);returnret;}// 2. 检测Sensor Chip ID(必须在串化器初始化后执行)ret = os04a10_check_chip_id(sensor);if(ret) {dev_err(dev,"Sensor chip id check failedn");gotoerr_ser_deinit;}// 3. 写入Sensor初始化寄存器序列ret = os04a10_write_regs(client, sensor->cur_mode->reg_list);if(ret) {dev_err(dev,"Sensor init regs write failedn");gotoerr_ser_deinit;}// 4. 配置v4l2控制参数(曝光、增益等)ret = __v4l2_ctrl_handler_setup(&sensor->ctrl_handler);if(ret) {dev_err(dev,"v4l2 ctrl setup failedn");gotoerr_ser_deinit;}// 5. 启动Sensor流输出ret = os04a10_set_streaming(sensor,true);if(ret) {dev_err(dev,"Sensor start streaming failedn");gotoerr_ser_deinit;}// 6. 检测串化器PCLK,确认Sensor数据正常输出ret = serializer->ser_ops->ser_pclk_detect(serializer);if(ret) {dev_err(dev,"Serializer PCLK detect failed, no data inputn");gotoerr_stop_stream;}dev_info(dev,"OS04A10 start stream successn");return0;err_stop_stream:os04a10_set_streaming(sensor,false);err_ser_deinit:serializer->ser_ops->ser_module_deinit(serializer);returnret;}
关流函数完整示例:
staticint __os04a10_stop_stream(structos04a10*sensor){structi2c_client*client=v4l2_get_subdevdata(&sensor->sd);structdevice*dev=&client->dev;structmaxim_remote_ser*serializer=sensor->serializer;int ret;// 1. 停止Sensor流输出ret=os04a10_set_streaming(sensor,false);if(ret)dev_warn(dev,"Sensor stop streaming failedn");// 2. 反初始化串化器ret=serializer->ser_ops->ser_module_deinit(serializer);if(ret)dev_warn(dev,"Serializer deinit failedn");dev_info(dev,"OS04A10 stop stream successn");return0;}
6.移除MCLK、GPIO相关代码
SerDes架构下,Sensor的MCLK、复位引脚均由远端串化器提供,无需SoC控制,直接删除驱动中相关的时钟申请、GPIO配置代码即可。
三、RVCAM中间件:车载摄像头应用开发的利器
RVCAM(Rockchip Vehicle Camera)是瑞芯微车载摄像头方案的灵魂,它屏蔽了底层硬件差异,提供了统一的API接口,完美解决了车载场景一摄多开、多应用共享、低延时传输、跨系统通信等核心痛点,是应用开发的核心抓手。
3.1 RVCAM介绍
RVCAM是专为车载场景设计的摄像头中间件,核心能力包括:
•虚拟多摄多开:一个物理摄像头可映射为多个虚拟摄像头,支持倒车影像、行车记录、环视应用同时访问,无资源抢占问题;
•全接口适配:同时支持Native API直接调用、AAOS EVS HAL、Android Camera HAL3,满足不同开发场景;
•低开销高性能:RK3576M平台四路1080P@30fps摄像头同时开启,CPU占用率仅10%左右;
•跨系统支持:原生支持Android+Linux双系统架构,基于eRPC实现跨系统摄像头控制与数据共享;
•可扩展架构:支持插件式集成图像处理算法,如畸变校正、HDR、BEV融合等。
3.2 RVCAM API使用指南
RVCAM提供了极简的C语言API接口,Native应用可直接调用,无需关心底层V4L2驱动细节,以下是API分类与完整的采集流程代码示例。
3.2.1核心API分类
|
API分类
|
核心功能
|
关键接口
|
|
初始化与终止
|
管理RVCAM上下文生命周期
|
rvcam_initialize、rvcam_uninitialize
|
|
设备信息查询
|
获取摄像头列表与参数
|
rvcam_query_inputs
|
|
流管理
|
摄像头流的开启/关闭/暂停/恢复
|
rvcam_open、rvcam_close、rvcam_start、rvcam_stop
|
|
参数管理
|
摄像头参数的查询与配置
|
rvcam_g_param、rvcam_s_param
|
|
帧数据管理
|
图像帧的获取与释放
|
rvcam_get_frame、rvcam_release_frame、rvcam_s_buffers
|
3.2.2完整的单摄采集代码示例
以下是基于RVCAM API实现的摄像头采集全流程代码,可直接用于倒车影像、单路预览等场景:
intmain(intargc,char*argv[]){intret =0;rvcam_init_tinit_params = {0};rvcam_input_t*camera_list =NULL;unsignedintcamera_num =0;rvcam_hndl_tcam_handle =NULL;rvcam_frame_info_tframe_info = {0};intcapture_count =100;// 采集100帧// ========== 1. 初始化RVCAM上下文 ==========ret =rvcam_initialize(&init_params);if(ret !=0) {printf("RVCAM initialize failed, ret=%dn", ret);return-1;}printf("RVCAM initialize successn");// ========== 2. 查询系统中的摄像头列表 ==========// 第一次调用:获取摄像头数量ret =rvcam_query_inputs(NULL,0, &camera_num);if(ret !=0|| camera_num ==0) {printf("Query camera num failed, ret=%d, num=%dn", ret, camera_num);gotoerr_uninit;}printf("Found %d cameras in systemn", camera_num);// 分配内存,第二次调用:获取摄像头详细信息camera_list = (rvcam_input_t*)malloc(sizeof(rvcam_input_t) * camera_num);if(!camera_list) {printf("Malloc camera list failedn");gotoerr_uninit;}ret =rvcam_query_inputs(camera_list, camera_num, &camera_num);if(ret !=0) {printf("Query camera info failed, ret=%dn", ret);gotoerr_free_list;}// 打印摄像头信息for(inti =0; i < camera_num; i++) {printf("Camera %d: name=%s, resolution=%dx%dn",camera_list[i].id, camera_list[i].name,camera_list[i].width, camera_list[i].height);}// ========== 3. 打开指定虚拟摄像头(以camId=0为例) ==========inttarget_cam_id =0;cam_handle =rvcam_open(target_cam_id);if(!cam_handle) {printf("Open camera %d failedn", target_cam_id);gotoerr_free_list;}printf("Open camera %d successn", target_cam_id);// ========== 4. 配置摄像头参数(可选) ==========// 示例:设置分辨率、帧率等参数// rvcam_param_value_t param_val = {0};// param_val.width = 1920;// param_val.height = 1080;// ret = rvcam_s_param(cam_handle, RVCAM_PARAM_RESOLUTION, ¶m_val);// ========== 5. 启动摄像头数据流 ==========ret =rvcam_start(cam_handle);if(ret !=0) {printf("Start camera stream failed, ret=%dn", ret);gotoerr_close_cam;}printf("Start camera stream successn");// ========== 6. 循环采集帧数据 ==========for(inti =0; i < capture_count; i++) {// 获取一帧数据,超时时间500msret =rvcam_get_frame(cam_handle, &frame_info,500,0);if(ret !=0) {printf("Get frame %d failed, ret=%dn", i, ret);continue;}// 帧数据处理printf("Capture frame %d success: timestamp=%llu, width=%d, height=%d, format=%d, buf_fd=%dn",i, frame_info.timestamp, frame_info.width, frame_info.height,frame_info.format, frame_info.buf_fd);// ========== 此处可添加图像处理、渲染、编码等业务逻辑 ==========// 例如:通过RGA做格式转换、缩放;通过OpenGL渲染显示;保存为图片/视频等// 释放帧缓冲区,必须调用,否则会出现缓冲区耗尽ret =rvcam_release_frame(cam_handle, frame_info.idx);if(ret !=0) {printf("Release frame %d failed, ret=%dn", i, ret);}// 控制采集帧率usleep(30000);// 30fps}// ========== 7. 停止数据流 ==========ret =rvcam_stop(cam_handle);if(ret !=0) {printf("Stop camera stream failed, ret=%dn", ret);}printf("Stop camera stream successn");// ========== 8. 资源释放 ==========err_close_cam:rvcam_close(cam_handle);err_free_list:free(camera_list);err_uninit:rvcam_uninitialize();printf("RVCAM resource release donen");returnret;}
3.3 RVCAM配置文件详解
RVCAM的所有物理摄像头配置、虚拟摄像头映射关系,都在rvcam_config.xml中定义,编译后部署到板端/vendor/etc/rvcam_config.xml,是实现多摄多开的核心。
3.3.1完整的配置文件示例
以下是支持4路物理摄像头、一摄三开的完整配置示例,可直接参考修改:
<CameraConfigversion="0x100"><boardname="Rockchip RK3588 VEHICLE EVB V22 Board"><cameras><cameraid="0"><entity>m00_b_max96712 6-0029entity><subDev>/dev/v4l-subdev5subDev><mbusCode>UYVY8_2X8/1920x1440mbusCode><channels><channelid="0"dev="/dev/video11"><cameraModel>Rear_CamcameraModel><streamid="0"format="YUYV"width="1920"height="1440"bufCnt="4"/>channel><channelid="1"dev="/dev/video12"><cameraModel>Right_CamcameraModel><streamid="0"format="YUYV"width="1920"height="1440"bufCnt="4"/>channel><channelid="2"dev="/dev/video13"><cameraModel>Left_CamcameraModel><streamid="0"format="YUYV"width="1920"height="1440"bufCnt="4"/>channel><channelid="3"dev="/dev/video14"><cameraModel>Front_CamcameraModel><streamid="0"format="YUYV"width="1920"height="1440"bufCnt="4"/>channel>channels>camera>cameras><inputMapping><inputMapcamId="0"><inputSrccameraId="0"channelId="0"streamId="0"/>inputMap><inputMapcamId="1"><inputSrccameraId="0"channelId="1"streamId="0"/>inputMap><inputMapcamId="2"><inputSrccameraId="0"channelId="2"streamId="0"/>inputMap><inputMapcamId="3"><inputSrccameraId="0"channelId="3"streamId="0"/>inputMap><inputMapcamId="4"><inputSrccameraId="0"channelId="0"streamId="0"/>inputMap><inputMapcamId="5"><inputSrccameraId="0"channelId="0"streamId="0"/>inputMap><inputMapcamId="6"><inputSrccameraId="0"channelId="1"streamId="0"/>inputMap>inputMapping>board>CameraConfig>
3.3.2关键配置说明
•board name:必须和主板的device-tree model一致,否则配置不生效;
•camera节点:对应物理解串器设备,channels下的每个channel对应一个物理摄像头通道;
•inputMapping节点:核心的虚拟映射配置,同一个物理channel可以映射给多个inputMap,实现一摄多开;
•camId分配:AAOS系统默认0-3号给EVS使用,Camera HAL3从4号开始,避免ID冲突导致上层应用找不到设备。
3.4 RVCAM调试功能
RVCAM内置了完善的调试功能,可通过系统属性开启,用于排查帧率、丢帧、多开冲突等问题:
# 1. 开启RVCAM调试日志,自动写入文件adbshell setprop persist.vendor.rockchip.rvcam.dbgfile.ontrue# 2. 设置日志写入间隔(单位:ms,默认200ms)adb shell setprop persist.vendor.rockchip.rvcam.dbgfile.interval200
调试日志路径:/data/vendor/camera/rvcam_debug.log,日志中包含摄像头开关状态、实时帧率、丢帧统计、buffer状态等关键信息。
四、EVS模块:车载视觉应用的核心框架
EVS(Exterior View System)是Android Automotive OS专为车载视觉设计的标准框架,核心优势是启动速度快、低延时,能在Android启动早期就完成倒车影像的渲染,满足车规级倒车影像<2s的启动时效要求,是车载后视、环视应用的首选方案。
4.1 EVS模块划分与目录介绍
RK平台的EVS方案完全遵循AAOS标准架构,底层基于RVCAM中间件实现,无需修改核心代码,仅需完成配置即可快速落地。EVS框架分为以下几个核心部分:
|
模块
|
源码路径
|
核心职责
|
|
EVS APP
|
packages/services/Car/cpp/evs/apps/default/
|
负责图像渲染、车辆状态响应、UI交互、环视拼接
|
|
EVS Manager
|
Android12: packages/services/Car/cpp/evs/manager/
|
中间管理层,封装EVS HAL接口,管理摄像头与显示设备
|
|
EVS HAL
|
瑞芯微定制实现,基于RVCAM
|
硬件抽象层,对接RVCAM中间件,向上提供标准EVS HIDL/AIDL接口
|
|
CarEvsService
|
packages/services/Car/service/
|
Java层服务,为APK应用提供EVS接口
|
4.2 EVS核心数据流程
EVS的核心数据流程分为摄像头数据采集流程和显示渲染流程两部分:
1.摄像头数据流程:EVS APP启动后,通过EVS Manager打开EVS HAL的摄像头设备,EVS HAL通过RVCAM获取摄像头帧数据,通过deliverFrame接口将帧数据上报给EVS APP,APP将帧数据存入双Buffer,通过OpenGL ES完成畸变校正、拼接、渲染后,释放buffer给底层。
2.显示渲染流程:EVS APP从EVS HAL获取显示Buffer,完成图像绘制后,将Buffer返回给EVS HAL完成上屏显示。
4.3 EVS产品配置详解
EVS的适配核心在于配置文件,分为EVS APP配置、EVS HAL配置、服务与SELinux配置三大部分。
4.3.1 EVS APP配置文件
EVS APP的核心配置文件为config_override.json,编译后部署到板端/vendor/etc/automotive/evs/config_override.json,用于配置车辆参数、显示参数、摄像头内外参、畸变校正参数等,完整配置示例如下:
{"car":{"width":180,"wheelBase":280,"frontExtent":90,"rearExtent":70},"displays":[{"displayPort":0,"frontRange":200,"rearRange":200}],"graphic":{"frontPixel":23,"rearPixel":223},// 核心:摄像头参数配置,每个摄像头对应一个节点"cameras":[{"cameraId":"0","function":"reverse,park","x":0.0,"y":-70.0,"z":120,"yaw":180,"pitch":-20,"roll":0,"hfov":130,"vfov":100,"hflip":true,"vflip":true},{"cameraId":"1","function":"right","x":90.0,"y":100.0,"z":120,"yaw":90,"pitch":-15,"roll":0,"hfov":130,"vfov":100,"hflip":false,"vflip":false},{"cameraId":"2","function":"left","x":-90.0,"y":100.0,"z":120,"yaw":-90,"pitch":-15,"roll":0,"hfov":130,"vfov":100,"hflip":false,"vflip":false},{"cameraId":"3","function":"front","x":0.0,"y":90.0,"z":120,"yaw":0,"pitch":-15,"roll":0,"hfov":130,"vfov":100,"hflip":false,"vflip":false}]}
关键说明:
•cameraId:必须和rvcam_config.xml中的虚拟摄像头camId一一对应;
•function:定义摄像头的用途,EVS APP会根据车辆档位、转向灯状态自动切换对应摄像头;
•位姿参数x/y/z/yaw/pitch/roll、视场角hfov/vfov:需根据摄像头实际安装位置和参数填写,直接影响环视拼接的效果。
4.3.2 EVS HAL配置文件
EVS HAL的配置文件为evs_configuration_override.xml,部署到板端/vendor/etc/automotive/evs/evs_configuration_override.xml,用于定义EVS HAL向上暴露的摄像头设备信息,完整配置示例如下:
<evs_config><camera><deviceid='0'position='rear'><caps><supported_controls>supported_controls><streamid='0'width='1920'height='1440'format='YCRCB_420_SP'framerate='30'/><streamid='1'width='1280'height='720'format='YCRCB_420_SP'framerate='30'/>caps><characteristics/>device><deviceid='1'position='right'><caps><streamid='0'width='1920'height='1440'format='YCRCB_420_SP'framerate='30'/>caps><characteristics/>device><deviceid='2'position='left'><caps><streamid='0'width='1920'height='1440'format='YCRCB_420_SP'framerate='30'/>caps><characteristics/>device><deviceid='3'position='front'><caps><streamid='0'width='1920'height='1440'format='YCRCB_420_SP'framerate='30'/>caps><characteristics/>device>camera><display><deviceid='0'type='display'><caps><streamid='0'width='1920'height='720'format='RGBA_8888'/>caps>device>display>evs_config>
4.3.3编译与服务配置
需要在产品的mk文件中添加EVS相关模块的编译配置,示例如下:
# Android14 AIDL版本编译配置PRODUCT_PACKAGES+=evs_appevsmanagerdandroid.hardware.automotive.evs-rvcamcardisplayproxyd# Android12 HIDL版本编译配置# PRODUCT_PACKAGES +=# evs_app# evs_manager# android.hardware.automotive.evs@1.1-rvcam# android.frameworks.automotive.display@1.0-service
同时,瑞芯微已经提供了配套的rc启动脚本、SELinux权限配置,无需额外修改,直接编译即可。
五、AutomotiveCamera HAL3层:安卓框架与硬件的桥梁
Automotive Camera HAL3(简称AutHAL3)是瑞芯微为车载场景定制的Camera HAL,对接Android标准Camera2 API,底层基于RVCAM中间件实现,为行车记录、舱内监控、DMS/OMS、拍照录像等应用提供标准化的安卓相机接口。
5.1基本功能说明
和Android原生的ExternalCamera HAL相比,AutHAL3完美适配车载场景,核心优势如下:
•基于RVCAM中间件,原生支持一摄多开、多应用同时访问,解决了原生HAL摄像头独占的问题;
•支持Buffer Management功能,降低内存峰值,提升捕获请求响应速度;
•支持Buffer透传功能,减少内存拷贝,降低CPU占用和传输延时;
•兼容Android HIDL/AIDL接口,适配Android12/14系统,无需上层应用修改代码。
AutHAL3的核心链路:Android Camera Framework → AutomotiveCamera HAL3 → RVCAM中间件→底层V4L2驱动→物理摄像头。
5.2核心功能详解
5.2.1 BUFFER MANAGEMENT功能
Buffer Management是Android 10+推出的可选内存管理机制,核心优势是HAL层按需申请buffer,而非框架层提前分配,减少了内存峰值占用,同时让捕获请求可以更快下发。
AutHAL3已完整实现该功能,Android14+系统可通过配置文件开启,Android12及以下系统默认开启。
5.2.2 BUFFER透传功能
这是RK AutHAL3的核心优化功能。非透传模式下,图像数据需要经过「V4L2驱动→ RVCAM中间件buffer → HAL层buffer →框架层buffer」两次拷贝;开启透传功能后,框架层的输出buffer直接透传给RVCAM,仅需一次拷贝,CPU占用减半,延时大幅降低。
该功能默认开启,可通过配置文件关闭。
5.3 HAL3产品配置详解
5.3.1核心配置文件
AutHAL3的核心配置文件为automotive_camera_config.xml,编译后部署到板端,完整配置示例如下:
<CameraHalConfig><Provider><ignore><id>0id><id>1id><id>2id><id>3id>ignore><CameraIdOffset>-4CameraIdOffset>Provider><BufferManagerenabled="false"/><HalBufferTransferenabled="true"/>CameraHalConfig>
关键说明:
•ignore节点:必须配置EVS占用的camId,避免HAL3和EVS争抢摄像头资源;
•CameraIdOffset:ID偏移配置,例如RVCAM的camId=4,经过-4偏移后,上报给Android框架的camera id为0,符合安卓应用的使用习惯。
5.3.2编译与服务配置
在产品mk文件中添加HAL3模块的编译配置,示例如下:
# Android14 AIDL版本PRODUCT_PACKAGES+=android.hardware.camera.provider-V1-automotive-implandroid.hardware.camera.provider-V1-automotive-service# Android12 HIDL版本# PRODUCT_PACKAGES +=# android.hardware.camera.provider@2.4-impl-automotive# android.hardware.camera.provider@2.4-automotive-service
瑞芯微已配套提供了rc启动脚本、SELinux权限配置、兼容性矩阵配置,无需额外修改。
5.4调试与性能说明
5.4.1核心性能指标
|
指标项
|
规格说明
|
|
虚拟摄像头数量
|
由rvcam_config.xml配置决定,无硬件限制
|
|
每路摄像头支持的tall stream数量
|
1路(拍照流)
|
|
每路摄像头支持的其他stream数量
|
2路(预览/录像流)
|
|
支持的图像格式
|
BLOB、YCbCr_422_I、YCbCr_420_888、厂商自定义格式
|
|
支持的分辨率
|
以物理摄像头参数为准,最高支持4K
|
|
支持的帧率
|
以物理摄像头参数为准,最高支持60fps
|
5.4.2常用调试命令
1.查看摄像头信息
# 查看HAL3上报给安卓框架的所有摄像头信息、支持的格式/分辨率/帧率adbshell dumpsys media.camera
2.Camera Trace性能调试
使用Perfetto工具抓取Camera链路的trace数据,分析帧率、延时、性能瓶颈,完整抓取脚本如下:
adb shell perfetto-c ---txt-o /data/misc/perfetto-traces/camera_trace<buffers: {size_kb:63488fill_policy: DISCARD}buffers: {size_kb:2048fill_policy: DISCARD}data_sources: {config {name:"android.packages_list"target_buffer:1}}data_sources: {config {name:"linux.ftrace"ftrace_config {ftrace_events:"ftrace/print"atrace_categories:"camera""gfx""input""view""sched"atrace_apps:"*"}}}duration_ms:10000 # 抓取时长,单位msEOF
抓取完成后,将trace文件导出,通过https://ui.perfetto.dev/网页即可可视化分析。
六、调试与问题排查:打造稳定高效的车载摄像头系统
车载摄像头开发过程中,会遇到驱动加载失败、无图像、画面异常、多开冲突等问题,以下是常用的调试技巧和常见问题的排查方案。
6.1驱动层调试命令
1.检查驱动是否加载成功
# 查看内核启动日志,搜索SerDes、Sensor相关的probe日志dmesg | grep -i maximdmesg | grep -i sensor# 查看系统中加载的v4l2子设备ls/dev/v4l-subdev*# 查看系统中的视频设备节点ls/dev/video*
2.查看media拓扑链路
# 查看media设备的完整拓扑,确认解串器、Sensor、ISP、CIF的链路是否正确media-ctl -d /dev/media0 -p
3.V4L2通道测试
# 查看video设备支持的格式、分辨率v4l2-ctl -d /dev/video11 --list-formats-ext# 测试视频采集,保存为原始文件v4l2-ctl -d /dev/video11 --set-fmt-video=width=1920,height=1440,pixelformat=YUYV --stream-mmap=4--stream-count=100--stream-to=/data/capture.yuv
4.I2C通信调试
# 检测I2C总线上的设备,确认解串器、Sensor的I2C地址是否可访问i2cdetect-y6 #6为解串器挂载的I2C总线号
6.2 RVCAM与上层调试
1.查看RVCAM服务状态
# Android系统查看RVCAM服务是否正常运行ps -A |greprvcam# 查看RVCAM服务日志logcat |grep-i rvcam
2.EVS服务调试
# 查看EVS相关进程ps -A |grep-i evs# 查看EVS日志logcat |grep-i evs# 手动重启EVS相关服务stop evs_app && start evs_app
6.3常见问题与解决方案
|
常见问题
|
核心排查方向
|
解决方案
|
|
解串器驱动probe失败
|
1. I2C地址与硬件是否匹配;2.电源、GPIO配置是否正确;3.解串器硬件供电是否正常
|
1.核对硬件原理图,修正DTS中的I2C地址、电源、GPIO配置;2.用万用表测量解串器供电引脚电压是否正常
|
|
远端Sensor probe成功,但无法通信
|
1.串化器与Sensor的DTS节点顺序是否正确;2. I2C地址映射是否正确;3.串化器绑定是否成功
|
1.确保DTS中串化器节点写在Sensor节点前面;2.核对cam-i2c-addr-def与Sensor硬件默认地址是否一致;3.查看内核日志,确认串化器绑定成功
|
|
驱动加载正常,但无图像输出
|
1.解串器链路是否锁定;2. MIPI配置与Sensor输出是否匹配;3. video-pipe与VC通道映射是否正确;4. Sensor是否正常输出数据
|
1.查看内核日志,确认GMSL链路lock成功;2.核对Sensor输出格式、分辨率、帧率与解串器配置是否一致;3.检查video-pipe的寄存器配置,确保数据映射到正确的VC通道;4.通过串化器的PCLK检测功能,确认Sensor有数据输出
|
|
上层应用找不到摄像头
|
1. rvcam_config.xml配置是否正确;2.虚拟摄像头camId是否配置;3. EVS与HAL3的ID是否冲突;4. RVCAM服务是否正常启动
|
1.核对board name与主板model是否一致;2.确认inputMapping中配置了对应的camId;3.检查HAL3的ignore配置,避免ID冲突;4.查看RVCAM服务日志,确认配置文件加载成功
|
|
多个应用同时访问摄像头失败
|
1.是否配置了一摄多开的虚拟映射;2.每个应用是否使用不同的虚拟camId
|
1.在rvcam_config.xml的inputMapping中,给同一个物理通道配置多个虚拟camId;2.不同应用使用不同的虚拟camId打开摄像头
|
|
图像画面花屏、卡顿
|
1. MIPI信号质量是否正常;2. SerDes链路速率是否匹配;3.帧率与带宽是否匹配;4.缓冲区数量是否足够
|
1.检查硬件线缆、阻抗匹配;2.核对GMSL链路速率配置,确保满足摄像头数据带宽需求;3.增加stream的bufCnt缓冲区数量
|
七、总结与展望
瑞芯微的车载摄像头开发框架,为开发者提供了从底层SerDes驱动适配、中间件配置,到上层AAOS EVS/HAL3应用落地的全链路解决方案,极大降低了车载摄像头的开发门槛。
对于开发者而言,车载摄像头开发的核心要点可以总结为3步:
1.底层驱动适配:完成SerDes芯片与Sensor的DTS配置,RAW Sensor完成驱动适配,确保内核层能正常采集到图像数据;
2.中间件配置:通过rvcam_config.xml完成物理摄像头与虚拟摄像头的映射,实现一摄多开能力;
3.上层应用适配:根据业务场景,完成EVS倒车/环视应用配置,或基于Camera2 API开发座舱相机应用。
希望本文能帮助各位开发者快速掌握RK平台车载摄像头的开发全流程,少走弯路,打造出稳定、高效的车载视觉应用。
-
瑞芯微
+关注
关注
27文章
841浏览量
54647 -
智能汽车
+关注
关注
30文章
3309浏览量
109670 -
车载摄像头
+关注
关注
5文章
152浏览量
28793
发布评论请先 登录
什么是车载摄像头?车载摄像头与雷达技术对比有哪些优势
终于卷到800万像素的车载摄像头
12路1080P高清视频流,米尔RK3576 开发板赋能车载360环视
RK3588平台USB摄像头调试实战:从报错到稳定运行
RK 平台 USB 摄像头成像调试指南:从信号到画质的全流程优化
RK平台车载摄像头开发:从底层到应用的全面解析
评论