写点什么

征程 6E/M|多 camera 场景示例

  • 2025-09-06
    广东
  • 本文字数:9356 字

    阅读完需:约 31 分钟

征程 6E/M|多 camera 场景示例

1. 功能概述

本 sample 提供全链路场景 1V,4V,7V 使用演示,实现单路及多路 VIO 接入,逐级经过 ISP、PYM、BPU、CODEC 模块处理。

1.1. 软件架构说明

本 sample 调用 VIO API 来实现整个数据通路,实现单路、多路 camera 接入,并能够 dump 每一路数据的图像。调用 BPU API 使用 BPU 模块,并依赖 libhbucp.so 等库中的算法 API 实现对视频图像的目标检测与识别。调用 MediaCodec API,经过 VPU 实现对视频图像的编码,保存为本地的 H265 格式视频。


软件控制图如下:


1.2. 硬件数据流说明

每个场景的图中已经标明硬件连接关系。


1V 场景如下:



4V 场景如下:



7V 场景如下:


1.3. 代码位置及目录结构

sample 代码位置在 SDK 工程目录 **{sdk_dir}/test/samples/platform_samples/source/S83_Sample/S83E06_Tros/vio_full_link_sample**;


目录结构如下:


vio_full_link_sample/    ├── Kconfig    ├── Makefile    ├── Makefile.in    ├── cfg                              # JSON files        ├── lib                              # dynamic libraries        |   ├── libhbucp.so    |   └── ...    ├── res    |   └── fcos.hbm                     # model hbm file        └── src        ├── include        ├── utils                        # utility codes                |   ├── bpu_dnn.cpp        |   ├── codec_venc.c        |   └── ...        ├── vio_full_link_sample.c       # core code                ├── run_vio_full_link_sample.sh  # sample execution script                ├── run_vio_full_link_sample_4V.sh  # sample execution script                ├── run_vio_full_link_sample_7V.sh  # sample execution script                └── Makefile
复制代码


根目录包含 Kconfig 和外部接口的 **Makefile**, Kconfig 用于控制本 sample 是否加入整体编译; 根目录中的 cfg 目录包含本 sample 用到的 JSON 配置文件; lib 目录包含本 sample 用到的动态库;res 目录包含本 sample 用到的 hbm 模型文件。


src 目录下的 Makefile 用于 src 目录下的编译; vio_full_link_sample.c 是 main 入口的所在文件; run_vio_full_link_sample.sh run_vio_full_link_sample_4V.sh run_vio_full_link_sample_7V.sh 是本 sample 在板端的运行脚本; src 目录中的 include 目录为头文件所在目录;utils 目录包含一些功能性代码。

1.4. API 流程说明

API 流程图如下:



需要注意的是,当将 pym 数据帧送入 VPU 编码时,对应 buffer 会先放入 buf_ctl 的状态队列中,当该帧编码完成后才会释放。


主干代码:


int main(int argc, char *argv[]){    int ret = 0;    pthread_t thid[HB_VIO_PIPELINE_MAX];        uint32_t pipe_id[HB_VIO_PIPELINE_MAX];         signal(SIGINT, get_exit_signal);            // get opts    ret = get_opts_for_vio(argc, argv);        if (ret < 0) {             vio_print_err("get opts err!\n");        return -1;        }    #ifdef ENABLE_BPU    ret = bpu_dnn_init(g_bpu_hbm);    if (ret < 0) {        vio_print_err("bpu_hbm_init\n");            goto err;    }#endif
ret = hb_vio_init(g_vpm_config); if (ret < 0) { vio_print_err("hb_vio_init\n"); goto err; } ret = hb_cam_init(0, g_cam_config); if (ret < 0) { hb_vio_deinit(); vio_print_err("hb_cam_init\n"); goto err; } #ifdef ENABLE_HBPLAYER vio_full_link_sample_event = hb_tool_start_transfer(0); if (vio_full_link_sample_event != NULL) { hb_tool_event_setcb(vio_full_link_sample_event, NULL, NULL, NULL, NULL, NULL); } else { vio_print_err("vio_full_link_sample_event is NULL\n"); ret = -1; goto err; }#endif
start_timer(); for (uint32_t id = 0; id < HB_VIO_PIPELINE_MAX; id++) { if (((g_port_mask >> id) & 0x0001) == 0) continue; ret = hb_vio_start_pipeline(id); if (ret < 0) { hb_cam_deinit(0); hb_vio_deinit(); vio_print_err("hb_vio_start_pipeline"); goto err; } else { vio_print_info("hb_vio_start_pipeline done"); } ret = hb_cam_start(id); if (ret < 0) { hb_vio_stop_pipeline(id); hb_cam_deinit(0); hb_vio_deinit(); vio_print_err("hb_cam_start"); goto err; } pipe_id[id] = id;#ifdef ENABLE_MULTI_MEDIA ret = pthread_create(&codec_thid[id], NULL, codec_encoding, (void *)(&pipe_id[id])); vio_print_dbg("pipe(%d)Test encode work thread---running.\n", id);#endif
ret = pthread_create(&thid[id], NULL, vio_worker_thread, (void *)(&pipe_id[id])); vio_print_dbg("pipe(%d)Test vio work thread---running.\n", id); }
sleep(1);
for (uint32_t id = 0; id < HB_VIO_PIPELINE_MAX; id++) { if (((g_port_mask >> id) & 0x0001) == 0) continue; vio_print_dbg("pipe(%d)Test vio work thread---try stop.\n", id); }
for (uint32_t id = 0; id < HB_VIO_PIPELINE_MAX; id++) { if (((g_port_mask >> id) & 0x0001) == 0) continue; pthread_join(thid[id], NULL); vio_print_dbg("pipe(%d)Test vio work thread---join done.\n", id); }
for (uint32_t id = 0; id < HB_VIO_PIPELINE_MAX; id++) { if (((g_port_mask >> id) & 0x0001) == 0) continue; ret = hb_cam_stop(id); if (ret < 0) { hb_vio_stop_pipeline(id); hb_cam_deinit(0); hb_vio_deinit(); vio_print_err("hb_cam_stop"); goto err; } ret = hb_vio_stop_pipeline(id); if (ret < 0) { hb_cam_deinit(0); hb_vio_deinit(); vio_print_err("hb_vio_stop_pipeline"); goto err; } } #ifdef ENABLE_MULTI_MEDIA for (uint32_t id = 0; id < HB_VIO_PIPELINE_MAX; id++) { if (((g_port_mask >> id) & 0x0001) == 0) continue; pthread_join(codec_thid[id], NULL); vio_print_dbg("pipe(%d)Test encode work thread---join done.\n", id); }
#endif
#ifdef ENABLE_BPU bpu_dnn_deinit();#endif
ret = hb_cam_deinit(0); ret |= hb_vio_deinit(); err: return ret;}
复制代码


获取及处理数据的代码:


   int vio_worker_func(uint32_t pipe_id, int loop_count)       {                       int ret = 0;                       pym_buffer_v3_t pym_buf;                       VIO_DATA_TYPE_E pym_data_type;                       pym_data_type = HB_VIO_PYM_DATA_V3;                       dp_info_t dump_info = {0};                                  ret = hb_vio_get_data(pipe_id, pym_data_type, &pym_buf);                       if (ret < 0) {                                       vio_print_err("Pipe(%u) HB_VIO_PYM_ADV_DATA get failed\n", pipe_id);                      goto err;                       }        #ifdef ENABLE_BPU                       if (((g_bpu_enable_mask >> pipe_id) & 0x0001) != 0) {                                       address_info_t img_info_bpu;                                       memset(&img_info_bpu, 0, sizeof(address_info_t));                                       ret = pym_layer_img_info_attach(&pym_buf, (PYM_LAYER_TYPE)g_pym_show_layer, &img_info_bpu);                                       if (ret < 0) {                                                       vio_print_err("pipe(%u)pym frame%d buf%d attch failed.\n", pipe_id, pym_buf.pym_img_info.frame_id,                                                                           pym_buf.pym_img_info.buf_index);                                                 goto err;                                       }                                       pthread_mutex_lock(&g_pym_lock);                                       bpu_dnn_process(pipe_id, img_info_bpu.addr[0], img_info_bpu.width, img_info_bpu.height);                                       pthread_mutex_unlock(&g_pym_lock);                                       //vio_print_info("pipe(%u) bpu process done\n", pipe_id);                     }       #endif          #ifdef ENABLE_HBPLAYER           if (g_pym_show_layer >= PYM_DS0_DATA && g_pym_show_layer < PYM_INVAILD_DATA) {                    pym_img_hbplayer_show((void *)vio_full_link_sample_event, &pym_buf, (PYM_LAYER_TYPE)g_pym_show_layer);                       }       #endif                       if (g_pym_save >= loop_count) {                                       //worker thread dump                                       dump_info.pipe_id = pipe_id;                                       dump_info.enable = PYM_BUF_DUMP;                                       memcpy(&dump_info.pym_buf, &pym_buf, sizeof(pym_buffer_v3_t));                    dp_worker_data_process(&dump_info);                                          }           #ifdef ENABLE_MULTI_MEDIA        if (g_codec_save >= loop_count) {                push_pym_buffer_to_post_for_codec(pipe_id, &pym_buf, FALSE);                if (g_codec_save == loop_count)     {                       // if last frame, push an empty frame more.                       push_pym_buffer_to_post_for_codec(pipe_id, NULL, TRUE);                }        } else {                ret = hb_vio_free_pymbuf(pipe_id, pym_data_type, &pym_buf);                if (ret < 0) {                   vio_print_err("pipe(%u)pym frame%d buf%d free failed.\n", pipe_id, pym_buf.pym_img_info.frame_id,                                pym_buf.pym_img_info.buf_index);                        goto err;                }    }#else         ret = hb_vio_free_pymbuf(pipe_id, pym_data_type, &pym_buf);         if (ret < 0) {                 vio_print_err("pipe(%u)pym frame%d buf%d free failed.\n", pipe_id, pym_buf.pym_img_info.frame_id,                         pym_buf.pym_img_info.buf_index);                 goto err;         }#endif    
err: eturn ret; }
复制代码

二. 编译

2.1. 编译环境

本 sample 的编译环境使用 SDK 中的 build 工具,请参考: Build 环境建立

2.2. 编译说明

本 sample 编译依赖 VPS 系统相关的头文件:


#include "hb_vin_data_info.h"#include "hb_vpm_data_info.h"#include "hb_vio_interface.h"
复制代码


使用 BPU 时,需要 BPU 模型处理相关的头文件:


#include "base/algorithm.h"#include "base/perception_common.h"#include "hobot/dnn/hb_dnn.h"#include "hobot/hb_ucp.h"#include "hobot/hb_ucp_sys.h"
复制代码


使用 VPU 时,需要 MM&CODEC 系统相关的头文件:


#include "hb_media_codec.h"#include "hb_media_error.h"#include #include #include "buf_queue.h"
复制代码


使用 hbplayer 时,需要 hbplayer 相关的头文件:


#include "hb_tool_server.h"
复制代码


sample 编译依赖的库:


LIBS += -lvio -lpthread -lalog -lhbmem
复制代码


使能 BPU 编译依赖的库:


LIBS += -lbpu -ldnn -lopencv_world -lhlog -lhbucp
复制代码


备注

当前本 sample 中使用的 dnn 版本: ucp_j6-v3.0.6_daily040101815


使能 MM&Codec 编译依赖的库:


LIBS += -lmultimedia -lavformat -lavcodec -lavutil -lswresample
复制代码


使能 hbplayer 编译依赖的库:


LIBS += -lhbplayer
复制代码


编译命令:


进入SDK所在目录{sdk_dir},并source构建环境(参见上)。# 编译本sample:bdm libvio-full-link-sample# 输出文件:{sdk_dir}/out/debug-gcc_{gcc_version}/build/test/samples/platform_samples/source/S83_Sample/S83E06_Tros/vio_full_link_sample
复制代码

三. 运行

3.1. 支持平台

Matrix 6E/M

3.2. 硬件环境搭建

接口连接如下:



模组:联创模组 OVX8B、OVX3C,SENSING-ISX031。


具体型号:


主前视联创 x8b:LCE_M24F121D12_S1ROT8E5;


窄前视联创 x8b:LCE_M24F30D12_S1ROT8E5;


后视联创 x3c:LCE_GM24F60D12_S2T0E6;


4 个周视联创 x3c:LCE_GM24F103D12_S2R8T0E6;


4 个环视森云 isx031c:SENSING_M24F190D4_SOROT7。


连接方式:


一路 OVX8B FOV120 通过 4 合 1 线束的 A 口连接到板子的 DES1;


一路 OVX8B FOV30 通过 4 合 1 线束的 C 口连接到板子的 DES1;


一路 OVX3C FOV60 通过 4 合 1 线束的 D 口连接到板子的 DES1;


四路 OVX3C FOV100 通过通过 4 合 1 线束的 ABCD 口连接到板子的 DES2;


四路 ISX031C 通过 4 合 1 线束的 ABCD 口连接到板子的 DES3。

3.3. 板端部署及配置

刷写系统软件镜像后,本 sample 的可执行文件位于板端: **/app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/bin/**;


需要用到的资源:


  • 需要用到的配置文件位于板端: **/app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/cfg/**;

  • 需要用到的资源文件位于板端: **/app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/res/**;

  • 需要用到的第三方库位于板端: **/app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/lib/**;

3.4. 运行指南

3.4.1. 运行方法

1V 测试命令,可直接执行提供的 sample 运行脚本:


bash /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/bin/run_vio_full_link_sample.sh
复制代码


或使用完整指令:


export LD_LIBRARY_PATH=/app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/lib:$LD_LIBRARY_PATH/app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/bin/vio_full_link_sample \-v /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/cfg/Scenario_1V_cpe0_sen_cim0_isp0_pym0_mode2_sample/vpm_config.json \-c /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/cfg/case_matrix/1V_OVX8B_RX0/hb_j6dev.json \-O /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/res/fcos.hbm -m 1 -o 1 -j 1 -l 1000 -s 10 -f 100 -e 0
复制代码


4V 测试命令,可直接执行提供的 sample 运行脚本:


bash /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/bin/run_vio_full_link_sample_4V.sh
复制代码


或使用完整指令:


export LD_LIBRARY_PATH=/app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/lib:$LD_LIBRARY_PATH/app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/bin/vio_full_link_sample \-v /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/cfg/Scenario_4V_cpe1_sen_cim1_isp1_pym1_mode1_sample/vpm_config.json \-c /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/cfg/Scenario_4V_cpe1_sen_cim1_isp1_pym1_mode1_sample/hb_j6dev.json \-O /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/res/fcos.hbm -m 15 -o 15 -j 15 -l 1000 -s 10 -f 10 -e 0
复制代码


7V 测试命令,可直接执行提供的 sample 运行脚本:


bash /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/bin/run_vio_full_link_sample_7V.sh
复制代码


或使用完整指令:


export LD_LIBRARY_PATH=/app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/lib:$LD_LIBRARY_PATH/app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/bin/vio_full_link_sample \-v /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/cfg/Scenario_7V_cpe01_sen_cim01_isp01_pym01_sample/vpm_config.json \-c /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/cfg/Scenario_7V_cpe01_sen_cim01_isp01_pym01_sample/hb_j6dev.json \-O /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/res/fcos.hbm -m 254 -o 254 -j 254 -l 1000 -s 10 -f 10 -e 0
复制代码

3.4.2. 运行命令行说明

vio_full_link_sample :应用程序名字。


下面的表格是具体参数的说明:



例如上面的 1V 测试命令:


/app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/bin/vio_full_link_sample \-v /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/cfg/Scenario_1V_cpe0_sen_cim0_isp0_pym0_mode2_sample/vpm_config.json \-c /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/cfg/case_matrix/1V_OVX8B_RX0/hb_j6dev.json \-O /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/res/fcos.hbm -m 1 -o 1 -j 1 -l 1000 -s 10 -f 100 -e 0
复制代码


-v 参数是 **/app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/cfg/Scenario_1V_cpe0_sen_cim0_isp0_pym0_mode2_sample/vpm_config.json**,代表 VIO 配置文件的所在位置,json 里面的具体配置可参考 VPS 配置文件说明。


-c 参数是 **/app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/cfg/case_matrix/1V_OVX8B_RX0/hb_j6dev.json**,代表 camera 的配置文件的所在位置,json 里面的具体配置可参考 征程 6X camera 配置文件说明。


-O 参数是 **/app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/res/fcos.hbm**,代表 hbm 模型文件的所在位置。


-m 参数是 1,表示使能 pipe0 数据流。


-o 参数是 1,表示对 pipe0 数据流进行 BPU 处理。


-j 参数是 1,表示对 pipe0 数据流进行 VPU 硬件编码。


-l 参数是 1000,表示获取 PYM 数据 1000 帧。


-s 参数是 10,表示 dump 前面 10 帧的数据。


-f 参数是 100,表示编码前面 100 帧的数据,输出 H265 视频。


-e 参数是 0,表示通过 hbplayer 工具实时显示 PYM DS0 层。


可增加 -t 参数,例如 -t 10000 表示程序获取数据的最长运行时间为 10000ms。 当 -t 参数与 -l 参数同时使用时,各线程在满足其中任意一个条件,即已获取指定的数据帧数或者已达到指定的运行时间后就会退出,一般情况下不建议同时使用这两个参数。


备注

BPU 对于 NV12 格式图像处理要求 Stride 32 对齐,通常 Pym 输出数据作为 BPU 输入就需要 Stride 32 对齐,如果不对齐,BPU 处理结果会不正确。 如果要强制停止,需要两次 ctrl+c 操作。原因是 hobot player 使用了 libevent 库,第一次 ctrl+c 操作被它吃掉了。

3.4.3. 运行结果说明

sample 运行时,通过下面的命令可以看到每个 IP 的帧率:


cat  /sys/class/vps/flow/fps
复制代码


sample 运行时的主要执行日志如下:


  • 成功加载 hbm 模型:


root@hobot:~# bash /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/bin/run_vio_full_link_sample_4V.sh[DNN] HBTL_EXT_DNN log level:3[UCP]: log level = 3[UCP]: UCP version = 3.0.6[VP]: log level = 3[DNN]: log level = 3[HPL]: log level = 3[UCPT]: log level = 6[INFO] model is: /app/sample/S83_Sample/S83E06_Tros/vio_full_link_sample/res/fcos.hbm[BPU][[BPU_MONITOR]][281472801308704][INFO]BPULib verison(2, 0, 5)[]![DNN]: 3.0.6_(4.0.19 HBRT)[INFO] Load model successfully!start_hbplayer_thread start success. pid 281472495382208create_socket_listen---177, listern 0xffff640154c0create a listener, port is 10086create_socket_event---202, t_base 0xaaab0d353e60 event base is 0xffff64014750, listener 0xffff640154c0[15:07:04]start_callback_service[538] hbplayer L: start_dump_server_thread start success.
[INFO] pym: hb_vio_start_pipeline done[DBG] pym: pipe(0)Test vio work thread---running.[DBG] pym: pipe(0) pym feedback worker_thread Ready ![INFO] pym: hb_vio_start_pipeline done[DBG] pym: pipe(1)Test vio work thread---running.[DBG] pym: pipe(1) pym feedback worker_thread Ready ![INFO] pym: hb_vio_start_pipeline done[DBG] pym: pipe(2)Test vio work thread---running.[DBG] pym: pipe(2) pym feedback worker_thread Ready ![INFO] pym: hb_vio_start_pipeline done[DBG] pym: pipe(3)Test vio work thread---running.[DBG] pym: pipe(3) pym feedback worker_thread Ready !
复制代码


里面的相应的版本号会变动,仅供参考。


  • Dump、CODEC 编码:



  • 运行结束正常退出:



查看运行时的帧率如下:


1V 场景如下:



4V 场景如下:



7V 场景如下:



通过 -t 10000 指定运行时间为 10000ms。

3.4.4. 看图结果

本 sample 支持通过 hbplayer 工具进行看图。首先在 hbplayer 中设置平台、IP 地址等相关参数:



执行命令后,点击 hbplayer 左侧栏中的 connect 即可完成连接并在右侧界面看到实时全链路场景图像:


1V 场景如下:



4V 场景如下:



7V 场景如下:



当满足 -l-t 参数指定的条件后,sample 将自动退出运行,也可通过 Ctrl+C 手动结束运行。


拿 1V 举例,Dump 的 YUV 图像以及 VPU 硬件编码输出的 H265 视频保存在当前目录下:



拿 1V 举例,查看 H265 视频:



用户头像

还未添加个人签名 2021-03-11 加入

还未添加个人简介

评论

发布
暂无评论
征程 6E/M|多 camera 场景示例_自动驾驶_地平线开发者_InfoQ写作社区