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

Logo

加入社区

更多推荐