新闻  |   论坛  |   博客  |   在线研讨会
征程 6E/M 快速上手实战 Sample-Camera
地平线开发者 | 2024-10-02 10:17:24    阅读:71   发布文章

01 Camera 模块简述


本文档简单介绍 Camera 子系统软件架构、列出已支持的 Camera 模组,并提供相应的配置说明,同时引用 Sensor 点亮调试方法介绍一颗新模组接入的步骤,再按根据重要功能按专题介绍接入方案限制、EMB 接收等,并最终汇总平台已有单板的 Camera 接入使用说明,用于指导 征程6 在 Camera 接入上的量产调试。



1.1 硬件特性

征程6 上 Camera 接入后,进入后级模块处理,其数据流通路主要相关模块有如下:



img


  • 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 处理。



img


此处默认示例使用的模组及连接关系为:


RX 口 LINK 端子模组描述备注 RX0ALCE-OVX8B Fov1203840x2160 RAW12CLCE-OVX8B Fov303840x2160 RAW12DLCE-OVX3C Fov601920x1280 RAW12RX1A-DLCE-OVX3C Fov1001920x1280 RAW12RX4A-DSENSING-ISX031 Fov1901920x1536 YUV422


本 sample 基于 Matrix 6E/M 硬件使用,其硬件连接及数据流通路如下:


img


1.2 软件功能

征程6 的 Sensor 接入属于图像处理子系统中的 Camera 部分,各模块间有结构如下:


img


其中 Camera 部分主要包括:Sensor,Deserial,Poc,Txser 设备驱动及 MIPI 配置操作,系统结构有如下:


img


本 sample 基于 VIO API 实现,调用 libvio 提供的 API,同时通过配置文件的方式,实现单路或多路 Camera 接入验证,并支持将接收的数据图像 dump 到文件系统中,用于图像数据验证,同时还支持可选的 hbplayer 显示功能,用于查看 Camera 输入图像。


img



02 Camera-Sample 使用


本文的 demo sample 实现单路、多路 Camera 接入与处理。


2.1 调用流程

采用 MediaCodec 的 poll 模式来解耦输入和输出,可使编码帧率性能达到最优。在主线程中灌 YUV 数据:取出一个空的 input buffer,配置 YUV 数据的地址信息(如 phys addr),再 queue input buffer 并通知编码器处理该帧数据;另一个线程取输出码流:通过 select 接收硬件编码完成通知,取出一个硬件填满输出码流的 output buffer,将编码结果写到文件中后归还 output buffer。


img


此处的 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 数据。


2.2 源码主干
#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;
}


2.3 编译&运行

获取 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


img


使用 WinScp 将 program 和 cfg 文件夹都传输到单板上。


*WinScp 使用方法请参考征程 6E/M 底软开发 Sample-IPC 2.1.2


硬件连接:


img

img


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


img


可取上述 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 数据


img


*如果出现监视窗口缩放系数错误的问题请尝试修改主机分辨率为 100%:


img





*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客