
SA8295平台QCarCamera
QCarCamera(简称QCarCam)是高通车载AIS(Automotive Imaging Subsystem)成像子系统对外统一C语言API,是SA8295座舱/智驾开发板读取GMSL摄像头图像的标准中间件。
核心特性:
- 上层API跨高通SoC通用:SA8155/SA8295/SA8650函数名、调用流程完全一致;
- 底层资源板级强绑定:libqcarcam.so、头文件、硬件配置文件仅适配对应8295项目BSP,无法跨开发板复用;
- 双系统支持:Android IVI座舱、QNX ADAS智驾共用同一套API,仅内存/权限编译配置存在差异。
SA8295 QCarCam整体业务运行流程

1. 整体时序流程图
完整执行链路:
qcarcam_initialize → qcarcam_query_inputs → qcarcam_open → qcarcam_s_buffers → qcarcam_start → 循环qcarcam_get_frame图像处理 → qcarcam_release_frame → qcarcam_stop → qcarcam_close → qcarcam_uninitialize
2. 分步业务说明(SA8295专属要点)
- 全局初始化 qcarcam_initialize
建立应用与AIS后台服务通信通道,SA8295必须传入匹配BSP基线的版本号,版本不匹配直接初始化失败。 - 枚举摄像头 qcarcam_query_inputs
读取qcarcam_config.xml硬件配置,获取8295开发板CSI通道、GMSL解串器、各路Camera ID、支持分辨率/格式;8295最多支持6路GMSL3摄像头,8155仅4路,结构体字段存在差异。 - 打开指定摄像头 qcarcam_open
根据Input ID创建相机句柄,多路AVM环视场景可并行打开4路/6路句柄。 - 配置图像缓冲区 qcarcam_s_buffers
SA8295推荐buffer数量5~8个,底层使用ION物理共享内存;QNX平台使用pmem物理内存,缓冲区分配逻辑与Android不同。 - 启动数据流 qcarcam_start
触发Sensor上电、SerDes寄存器初始化、ISP流水线启动,开始持续输出图像帧。 - 取流+释放帧(核心业务)
qcarcam_get_frame阻塞/非阻塞获取一帧图像数据,完成算法/预览处理后必须调用qcarcam_release_frame归还buffer,否则缓冲区耗尽断流。 - 停止、关闭、反初始化
必须完整执行逆序销毁,否则8295会出现Camera资源锁死,进程重启也无法重新打开摄像头。
核心API
头文件依赖:#include "QCarCam.h"、#include "QCarCam_types.h",仅能使用当前SA8295项目BSP内的头文件,其他平台头文件结构体字段缺失。
1. 生命周期基础API
(1)全局初始化
c
qcarcam_ret_t qcarcam_initialize(qcarcam_init_t* p_init_params);
- 入参:版本号、日志等级、事件回调;
- SA8295坑点:
qc_version必须和libqcarcam.so编译基线一致,混用8155头文件会报参数错误407; - 返回值:
QCARCAM_RET_OK成功,其余为错误码。
(2)枚举可用摄像头
c
qcarcam_ret_t qcarcam_query_inputs(qcarcam_input_t* p_inputs, unsigned int size, unsigned int* ret_size);
- 作用:查询8295开发板硬件配置的所有Camera,获取ID、宽高、色彩格式;
- 使用方式:先传size=0获取摄像头总数,再分配数组二次读取详细信息。
(3)打开摄像头获取句柄
c
qcarcam_hndl_t qcarcam_open(qcarcam_input_desc_t desc);
- 入参:
input_id摄像头编号(0~5,8295最大6路)、流模式(预览/RAW); - 返回:非空句柄代表打开成功;NULL表示CSI通道被占用、硬件配置错误。
(4)缓冲区配置(关键)
c
qcarcam_ret_t qcarcam_s_buffers(qcarcam_hndl_t hndl, qcarcam_buffers_t* p_buffers);
- 配置:buffer个数、图像宽高、NV12/NV21/RAW格式、内存平面;
- SA8295规范:n_buffers≥5,低于2帧直接启动失败。
(5)启停数据流
c
qcarcam_ret_t qcarcam_start(qcarcam_hndl_t hndl); // 开始出图
qcarcam_ret_t qcarcam_stop(qcarcam_hndl_t hndl); // 停止出图
(6)帧存取核心接口
c
// 获取一帧图像
qcarcam_ret_t qcarcam_get_frame(qcarcam_hndl_t hndl, qcarcam_frame_t* p_frame, uint32_t timeout_ms);
// 处理完成归还buffer(不可省略)
qcarcam_ret_t qcarcam_release_frame(qcarcam_hndl_t hndl, qcarcam_frame_t* p_frame);
- timeout_ms:0非阻塞,>0阻塞等待帧;
- 漏调用release_frame:8295底层buffer池耗尽,几秒后断流,无报错日志。
(7)销毁资源
c
qcarcam_ret_t qcarcam_close(qcarcam_hndl_t hndl); // 关闭单路相机
qcarcam_ret_t qcarcam_uninitialize(void); // 全局反初始化
- 强制规范:所有句柄close完成后再调用uninitialize,否则下次初始化直接失败。
2. 辅助控制API
qcarcam_s_param:设置事件回调、曝光、增益、镜像翻转等ISP参数;qcarcam_get_param:读取当前帧率、硬件状态、错误事件;qcarcam_get_error_str:错误码转可读字符串,用于8295日志调试。
3. 标准极简Demo代码片段(SA8295通用)
c
#include "QCarCam.h"
#include <stdio.h>
int main() {
// 1. 全局初始化
qcarcam_init_t init_param = {0};
init_param.qc_version = QCARCAM_VERSION;
qcarcam_ret_t ret = qcarcam_initialize(&init_param);
if(ret != QCARCAM_RET_OK) {
printf("初始化失败 err:%d\n", ret);
return -1;
}
// 2. 查询摄像头数量
unsigned int cam_cnt = 0;
qcarcam_query_inputs(NULL, 0, &cam_cnt);
qcarcam_input_t inputs[6] = {0}; // SA8295最大6路
qcarcam_query_inputs(inputs, cam_cnt, &cam_cnt);
// 3. 打开0号摄像头
qcarcam_input_desc_t desc = {.input_id = 0};
qcarcam_hndl_t hCam = qcarcam_open(desc);
if(hCam == NULL) {
printf("打开摄像头0失败\n");
goto deinit;
}
// 4. 配置Buffer
qcarcam_buffers_t buf_cfg = {0};
buf_cfg.n_buffers = 5;
buf_cfg.color_fmt = QCARCAM_FMT_NV12;
buf_cfg.width = 1920;
buf_cfg.height = 1080;
qcarcam_s_buffers(hCam, &buf_cfg);
// 5. 启动采集
qcarcam_start(hCam);
// 循环取流100帧
for(int i=0; i<100; i++) {
qcarcam_frame_t frame = {0};
ret = qcarcam_get_frame(hCam, &frame, 1000);
if(ret == QCARCAM_RET_OK) {
// 图像处理逻辑
printf("获取帧 %d, 宽度:%d\n", i, frame.planes[0].width);
qcarcam_release_frame(hCam, &frame); // 必须归还
}
}
// 逆序销毁
qcarcam_stop(hCam);
qcarcam_close(hCam);
deinit:
qcarcam_uninitialize();
return 0;
}
QCarCam_types.h 和 QCarCam_diag_types.h
- QCarCam_types.h :业务主类型,所有相机生命周期、帧、buffer、输入设备、参数、返回码都在这里,写采集程序必包含;
- QCarCam_diag_types.h:诊断/调试专用类型,日志等级、故障码、诊断事件、性能统计、ISP诊断信息,用于问题定位、量产诊断;
- 两者均板级强绑定:SA8295 基线内的头文件不能和 SA8155/8650 混用,结构体存在扩展字段差异;
- 依赖关系:
QCarCam.h内部依赖QCarCam_types.h,诊断接口函数依赖QCarCam_diag_types.h。
第一部分 QCarCam_types.h 核心结构体/枚举详解
1. 基础返回码枚举 qcarcam_ret_t
所有 API 统一返回该类型,判断接口成败
c
typedef enum {
QCARCAM_RET_OK = 0, // 成功
QCARCAM_RET_FAILED, // 通用失败
QCARCAM_RET_INVALID_PARAM, // 参数非法
QCARCAM_RET_OUT_OF_MEM, // 内存不足
QCARCAM_RET_TIMEOUT, // 取帧超时
QCARCAM_RET_NO_FRAME, // 无可用帧
QCARCAM_RET_BUSY, // 相机被占用
QCARCAM_RET_NOT_SUPPORTED, // 当前硬件/ISP不支持该功能
QCARCAM_RET_INVALID_HANDLE, // 无效相机句柄
QCARCAM_RET_VERSION_MISMATCH, // 应用版本与AIS服务不匹配(8295高频报错407根源)
QCARCAM_RET_RESOURCE_LOCKED, // 硬件资源锁死
QCARCAM_RET_IO_ERROR, // CSI/SerDes硬件IO错误
} qcarcam_ret_t;
SA8295 重点坑:
QCARCAM_RET_VERSION_MISMATCH绝大多数是头文件/libqcarcam.so/AIS基线三套不配套导致。
2. 全局初始化结构体 qcarcam_init_t
qcarcam_initialize() 入参,控制全局客户端配置
c
typedef struct {
uint32_t qc_version; // QCARCAM_VERSION,必须与lib基线一致
uint32_t log_level; // 日志等级(与diag日志枚举互通)
void (*event_cb)(qcarcam_event_t event, void* user_data); // 全局事件回调
void* user_data; // 回调透传私有数据
uint32_t reserved[8];
} qcarcam_init_t;
qc_version:8295 BSP 内宏QCARCAM_VERSION,直接赋值即可,手写数字极易版本不匹配。
3. 图像色彩格式枚举 qcarcam_color_fmt_t
配置 buffer、帧数据格式,SA8295 支持 GMSL RAW+YUV 多路输出
c
typedef enum {
QCARCAM_FMT_INVALID = 0,
QCARCAM_FMT_NV12, // 主流预览、AVM环视使用
QCARCAM_FMT_NV21,
QCARCAM_FMT_YUYV,
QCARCAM_FMT_UYVY,
QCARCAM_FMT_RAW8,
QCARCAM_FMT_RAW10, // 8295 ISP原生10bit RAW(8155部分基线缺失)
QCARCAM_FMT_RAW12,
QCARCAM_FMT_RGB888,
QCARCAM_FMT_ARGB8888,
} qcarcam_color_fmt_t;
4. 相机输入设备信息 qcarcam_input_t / qcarcam_input_desc_t
qcarcam_input_t(qcarcam_query_inputs 输出,硬件静态信息)
c
typedef struct {
uint32_t input_id; // 相机编号 0~5(SA8295最大6路)
char sensor_name[32]; // 传感器名称 ar0144/ox08b等
uint32_t width; // 硬件最大分辨率宽
uint32_t height; // 硬件最大分辨率高
qcarcam_color_fmt_t fmt_list[16]; // 该摄像头支持的格式列表
uint32_t fmt_cnt;
uint32_t csi_port; // 绑定的CSI通道号
uint32_t gmsl_ver; // GMSL1/GMSL2/GMSL3(8295独有)
uint32_t reserved[16];
} qcarcam_input_t;
qcarcam_input_desc_t(qcarcam_open 入参,打开相机配置)
c
typedef struct {
uint32_t input_id; // 指定打开哪一路相机
uint32_t stream_mode; // 预览流/RAW流/算法流
uint32_t reserved[4];
} qcarcam_input_desc_t;
5. 缓冲区配置结构体 qcarcam_buffers_t
qcarcam_s_buffers() 设置帧池,采集核心配置
c
typedef struct {
uint32_t n_buffers; // buffer数量,SA8295推荐5~8
uint32_t width;
uint32_t height;
qcarcam_color_fmt_t color_fmt;
uint32_t stride[4]; // 各平面行宽
uint32_t plane_cnt; // YUV2平面、RAW单平面
uint32_t buf_size; // 单帧总字节大小
uint32_t reserved[8];
} qcarcam_buffers_t;
坑:n_buffers < 2 时 qcarcam_start 直接返回 NOT_SUPPORTED。
6. 帧数据结构体 qcarcam_frame_t(业务最常用)
qcarcam_get_frame 输出,承载一帧图像内存、时间戳、元数据
c
typedef struct {
// 图像平面地址(ION/PMEM物理虚拟地址)
qcarcam_plane_t planes[4];
uint32_t plane_cnt;
uint64_t timestamp_us; // Sensor出图时间戳,同步AVM拼接关键
uint32_t frame_id; // 帧序号,丢帧可通过序号判断
uint32_t width;
uint32_t height;
qcarcam_color_fmt_t fmt;
// 帧状态标记
uint32_t flags;
#define QCARCAM_FRAME_FLAG_DROPPED (1 << 0) // 丢帧标记
#define QCARCAM_FRAME_FLAG_ERROR (1 << 1) // 该帧图像损坏
void* priv_buf_handle; // 底层buffer私有句柄,release时内部使用,业务不可修改
uint32_t reserved[8];
} qcarcam_frame_t;
附属:qcarcam_plane_t 单平面内存信息
c
typedef struct {
uint8_t* virt_addr; // 用户态虚拟地址(直接取图像数据)
uint64_t phys_addr; // 物理地址,GPU/算法渲染使用
int32_t fd; // ION buffer fd(Android特有,QNX无意义)
uint32_t stride;
uint32_t size;
} qcarcam_plane_t;
7. 参数控制类型:qcarcam_param_t
qcarcam_s_param / qcarcam_get_param 用于曝光、增益、镜像、回调设置
c
typedef enum {
QCARCAM_PARAM_EXPOSURE,
QCARCAM_PARAM_GAIN,
QCARCAM_PARAM_FLIP_H, // 水平翻转
QCARCAM_PARAM_FLIP_V, // 垂直翻转
QCARCAM_PARAM_EVENT_CB, // 单路相机帧事件回调
QCARCAM_PARAM_FPS,
QCARCAM_PARAM_AE_MODE, // 自动曝光开关
QCARCAM_PARAM_AWB_MODE, // 自动白平衡
// SA8295扩展:多路同步、HDR、畸变矫正参数
QCARCAM_PARAM_MULTI_SYNC,
QCARCAM_PARAM_HDR_ENABLE,
} qcarcam_param_id_t;
// 参数值通用联合体
typedef union {
uint32_t u32;
int32_t i32;
float f32;
void (*cb)(...);
uint8_t data[64];
} qcarcam_param_val_t;
typedef struct {
qcarcam_param_id_t id;
qcarcam_param_val_t val;
} qcarcam_param_t;
8. 事件枚举 qcarcam_event_t
全局/单路回调上报硬件异常、状态变更
c
typedef enum {
QCARCAM_EVENT_FRAME_READY, // 帧就绪
QCARCAM_EVENT_ERROR, // 硬件故障
QCARCAM_EVENT_SENSOR_LOST, // Sensor断线、GMSL断开
QCARCAM_EVENT_STREAM_STOP, // 流主动停止
QCARCAM_EVENT_OVERFLOW, // buffer池耗尽
} qcarcam_event_t;
第二部分 QCarCam_diag_types.h 诊断类型头文件
该头文件不参与基础图像采集,用于日志调试、故障诊断、性能统计、产线检测,定位8295相机卡顿、丢帧、硬件断线问题必备。
1. 诊断日志等级枚举 qcarcam_diag_log_level_t
与 qcarcam_init_t.log_level 一一对应
c
typedef enum {
QCARCAM_DIAG_LOG_LEVEL_NONE = 0, // 关闭日志
QCARCAM_DIAG_LOG_LEVEL_ERROR, // 仅错误
QCARCAM_DIAG_LOG_LEVEL_WARN, // 警告+错误
QCARCAM_DIAG_LOG_LEVEL_INFO, // 普通信息
QCARCAM_DIAG_LOG_LEVEL_DEBUG, // 调试日志(开发使用)
QCARCAM_DIAG_LOG_LEVEL_VERBOSE, // 全量底层打印(性能损耗大)
} qcarcam_diag_log_level_t;
开发调试设置 log_level = QCARCAM_DIAG_LOG_LEVEL_DEBUG;量产版本仅保留 ERROR。
2. 诊断故障码 qcarcam_diag_fault_code_t
用于读取相机硬件永久/瞬时故障,产线检测、售后定位
c
typedef enum {
// 通用故障
QCARCAM_DIAG_FAULT_NONE = 0,
QCARCAM_DIAG_FAULT_SENSOR_PWR_FAIL, // Sensor供电失败
QCARCAM_DIAG_FAULT_SERDES_COMM_ERR, // GMSL解串器通讯失败
QCARCAM_DIAG_FAULT_CSI_LANE_ERR, // CSI Lane信号丢失
QCARCAM_DIAG_FAULT_BUFFER_OVERRUN, // buffer溢出丢帧
QCARCAM_DIAG_FAULT_ISP_HANG, // ISP流水线卡死
QCARCAM_DIAG_FAULT_CLOCK_ERR, // 相机时钟异常
// SA8295 GMSL3专属故障
QCARCAM_DIAG_FAULT_GMSL_LINK_DEGRADE, // GMSL链路信号衰减
} qcarcam_diag_fault_code_t;
3. 单路相机性能统计结构体 qcarcam_diag_stream_stats_t
用于统计帧率、丢帧、处理耗时,分析AVM卡顿根源
c
typedef struct {
uint64_t total_frames; // 总出帧数量
uint64_t dropped_frames; // 累计丢帧
uint32_t avg_fps; // 平均帧率
uint32_t min_fps;
uint32_t max_fps;
uint64_t total_get_frame_latency_us; // 取帧平均耗时
uint32_t underrun_count; // 底层buffer空次数
uint32_t overrun_count; // buffer占满次数
uint32_t reserved[16];
} qcarcam_diag_stream_stats_t;
配套API:qcarcam_diag_get_stream_stats(),传入相机句柄获取实时统计。
4. 硬件链路诊断信息 qcarcam_diag_link_info_t
读取GMSL、CSI物理层状态,排查图像花屏、闪屏
c
typedef struct {
uint32_t input_id;
uint32_t gmsl_lane_rate; // GMSL链路速率
uint32_t csi_lane_count; // CSI lane数量 2/4
uint32_t ber_count; // 误码计数,非0代表线路干扰
uint32_t serdes_chip_id; // 解串器芯片ID MAX96717/MAX9296
uint8_t link_health; // 0=正常,>0链路衰减
uint32_t reserved[8];
} qcarcam_diag_link_info_t;
5. ISP 诊断参数结构体 qcarcam_diag_isp_info_t
读取AE/AWB/ISP内部状态,图像偏暗、偏色调试使用
c
typedef struct {
float current_exposure;
float current_gain;
uint32_t ae_status; // 自动曝光锁定/调整中
uint32_t awb_status;
float lux_value; // 环境亮度
uint32_t isp_temp_c; // ISP硬件温度,高温会降帧
uint32_t reserved[8];
} qcarcam_diag_isp_info_t;
6. 全局诊断配置结构体 qcarcam_diag_config_t
动态控制诊断日志、故障上报开关
c
typedef struct {
qcarcam_diag_log_level_t log_lvl;
uint32_t fault_report_enable; // 故障实时上报开关
uint32_t stats_collect_enable; // 性能统计采集开关
uint32_t reserved[4];
} qcarcam_diag_config_t;
配套接口:
qcarcam_diag_set_config():动态修改日志等级qcarcam_diag_get_fault():查询指定相机故障码
两者头文件使用场景区分
1. 只做图像采集(AVM/预览/算法取图)
仅需包含:
c
#include "QCarCam.h"
#include "QCarCam_types.h"
无需引入 diag 头文件,减少编译依赖。
2. 需要调试、性能分析、故障检测、产线自检
双文件都要引入:
c
#include "QCarCam.h"
#include "QCarCam_types.h"
#include "QCarCam_diag_types.h"
适用场景:
- 开发阶段打印详细调试日志;
- 排查丢帧、花屏、GMSL断线;
- 统计帧率延迟做性能优化;
- 量产自检程序,上报相机硬件故障。
双头文件完整demo片段
c
#include <stdio.h>
#include "QCarCam.h"
#include "QCarCam_types.h"
#include "QCarCam_diag_types.h"
int main() {
qcarcam_init_t init = {0};
init.qc_version = QCARCAM_VERSION;
// 开启诊断调试日志
init.log_level = QCARCAM_DIAG_LOG_LEVEL_DEBUG;
qcarcam_ret_t ret = qcarcam_initialize(&init);
// 打开相机省略...
qcarcam_hndl_t hCam;
// 读取诊断性能统计
qcarcam_diag_stream_stats_t stats = {0};
qcarcam_diag_get_stream_stats(hCam, &stats);
printf("丢帧总数:%llu,平均帧率:%d\n", stats.dropped_frames, stats.avg_fps);
// 读取硬件链路故障
qcarcam_diag_fault_code_t fault;
qcarcam_diag_get_fault(hCam, &fault);
if(fault != QCARCAM_DIAG_FAULT_NONE) {
printf("相机硬件故障码:%d\n", fault);
}
// 释放资源省略
return 0;
}
总结
- 代码复用 vs 编译环境隔离
上层C业务逻辑(初始化、取流)可直接在8155/8295通用;但编译工具链、libqcarcam、头文件、硬件配置文件必须每块8295项目独立,不可跨板拷贝。 - 版本强绑定三要素
头文件、libqcarcam.so、开发板AIS服务基线三者必须来自同一套SA8295 BSP,任意一个版本不一致都会初始化失败。 - 资源销毁严格逆序
不完整关闭会导致Camera硬件锁死,只能重启开发板恢复。 - 缓冲区配置规范
SA8295推荐5~8个buffer,低于2帧直接启动失败,取流后必须release_frame。 - 编译环境红线
禁止使用PC本地NDK、系统GCC编译QCarCam程序,仅允许BSP自带交叉工具链。
