"); //-->
01 Camera 模块简述
本文档简单介绍 Camera 子系统软件架构、列出已支持的 Camera 模组,并提供相应的配置说明,同时引用 Sensor 点亮调试方法介绍一颗新模组接入的步骤,再按根据重要功能按专题介绍接入方案限制、EMB 接收等,并最终汇总平台已有单板的 Camera 接入使用说明,用于指导 征程6 在 Camera 接入上的量产调试。
征程6 上 Camera 接入后,进入后级模块处理,其数据流通路主要相关模块有如下:
MIPI RX: 3 路 CDPHY,每路为 DPHY 最大 4.5Gbps/lane x 4lane 或 CPHY 最大 3.5Gbps/trio x 3trio,每路支持 4VC,最多支持 12 路接入。
MIPI TX: 2 路 DPHY,每路为 2.5Gbps/lane x 4lane,支持 RX bypass 与 IDU 输出方式。
CIM: RX 接入,可 online 输出到 ISP0/ISP1(RAW)与 PYM0/PYM1(YUV),也可 offline 下 DDR,之后各模块通过 DDR 读取使用数据流。
ISP: 2 个 ISP 设备,各支持 4 路 online+8 路 offline 输入,每个 ISP 最大支持 2x4K@60fps 处理。
PYM: 3 个 PYM 设备,其中 PYM0/PYM1 为全功能模块支持 online/offline,PYM4 只支持 offline,4K@60fps 处理。
GDC: 1 个 GDC 设备,只支持 offline 方式,4K@60fps 处理。
此处默认示例使用的模组及连接关系为:
RX 口 LINK 端子模组描述备注 RX0ALCE-OVX8B Fov1203840x2160 RAW12CLCE-OVX8B Fov303840x2160 RAW12DLCE-OVX3C Fov601920x1280 RAW12RX1A-DLCE-OVX3C Fov1001920x1280 RAW12RX4A-DSENSING-ISX031 Fov1901920x1536 YUV422
本 sample 基于 Matrix 6E/M 硬件使用,其硬件连接及数据流通路如下:
征程6 的 Sensor 接入属于图像处理子系统中的 Camera 部分,各模块间有结构如下:
其中 Camera 部分主要包括:Sensor,Deserial,Poc,Txser 设备驱动及 MIPI 配置操作,系统结构有如下:
本 sample 基于 VIO API 实现,调用 libvio 提供的 API,同时通过配置文件的方式,实现单路或多路 Camera 接入验证,并支持将接收的数据图像 dump 到文件系统中,用于图像数据验证,同时还支持可选的 hbplayer 显示功能,用于查看 Camera 输入图像。
本文的 demo sample 实现单路、多路 Camera 接入与处理。
采用 MediaCodec 的 poll 模式来解耦输入和输出,可使编码帧率性能达到最优。在主线程中灌 YUV 数据:取出一个空的 input buffer,配置 YUV 数据的地址信息(如 phys addr),再 queue input buffer 并通知编码器处理该帧数据;另一个线程取输出码流:通过 select 接收硬件编码完成通知,取出一个硬件填满输出码流的 output buffer,将编码结果写到文件中后归还 output buffer。
此处的 hb_cam_start/hb_cam_stop 为可选调用,目前在 sample 中未直接使用,若有兼容原 VIO API 流程需要,仍支持继续调用。
int32_t hb_vio_init( const char *cfg_file):初始化 VIO 模块,包括 cim& isp & pym & gdc & ynr,初始化配置文件配置的所有 pipeline,多路场景时配置文件对应包含多路配置,vio init 必须最先调用,再调用 hb_cam_init。
int32_t hb_vio_deinit(void):释放 init 中用到的各种资源,内存等。
int32_t hb_cam_init(uint32_t cfg_index,const char *cfg_file):初始化 cam 模块中的 sensor & mipi rx(mipi tx)。
int32_t hb_cam_deinit(uint32_t cfg_index):释放 camera 模块资源,和 hb_cam_init 对应。
int32_t hb_vio_start_pipeline(uint32_t pipeline_id):启动 vio pipe 通路工作,对应初始化中的数据通路。
int32_t hb_cam_start(uint32_t port):启动 sensor 数据流,mipi 检查是否有 hs 信号,使能对应 cim/cimdma。
int32_t hb_vio_get_data(uint32_t pipeline_id, VIO_DATA_TYPE_E info_type,void* data):指定 pipeline_id,通过 type 类型,执行不同的实际操作,得到对应 type 类型的数据结构,获取到的 yuv 图像地址默认是连续的。
int32_t hb_cam_stop(uint32_t port):关闭 sensor 数据流,执行 mipi stop,关闭对应 cim/cimdma。
int32_t hb_vio_stop_pipeline(uint32_t pipeline_id):关闭 vio 对应 pipe id 通路工作,对应初始化中的数据通路,如果数据通路包含 hb_vio_start_pipeline 所打开的,退出时需要先关闭 camera 数据。
#Sample源码路径
/test/samples/platform_samples/source/S83_Sample/S83E04_Module/camera_sample
Encoder:
static void *vflow_frame_thread(void *arg)
{
int32_t ret;
float fps;
struct timeval last, now;
vflow_work_t *vfw = (vflow_work_t *)arg;
char tname[32];
if ((vfw == NULL) || ((uint32_t)vfw->flow_id >= HB_VIO_PIPELINE_MAX)) {
return NULL;
}
snprintf(tname, sizeof(tname), "cam%d:%s", vfw->flow_id, vio_types[vfw->flow_type]);
prctl(PR_SET_NAME, tname);
pr_info("thread %s work\n", tname);
gettimeofday(&last, NULL);
while (check_end() && (vfw->th_create <= 1)) {
ret = vflow_frame_do(vfw);
if (ret < 0) {
usleep(1*1000);
continue;
}
/* fps cal and show */
gettimeofday(&now, NULL);
if (time_cost_ms(&last, &now) >= (FPS_TIMER_MS - 1)) {
memcpy(&last, &now, sizeof(struct timeval));
fps = vfw->frame_cntfps / (FPS_TIMER_MS / 1000.0);
vfw->frame_cntfps = 0;
if (vfw->flow_log & (0x1 << VFLOW_LOG_FPS))
pr_info("camera flow%d:t%d-%s frame %d: fps %.2f\n",
vfw->flow_id, vfw->flow_type, vio_types[vfw->flow_type],
vfw->frame_cntall, fps);
}
}
vfw->th_create = 0;
pr_info("thread %s exit\n", tname);
return NULL;
}
static int32_t vflow_frame_do(vflow_work_t *vfw)
{
int32_t ret, dump = 0;
vflow_img_t img = { 0 };
int32_t flow_id = vfw->flow_id;
uint32_t type = (uint32_t)vfw->flow_type;
char dump_name[128];
int32_t tsdiff = 0;
uint32_t id = 0u, w = 0u, h = 0u;
uint64_t tslast = 0ul, ts = 0ul;
/* get */
ret = vflow_img_get(vfw, &img);
if (ret < 0) {
vfw->frame_err++;
return ret;
}
/* base info */
vflow_img_baseinfo(vfw, &img, &id, &ts, &w, &h);
vfw->frame_cntall++;
vfw->frame_cntfps++;
tslast = (vfw->ts_last) ? vfw->ts_last : ts;
vfw->ts_last = ts;
/* get show */
if (vfw->flow_log & (0x1 << VFLOW_LOG_GET)) {
tsdiff = ts_diff(tslast, ts);
pr_info("camera flow%d:t%d-%s get: ts %lu.%06lu (+%d %.3fms) id %d\n",
flow_id, type, vio_types[type], ts2s(ts), ts2us(ts),
tsdiff, (ts2us(tsdiff) / 1000.0), id);
}
/* info show */
if (vfw->flow_log & (0x1 << VFLOW_LOG_INFO)) {
vflow_img_info(vfw, &img);
}
/* detail show */
if (vfw->flow_log & (0x1 << VFLOW_LOG_DETAIL)) {
vflow_img_detail(vfw, &img);
}
/* dump */
if (vfw->flow_dump) {
if ((vfw->flow_dadd) && ((vfw->frame_cntall % vfw->flow_dadd) == 0)) {
dump = 1;
}
if ((vfw->flow_dmax) && (vfw->frame_dump < vfw->flow_dmax)) {
dump = 1;
}
if (dump) {
snprintf(dump_name, sizeof(dump_name), "p%d_cam_%s_%dx%d_d%d_f%u_t%lu.%lu.%s",
vfw->flow_id, vio_types[type], w, h,
vfw->frame_dump, id, ts2s(ts), ts2us(ts), vio_filetypes[type]);
vflow_img_dump(dump_name, &img);
vfw->frame_dump++;
}
}
/* show */
if (vfw->flow_show) {
if ((vfw->frame_cntall % vfw->flow_show) == 0)
vflow_show_img(vfw, &img);
}
/* free */
vflow_img_free(vfw, &img);
return ret;
}
获取 AppSDK 包后,进入 appuser 执行:
*其中 hbrootfs-sdk_0.0.1.XXX_all.deb 是地平线自己的库和头文件,rootfs-sdk-focal_0.0.1.XXX_all.deb 是系统库,aarch64-linux-hb-gcc_12.2.0_amd64.deb 是 gcc 12.2.0 工具链,目前在 ubuntu22.04 非 docker 环境下运行正常。其它环境不能保证。
dpkg-deb -x rootfs-sdk*.deb ./sdk
dpkg-deb -x hbrootfs-sdk*.deb ./sdk
##移动sdk库路径,本文档放入/usr/lib中
sudo mv sdk/ /usr/lib
进入 toolchain 执行:
dpkg -x aarch64-linux-hb-gcc_12.2.0_amd64.deb ./arm-gnu-toolchain
##移动toolchain库路径,本文档放入/usr/lib中
sudo mv arm-gnu-toolchain/ /usr/lib
nano ~/.bashrc
##添加系统路径
export PATH="/usr/lib/arm-gnu-toolchain/bin:$PATH"
export LD_LIBRARY_PATH="/usr/lib/arm-gnu-toolchain/lib:$LD_LIBRARY_PATH"
##
source ~/.bashrc
Sample 代码路径:
#Sample源码路径
/test/samples/platform_samples/source/S83_Sample/S83E04_Module/camera_sample
运行参数说明:
参数名说明是否必须备注-c 指定 Camera 配置文件,默认为。/hb_j6dev.json 否若非当前目录,需指定-v 指定 VIO 配置文件,默认为。/vpm_config.json 否若非当前目录,需指定-p 指定运行 camera 通道的数量,默认为自动获取否若非全运行,需指定-M 指定运行 camera 通路的掩码,默认为自动获取否若非全运行,可指定-t 指定要获取的数据类型,按 bit 掩码,默认为 CIM_RAW 支持 b#的方式进行配置,如:CIM_RAW:b24,CIM_YUV:b25 否若为 YUV 数据,需指定-d 使能 dump 功能,将数据 dump 到当前运行目录下支持 dump 数量设置,如:-d 10 为前 10 帧否若要 dump 数据,需使能-s 使能 hbplayer 显示功能否若要显示查看,需使能-S 配置 hbplayer 显示用端口,默认 0 使用默认端口否-l 指定 log 打印信息,通过 bit 掩码配置,默认为 1,只打印 fps 统计信息:b0-fps 统计信息,b1-取帧时信息,b2-帧基础信息,b3-帧详细信息,b4-显示发送信息;否-r 指定运行时间,默认为 0,只验证配置后立即退出是若要长时运行,需指定-V 获取 sample 版本信息否-h 查看帮助信息否
复制/src 源码到新建文件夹 codec 并构建新 Makefile:
camera
├── cfg
│ └── case_matrix
│ └── ...
├── Makefile
├── program
└── src
├── camera_sample.c
└── camera_sample.o
Makefile:
CROSS_COMPILE = aarch64-none-linux-gnu-
OUTPUT_HBROOTFS_DIR = /usr/lib/sdk
CXX := ${CROSS_COMPILE}gcc
INC_DIR := ${OUTPUT_HBROOTFS_DIR}/usr/hobot/include
INC_DIR += ${OUTPUT_HBROOTFS_DIR}/include
LIB_DIR := ${OUTPUT_HBROOTFS_DIR}/usr/hobot/lib
LIB_DIR += ${OUTPUT_HBROOTFS_DIR}/usr/lib/aarch64-linux-gnu
LIBS += -lvio -lpthread -lalog -lhbmem -lvpf
LIBS += -lhbplayer -lcam -lcjson -lgdcbin
CXXFLAGS := -Wall -O2 $(foreach dir,$(INC_DIR),-I$(dir))
CXXFLAGS += -DENABLE_HBPLAYER
LDFLAGS := $(addprefix -L, $(LIB_DIR)) $(LIBS)
SRC_DIR := src
TARGET := program
SRCS := $(wildcard $(SRC_DIR)/*.c)
OBJS := $(SRCS:.c=.o)
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@
%.o: %.c
$(CXX) $(CXXFLAGS) -c $< -o $@
clean:
rm -f $(OBJS) $(TARGET)
执行 make 完成编译,生成的文件为。/program
使用 WinScp 将 program 和 cfg 文件夹都传输到单板上。
*WinScp 使用方法请参考征程 6E/M 底软开发 Sample-IPC 2.1.2
硬件连接:
RX 口 LINK 端子模组描述 RX0ALCE-OVX8B Fov1203840x2160 RAW12CLCE-OVX8B Fov303840x2160 RAW12DLCE-OVX3C Fov601920x1280 RAW12RX1A-DLCE-OVX3C Fov1001920x1280 RAW12
chmod +x program
#camera
#1V_OVX8B_RX0
./program -c ./cfg/case_matrix/1V_OVX8B_RX0/hb_j6dev.json -v cfg/case_matrix/1V_OVX8B_RX0/vpm_config.json -r 10
#2V_OVX8B_OVX3C_RX0
./program -c ./cfg/case_matrix/2V_OVX8B_OVX3C_RX0/hb_j6dev.json -v cfg/case_matrix/2V_OVX8B_OVX3C_RX0/vpm_config.json -r 10
#3V_2xOVX8B_1xOVX3C_RX0
./program -c ./cfg/case_matrix/3V_2xOVX8B_1xOVX3C_RX0/hb_j6dev.json -v cfg/case_matrix/3V_2xOVX8B_1xOVX3C_RX0/vpm_config.json -r 10
#4V_4xOVX3C_RX1
./program -c ./cfg/case_matrix/4V_4xOVX3C_RX1/hb_j6dev.json -v cfg/case_matrix/4V_4xOVX3C_RX1/vpm_config.json -r 10
#4V_4xISX031_RX4
./program -c ./cfg/case_matrix/3V_2xOVX8B_1xOVX3C_RX0/hb_j6dev.json -v cfg/case_matrix/3V_2xOVX8B_1xOVX3C_RX0/vpm_config.json -r 10
Sample 运行时日志:*1V
[camera_sample]:cam_cfg_file = ./cfg/case_matrix/1V_OVX8B_RX0/hb_j6dev.json
[camera_sample]:vio_cfg_file = cfg/case_matrix/1V_OVX8B_RX0/vpm_config.json
[camera_sample]:run_time = 10
[camera_sample]:camera_sample start
[camera_sample]:hb_vio_init(cfg/case_matrix/1V_OVX8B_RX0/vpm_config.json) ...
[camera_sample]:hb_cam_init(0, ./cfg/case_matrix/1V_OVX8B_RX0/hb_j6dev.json) ...
[camera_sample]: auto get 1 pipe mask 0x1
[camera_sample]:hb_vio_start_pipeline(0) ...
[camera_sample]:thread cam0:CIM_RAW work
[camera_sample]:camera flow0:t24-CIM_RAW frame 25: fps 25.00
[camera_sample]:camera flow0:t24-CIM_RAW frame 50: fps 25.00
[camera_sample]:camera flow0:t24-CIM_RAW frame 75: fps 25.00
[camera_sample]:camera flow0:t24-CIM_RAW frame 100: fps 25.00
[camera_sample]:camera flow0:t24-CIM_RAW frame 125: fps 25.00
[camera_sample]:camera flow0:t24-CIM_RAW frame 150: fps 25.00
[camera_sample]:camera flow0:t24-CIM_RAW frame 175: fps 25.00
[camera_sample]:camera flow0:t24-CIM_RAW frame 200: fps 25.00
[camera_sample]:camera flow0:t24-CIM_RAW frame 225: fps 25.00
[camera_sample]:thread cam0:CIM_RAW exit
[camera_sample]:hb_vio_stop_pipeline(0) ...
[camera_sample]:hb_cam_deinit() ...
[camera_sample]:hb_vio_deinit() ...
[camera_sample]:camera_sample end 0 --> PASS
运行过程中还可通过以下命令查看帧率信息:
cat /sys/class/vps/flow/fps
sample 支持将数据 dump 到文件系统,供查看验证,只需在运行命令加上:-d 10 (dump 前 10 帧)。
#1V_OVX8B_RX0
./program -c ./cfg/case_matrix/1V_OVX8B_RX0/hb_j6dev.json -v cfg/case_matrix/1V_OVX8B_RX0/vpm_config.json -d 10 -r 10
可取上述 raw 数据查看使用。
hbplayer 显示:
本 sample 支持将数据通过网络发送到 PC 端,配合 hbplayer 工具,在线查看数据流接入,只需在运行命令加上:-s 1 (若要长时间运行,可通过-r 调整运行时间)。
./program -c ./cfg/case_matrix/1V_OVX8B_RX0/hb_j6dev.json -v cfg/case_matrix/1V_OVX8B_RX0/vpm_config.json -r 100 -s 1
之后运行,将自动获取图像并发送给 hbplayer。
PC 打开 hbplayer\out\hbplayer.exe:*获取的为 raw 数据
*如果出现监视窗口缩放系数错误的问题请尝试修改主机分辨率为 100%:
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。