海思hi3516读取摄像图头数据(以易百纳G610Q-IPC-38E 模组为例)

提示:海思hi3516读取摄像头的数据是后续应用开发的前提,开发中发现相关文档并不齐全,官方只提供了一个sample。如果需要将其提取合并到自己的工程文件中,整理MakeFile耗时耗力;在踩完所有坑后,记录本文也希望帮助到有关的开发者朋友。如果你不想看具体分析和文件分析,可以直接跳至文件最后从百度网盘下载本人整理的源代码!

目录

前言

一、海思Hi3516

关于易百纳G610Q-IPC-38E

二、从摄像头读取数据应用

2.1 开发环境搭建(docker)

2.2 下载相关依赖包

2.3 提取依赖文件和依赖包,并修改示例代码

2.4 添加代码并编译

总结

附录 下载链接


前言

海思Hi3516读取摄像头的数据是后续应用开发的前提,开发中发现相关文档并不齐全,官方只提供了一个sample。如果需要将其提取合并到自己的工程文件中,根据MakeFile整理相关依赖耗时耗力;在踩完所有坑后,记录本文也希望帮助到有关的开发者朋友。如果你不想看具体使用过程,可以跳到文件最后从百度云盘链接中下载本人整理的全部工程文件,直接编译使用


一、海思Hi3516

Hi3516是海思半导体主要应用在安防市场的 IPC 处理器内核 SoC,其H264多码流编码性能、优异的ISP和编码视频质量、高性能的智能加速引擎等特性,在满足客户差异化IPCamera产品功能、性能、图像质量要求的同时,可大大降低ebom成本。

关于易百纳G610Q-IPC-38E

G610Q-IPC-38E 模组采用 HI3516CV610(ARM Cortex-A7 MP2)芯片。该芯片基于 ARM Cortex-A7 主频 950MHz 20S,Hi3516CV610 是一颗应用在安防市场的IPC SoC。 G610Q-IPC-38E 模组集成集成 4M@30FPS Sensor,支持最高 6M@30fps 的 ISP 图像处理能力,支持 SVAC3.0 编码。

二、从摄像头读取数据应用

2.1 开发环境搭建(docker)

海思准备了开发环境需要的docker,安装使用和维护都非常方便,强烈推荐!docker内已经完整安装了交叉编译工具和其他开发工具。

# 拉取镜像
docker pull swr.cn-north-4.myhuaweicloud.com/hi_spark/qiankunbp:2.1.1
 
# 运行
docker run -it -d -v ${PROJECT_PATH}:${PROJECT_PATH} --shm-size 2g --name hi3516 swr.cn-north-4.myhuaweicloud.com/hi_spark/qiankunbp:2.1.1 /bin/bash
 
# 进入容器
docker exec -it hi3516 /bin/bash

2.2 下载相关依赖包

相关依赖包,hi3516cv610_musl.tar提供相关sample源码和依赖库,下载完成后,将其拷贝至docker宿主机映射目录下

2.3 提取依赖文件和依赖包,并修改示例代码

编译读取摄像头的文件在“hi3516cv610_musl/smp/a7_linux/source/mpp/sample/smart_ae/”目录下,如果你自己一层层整理MakeFIle,可以完整整理出一套完整依赖和编译选项,但是非常痛苦。用如下命令  可以帮你整理出所有依赖:

# 拷贝依赖的头文件和库到你的工程目下
cp -r hi3516cv610_musl/smp/a7_linux/source/out/lib/  /path/to/you/project
cp -r hi3516cv610_musl/smp/a7_linux/source/out/include/ /path/to/you/project
cp -r hi3516cv610_musl/smp/a7_linux/source/mpp/sample/common/ /path/to/you/project


# 拷贝sample_smart_ae.c
cp hi3516cv610_musl/smp/a7_linux/source/mpp/sample/smart_ae/sample_smart_ae.c  /path/to/you/project/src/

修改sample_smart_ae.c文件12399-1271行,为如下内容(修改后可以手动设置图像大小)

# 修改后代码
hi_s32 sample_smart_ae_start_video_route(int img_width, int img_height)
{
    sample_sns_type sns_type = SENSOR0_TYPE;

    sample_smart_ae_get_vi_vpss_mode(HI_FALSE);
    sample_comm_vi_get_default_vi_cfg(sns_type, &g_vi_cfg[0]);
    sample_smart_ae_get_pipe_wrap_line(g_vi_cfg, 1);
    sample_comm_vpss_get_default_vpss_cfg(&g_vpss_cfg, g_vie_sys_cfg.vpss_wrap_en);
    g_vpss_cfg.chn_attr[1].width = img_width; /* model 1024x576 */
    g_vpss_cfg.chn_attr[1].height = img_height; /* model 1024x576 */
    sample_smart_ae_vpss_get_wrap_cfg(&g_vie_sys_cfg, &g_vpss_cfg);

    if (sample_smart_ae_start_route(g_vi_cfg, &g_vpss_cfg, g_vie_sys_cfg.route_num) != HI_SUCCESS) {
        return HI_FAILURE;
    }
    return HI_SUCCESS;
}

hi_void sample_smart_ae_stop_video_route()
{
    sample_smart_ae_stop_route(g_vi_cfg, g_vie_sys_cfg.route_num);
}

static hi_s32 sample_smart_ae_start(hi_void)
{
    hi_s32 ret;

    // start video route
    ret = sample_smart_ae_start_video_route(1024, 576);
    if (ret != HI_SUCCESS) {
        sample_print("start_video_route error!\n");
        return ret;
    }

# 注释掉sample_smart_ae.c中main函数

// int main(int argc, char *argv[])
// {
//     hi_s32 ret;
// #ifndef __LITEOS__
//     sample_register_sig_handler(sample_smart_ae_handle_sig);
// #endif

//     if (sample_ipc_server_init(sample_smart_ae_ipc_msg_proc) != HI_SUCCESS) {
//         printf("sample_ipc_server_init failed!!!\n");
//     }

//     ret = sample_smart_ae_init_aidetect(argc, argv);
//     if (ret != HI_SUCCESS) {
//         sample_smart_ae_usage(argv[0]);
//         sample_ipc_server_deinit();
//         return ret;
//     }

//     ret = sample_smart_ae_start();

//     sample_ipc_server_deinit();

//     return ret;
// }

2.4 添加代码并编译

如果你不想看具体分析和文件分析,可以直接跳至文件最后从百度网盘下载本人整理的源代码!

添加在include文件夹下添加smart_ae.h,内容如下:

#ifndef INCLUDE_SMART_AE_H_
#define INCLUDE_SMART_AE_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include "sample_comm.h"

extern hi_s32 sample_smart_ae_start_video_route(int img_width, int img_height);
extern hi_void sample_smart_ae_stop_video_route();

#ifdef __cplusplus
}
#endif
#endif // INCLUDE_SMART_AE_H_

添加在include文件夹下添加camera.h,内容如下(封装smart_ae为camera类):


#ifndef INCLUDE_CAMERA_H_
#define INCLUDE_CAMERA_H_
#include <string>
#include <iostream>

namespace zytracker{
namespace vio_plugin{

enum class IOSourceType{
    kLocalFile = 0,
    kCamera
};

class Camera{
public:
    Camera(){};
    ~Camera(){};
    int Init(IOSourceType source_type, std::string source_path, int img_width, int img_height);
    void* LoadYUV(int img_width, int img_height);
    int DeInit();

private:
    IOSourceType source_type_ = IOSourceType::kLocalFile;
    std::string source_path_ = "";
    int img_width_ = 0;
    int img_height_ = 0;
    bool is_running_ = false;

};

}//namespace vio_plugin
}//namespace zytracker

在src/文件夹内添加camera.cpp,通过接口读取frame, 返回值yuv_ptr即为从摄像头读取的NV21图像。

#include "smart_ae.h"
#include "camera.h"

namespace zytracker{
namespace vio_plugin{

int Camera::Init(IOSourceType source_type, std::string source_path, int img_width, int img_height){
    source_path_ = source_path;
    img_width_ = img_width;
    img_height_ = img_height;
    source_type_ = source_type;

    hi_s32 result = sample_smart_ae_start_video_route(img_width_, img_height_);
    if(result != HI_SUCCESS){
        printf("start video route failed\n");
        return -1;
    }
    return 0;
}

void* Camera::LoadYUV(int img_width, int img_height){
    if(img_width != img_width_ || img_height != img_height_){
        printf("img_width or img_height is not equal to init width or height\n");
        return nullptr;
    }

    hi_s32 ret = HI_SUCCESS;
    hi_video_frame_info src_frame;
    hi_u32 size = 0, size_c = 0;

    hi_mpi_isp_get_vd_time_out(0, OT_ISP_VD_FE_START, 500); /* 500ms */
    ret = hi_mpi_vpss_get_chn_frame(0, 1, &src_frame, 500); /* 500ms */
    if (ret != HI_SUCCESS) {
        printf("hi_mpi_vpss_get_chn_frame fail, ret = 0x%x\n", ret);
    }
    size = src_frame.video_frame.stride[0] * src_frame.video_frame.height;
    size_c = src_frame.video_frame.stride[1] * src_frame.video_frame.height / 2; /* YUV420, 4/2 */

    int height = src_frame.video_frame.height;
    int width = src_frame.video_frame.width;
    int stride_y = src_frame.video_frame.stride[0];

    src_frame.video_frame.virt_addr[0] = (char *)hi_mpi_sys_mmap(src_frame.video_frame.phys_addr[0], height*stride_y);
    void* yuv_ptr = malloc(img_width_*img_height_*3/2);
    memcpy(yuv_ptr, src_frame.video_frame.virt_addr[0], height*stride_y);

    int stride_c = src_frame.video_frame.stride[1];
    src_frame.video_frame.virt_addr[1] = (char*)hi_mpi_sys_mmap(src_frame.video_frame.phys_addr[1], stride_c*height/2);
    memcpy(yuv_ptr+height*width, src_frame.video_frame.virt_addr[1], stride_c*height/2);

    hi_mpi_sys_munmap(src_frame.video_frame.virt_addr[0], size);
    hi_mpi_sys_munmap(src_frame.video_frame.virt_addr[1], size_c);
    if (hi_mpi_vpss_release_chn_frame(0, 1, &src_frame) != HI_SUCCESS) {
        printf("hi_mpi_vpss_release_chn_frame fail.\n");
    }

    return yuv_ptr;
}

int Camera::DeInit(){
    sample_smart_ae_stop_video_route();
    return 0;
}

}//namespace vio_plugin
}//namespace zytracker

添加main.cpp文件,调用接口读取并保存数据:

#include "smart_ae.h"
#include "camera.h"

using zytracker::vio_plugin::Camera;
using zytracker::vio_plugin::IOSourceType;

void writeYuvToFile(const char* filename, void* yuvData, size_t dataSize) {
    FILE* file = fopen(filename, "wb");
    if (!file) {
        perror("Failed to open file");
        return;
    }
    fwrite(yuvData, 1, dataSize, file);
    fclose(file);
}

int main(int argc, char* argv[]){
    Camera camera;
    camera.Init(IOSourceType::kLocalFile, "", 1024, 576);
    void* yuv_ptr = camera.LoadYUV(1024, 576);
    writeYuvToFile("ouput.yuv", yuv_ptr, 1024*576*3/2);
    free(yuv_ptr);
    camera.DeInit();
    return 0;
}

整理后文件目录如下:

<Docker> [root@07276ee5fc5e]:/workspace/tmp/smart_ae$ tree . -L 1
.
|-- CMakeLists.txt
|-- build.sh
|-- common
|-- include
|-- lib
|-- main.cpp
`-- src

添加CMakeLists.txt进行编译即可编译可执行文件进行运行读取图像。需要注意的是add_definitions内的内容,需要根据自己情况进行替换,比如摄像头的sensor_type(非常重要)。

cmake_minimum_required(VERSION 3.10)

project(smart_ae)

# Compile options
add_compile_options(
    -fstack-protector-all
    -D_FORTIFY_SOURCE=2
    -Wno-sign-compare
    )

set(CMAKE_C_FLAGS_DEBUG "-fPIC -O0 -g -Wall")
set(CMAKE_CXX_FLAGS_DEBUG "-fPIC -O0 -g -Wall -std=c++14")
set(CMAKE_C_FLAGS_RELEASE "-fPIC -O2 -Wall -s")
set(CMAKE_CXX_FLAGS_RELEASE "-fPIC -O2 -Wall -s -std=c++14")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,relro,-z,now,-z,noexecstack -fPIE -pie")
set(CMAKE_SKIP_RPATH TRUE)

add_definitions(
    -DSC4336P_MIPI_4M_30FPS_10BIT_SELECT=y
    -DSENSOR0_TYPE=SC4336P_MIPI_4M_30FPS_10BIT
    -DSENSOR1_TYPE=SC4336P_MIPI_4M_30FPS_10BIT
    -Dhi3516cv610
    -DOT_XXXX
    -DISP_V2
    -DVER_X=1
    -DVER_Y=0
    -DVER_Z=0
    -DVER_P=0
    -DVER_B=10
    -DUSER_BIT_32
    -DKERNEL_BIT_32
    -DOT_RELEASE
    -DBOARD_TYPE=DMEB_QFN
    -DOT_ACODEC_TYPE_INNER
    -DOT_VQE_USE_STATIC_MODULE_REGISTER
    )

include_directories(
    ${PROJECT_SOURCE_DIR}/common/
    ${PROJECT_SOURCE_DIR}/include/
)

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=softfp")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=softfp")


set(AE_LIB_PATH ${PROJECT_SOURCE_DIR}/lib)
link_directories(
    ${AE_LIB_PATH}
)
set(AE_LIB hi_mpi_cipher hi_mpi_smartae
    hi_mpi hi_mpi_sysmem hi_mpi_sysbind
    hi_mpi_ae  hi_mpi_isp ot_mpi_isp
    hi_mpi_awb dehaze extend_stats
    drc ldci bnr calcflicker ir_auto acs
    sns_sc4336p  hi_mpi_km  bnr
    hi_mpi_ive hi_ivs_md
    )

set(AE_SRC
    ${PROJECT_SOURCE_DIR}/common/sample_comm_vi.c
    ${PROJECT_SOURCE_DIR}/common/sample_comm_vpss.c
    ${PROJECT_SOURCE_DIR}/common/sample_comm_sys.c
    ${PROJECT_SOURCE_DIR}/common/sample_comm_isp.c
    ${PROJECT_SOURCE_DIR}/common/sample_comm_venc.c
)

add_executable(main main.cpp src/sample_smart_ae.c src/camera.cpp ${AE_SRC})

target_link_libraries(main ${AE_LIB} stdc++ m pthread securec dl protobuf-c)

set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/install/)
install(TARGETS main DESTINATION .)

用7yuv打开保存的yuv文件看到图像,说明代码可以正常运行


总结

本文详细介绍了基于海思Hi3516CV610芯片的摄像头数据读取开发全流程,通过Docker快速搭建开发环境,提取并整理海思SDK中的关键依赖文件和示例代码,解决了官方文档不全导致的开发难题。重点对sample_smart_ae.c进行改造,封装出可设置图像尺寸的C++接口类,实现了YUV数据的稳定读取和保存。项目提供了完整的CMake工程配置,包含交叉编译选项、库文件链接和预定义宏设置,可直接编译使用。最终通过7yuv工具验证了YUV数据的正确性,为后续视频处理开发奠定了基础。文中分享的代码架构设计、编译参数优化和问题排查经验,对Hi3516平台开发者具有重要参考价值,可显著降低同类项目的开发门槛。完整工程文件已提供百度网盘下载。

附录 下载链接

本项目,代码文件百度网盘下载地址
链接: https://pan.baidu.com/s/17W62l8NK6VRw_E4jXTddDg 提取码: s834

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值