海思3559 sample解析:venc

本文涉及的产品
阿里云百炼推荐规格 ADB PostgreSQL,4核16GB 100GB 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
简介: 海思3559 sample解析:venc

前言:

 分析完vio的例程后瞬间信心满满,自信的去找大佬请求分配任务了,“简简单单”几个步骤,照着葫芦画瓢,调调参数,对应位置具体分析具体修改,美好光明的“大路”清晰明朗啊!

e03496f513c74999bb9743defaa911c6.png

年轻人,too young too naive啊要真是这么简单,用芯片大炮打蚊子吗?

 可是看起来就是很简单啊,属性挨个配置,一绑定,巴拉巴拉

 那如果不绑定呢?需要自己加算法修改呢?怎么获取图像,怎么输出?假如要做个人脸识别呢?b63a671dcb764ee8a0e75b596b428bd8.png

有没有感觉到越简单的流程好像越不自由,很多都没法自己掌控,想自己随需求修改的更多,自然就没那么容易了

捂着被打肿的脸痛定思痛,一定要好好拆解一下具体步骤

一个sample不够那就再看个复杂一点点的!

sample_venc

 有了之前的经验,整体流程心里还是有了点x数,就不用每次都跳来跳去挨个查看了,直接理一下代码框架吧


main 主函数
  SAMPLE_VENC_4K60 视频采集函数
  SAMPLE_COMM_SYS_GetPicSize 获取w.h参数
  SAMPLE_COMM_VI_GetSensorInfo
  SAMPLE_VENC_CheckSensor
    SAMPLE_COMM_VI_GetSizeBySensor 得到sensor的相关参数,得到mmp系统所需的一些参数
    SAMPLE_COMM_SYS_GetPicSize 得到图片的尺寸
  SAMPLE_VENC_VI_Init
    SAMPLE_VENC_SYS_Init 编码系统初始化
    SAMPLE_COMM_VI_GetSizeBySensor  得到sensor的相关参数,得到mmp系统所需的一些参数
    SAMPLE_COMM_SYS_GetPicSize  得到图片的尺寸
    COMMON_GetPicBufferSize  得到缓存块的大小
    SAMPLE_COMM_SYS_Init   MMP系统初始化
      HI_MPI_SYS_Exit();去初始化 MPP 系统。
      HI_MPI_VB_Exit();去初始化 MPP 视频缓存池
      HI_MPI_VB_SetConfig设置 MPP 视频缓存池属性
      HI_MPI_VB_Init 初始化 MPP 视频缓存池
      HI_MPI_SYS_Init 初始化 MPP 系统。
      SAMPLE_COMM_VI_GetFrameRateBySensor
    HI_MPI_ISP_GetCtrlParam 获取 ISP 控制参数。
    HI_MPI_ISP_SetCtrlParam 设置 ISP 控制参数。
    SAMPLE_COMM_VI_StartVi
    SAMPLE_COMM_VI_StartMIPI 初始化mipi : 设置mipi的模式。.使能mipi时钟。mipi复位。使能sensor时钟。sensor复位。设置mipi的属性。mipi解复位。.sensor解复位
    SAMPLE_COMM_VI_SetParam获取 VI,VPSS 的工作模式。设置 VI,VPSS 工作模式
    SAMPLE_COMM_VI_CreateVi设置 VI 设备与物理 PIPE 的绑定关系。 创建vi pipe。 设置 VI 通道ch属性,启用 VI 通道ch
    SAMPLE_COMM_VI_CreateIsp  参考HiISP开发参考
  SAMPLE_VENC_VPSS_Init
    SAMPLE_COMM_VI_GetSizeBySensor  得到sensor的相关参数,得到mmp系统所需的一些参数
    SAMPLE_COMM_SYS_GetPicSize  得到图片的尺寸
    SAMPLE_COMM_VPSS_Start  创建vpss group 配置通道属性 启用通道 启用vpss group
  SAMPLE_COMM_VI_Bind_VPSS  包含数据源3个参数接收者3个参数,分别是vi和vpss,调用数据源到数据接收者绑定接口
    HI_MPI_SYS_Bind
  /     start stream venc   /
  SAMPLE_VENC_GetRcMode    获取rc模式(码率控制)
  SAMPLE_VENC_GetGopMode  gop模式选择
  SAMPLE_COMM_VENC_GetGopAttr 根据gop模式配置相关属性
   /***encode h.265 **/
  SAMPLE_COMM_VENC_Start  启动编码 stream模式
    SAMPLE_COMM_VENC_Creat  创建venc channel根据enType选择编码格式
    HI_MPI_VENC_StartRecvFrame 开启编码通道接收输入图像。允许指定接收帧数,超出指定的帧数后自动停止接收图像
  SAMPLE_COMM_VPSS_Bind_VENC  数据源到数据接收者绑定接口。
    HI_MPI_SYS_Bind  数据源到数据接收者绑定接口。
  /***encode h.264 **/
  SAMPLE_COMM_VENC_Start
    SAMPLE_COMM_VENC_Creat  创建venc channel根据enType选择编码格式
    HI_MPI_VENC_StartRecvFrame 开启编码通道接收输入图像。允许指定接收帧数,超出指定的帧数后自动停止接收图像
  SAMPLE_COMM_VPSS_Bind_VENC
    HI_MPI_SYS_Bind  数据源到数据接收者绑定接口。
  /*stream save process*/
  SAMPLE_COMM_VENC_StartGetStream  创建线程用以开启编码流
    SAMPLE_COMM_VENC_GetVencStreamProc
     step 1:   检查并准备保存文件和venc fd
      /* 确定视频流文件名,并打开文件以保存视频流*/
      /* 设置 Venc Fd. */
     step 2:  开始获取每个通道的视频流
      step 2.1 : 查询每个帧流中有多少包。
      step 2.2 :建议同时检查u32CurPacks和u32LeftStreamFramese
      step 2.3 :  malloc对应的包节点数。
      step 2.4 : 调用mpi获取一个帧流
      step 2.5 : 将框架保存到文件
      step 2.6 : 释放视频流
       step 2.7 : 释放包节点
     step 3 :关闭保存文件
  SAMPLE_COMM_VENC_StopGetStream  pthread_join线程

看起啦又清晰了不少,那么接下来就以此为基础,开始我们自己的平台搭建吧!

部分补充注释

PIC_SIZE_E enSize[2] = {PIC_3840x2160, PIC_1080P};
编码通道s32ChnNum=2;//一个是4k120一个是1080p30
VENC_CHN VencChn[2] = {0,1};
HI_U32 u32Profile[2] = {0,1};
PAYLOAD_TYPE_E enPayLoad[2] = {PT_H265, PT_H264}; //两种编码方式

一、获取编码的具体分辨率

二、获取sensor的信息

三、检查sensor

主要的工作内容是获取sensor的宽高,检查需要编码的视频的宽高是否大于sensor能够捕获的最大宽高。如果大于则说明编码分辨率设置错误。

四、VI的初始化

1.venc初始化

获取sensor的分辨率,并计算出需要的vb块大小(这里计算了两个,一个是sensor的分辨率,一个是1920 *1080的分辨率),并且缓存池的数量是2(stVbConf.u32MaxPoolCnt = 2;)

设置 MPP 视频缓存池属性,初始化VB,初始化sys:

HI_MPI_SYS_Exit();
HI_MPI_VB_Exit();
HI_MPI_VB_SetConfig(pstVbConfig);
HI_MPI_VB_Init();
HI_MPI_SYS_Init();

2.根据sensor的类型获取帧率u32FrameRate。

3.获取ISP的控制参数。

打开isp_dev设备节点,获取控制参数:

ioctl(g_as32IspFd[ViPipe], ISP_GET_CTRL_PARAM, pstIspCtrlParam);
stIspCtrlParam.u32StatIntvl = u32FrameRate/30;
ioctl(g_as32IspFd[ViPipe], ISP_SET_CTRL_PARAM, pstIspCtrlParam);

4.start mipi

.设置mipi的模式

fd = open("/dev/hi_mipi", O_RDWR);
ioctl(fd, HI_MIPI_SET_HS_MODE, LANE_DIVIDE_MODE_7);
close(fd);

.使能mipi时钟

fd = open("/dev/hi_mipi", O_RDWR);
ioctl(fd, HI_MIPI_ENABLE_MIPI_CLOCK, &devno);
close(fd);

.reset mipi

fd = open("/dev/hi_mipi", O_RDWR);
s32Ret = ioctl(fd, HI_MIPI_RESET_MIPI, &devno);
close(fd);

.使能sensor时钟

fd = open("/dev/hi_mipi", O_RDWR);
ioctl(fd, HI_MIPI_ENABLE_SENSOR_CLOCK, &SnsDev);
close(fd);

.reset sensor

fd = open("/dev/hi_mipi", O_RDWR);
s32Ret = ioctl(fd, HI_MIPI_RESET_SENSOR, &SnsDev);
close(fd);

.设置mipi的属性

fd = open("/dev/hi_mipi", O_RDWR);
ioctl(fd, HI_MIPI_SET_DEV_ATTR, &stcomboDevAttr);//raw图位宽,
close(fd);

.mipi解复位

fd = open("/dev/hi_mipi", O_RDWR);
ioctl(fd, HI_MIPI_UNRESET_MIPI, &devno);
close(fd);

.sensor解复位

open("/dev/hi_mipi", O_RDWR);
ioctl(fd, HI_MIPI_UNRESET_SENSOR, &SnsDev);
close(fd);

5.set vi vpss的工作模式【这个模式具体细节可参考hi说明文档】

HI_MPI_SYS_SetVIVPSSMode(&stVIVPSSMode);//定义 VI 各个 PIPE 和 VPSS 各个组的工作模式。

typedef enum hiVI_VPSS_MODE_E
{
VI_OFFLINE_VPSS_OFFLINE = 0,
VI_OFFLINE_VPSS_ONLINE,
VI_ONLINE_VPSS_OFFLINE,
VI_ONLINE_VPSS_ONLINE,
VI_PARALLEL_VPSS_OFFLINE,
VI_PARALLEL_VPSS_PARALLEL,
VI_VPSS_MODE_BUTT
} VI_VPSS_MODE_E;

6.创建vi和ISP

.创建VI

HI_MPI_VI_SetDevAttr(ViDev, &stViDevAttr);
HI_MPI_VI_EnableDev(ViDev);
HI_MPI_VI_SetDevBindPipe(pstViInfo->stDevInfo.ViDev, &stDevBindPipe);//vi设备和物理pipe的绑定关系
HI_MPI_VI_CreatePipe(ViPipe, &stPipeAttr);
HI_MPI_VI_SetChnAttr(ViPipe, ViChn, &stChnAttr);
HI_MPI_VI_EnableChn(ViPipe, ViChn);// vi在线VPSS在线模式、VI离线VPSS在线模式, VI并行VPSS 并行模式下,启动VI通道不生效,直接返回成功。

.创建ISP

以下的操作,每个输入工作通道都需要处理。

获得回调函数指针:sensor_register_callback

执行注册的回调函数:sensor_register_callback

sensor_register_callback

cmos_init_sensor_exp_function(&stIspRegister.stSnsExp);
    HI_MPI_ISP_SensorRegCallBack(ViPipe, &stSnsAttrInfo, &stIspRegister);
    cmos_init_ae_exp_function(&stAeRegister.stSnsExp);
    HI_MPI_AE_SensorRegCallBack(ViPipe, pstAeLib, &stSnsAttrInfo, &stAeRegister);
    cmos_init_awb_exp_function(&stAwbRegister.stSnsExp);
    HI_MPI_AWB_SensorRegCallBack(ViPipe, pstAwbLib, &stSnsAttrInfo, &stAwbRegister);

根据sensor的不同,注册不同的控制总线(iic或者ssp)

HI_MPI_AE_Register(IspDev, &stAeLib);
HI_MPI_AWB_Register(IspDev, &stAwbLib)
HI_MPI_ISP_MemInit(ViPipe);
HI_MPI_ISP_SetPubAttr(ViPipe, &stPubAttr);
HI_MPI_ISP_Init(ViPipe);
pthread_create(&g_IspPid[*pIspDev], pstAttr, SAMPLE_COMM_ISP_Thread, (HI_VOID*)pIspDev);
SAMPLE_COMM_ISP_Thread
 HI_MPI_ISP_Run(IspDev);

五、VPSS初始化

1.通过sensor的型号确定分辨率

VPSS start
HI_MPI_VPSS_CreateGrp(VpssGrp, pstVpssGrpAttr);

同一个goroup下面的4个通道都需要

HI_MPI_VPSS_SetChnAttr(VpssGrp, VpssChn, &pastVpssChnAttr[VpssChn]);
HI_MPI_VPSS_EnableChn(VpssGrp, VpssChn);
HI_MPI_VPSS_StartGrp(VpssGrp);

六、VI bind VPSS

stSrcChn.enModId   = HI_ID_VI;
stSrcChn.s32DevId  = ViPipe;
stSrcChn.s32ChnId  = ViChn;
stDestChn.enModId  = HI_ID_VPSS;
stDestChn.s32DevId = VpssGrp;
stDestChn.s32ChnId = 0;
HI_MPI_SYS_Bind(&stSrcChn, &stDestChn);

七、start stream venc

确定用户选择的rc模式和gop模式,并根据这些用户选择确定gop属性。

八、encode h.265 h.264

1.VENC creat

HI_MPI_VENC_CreateChn(VencChn, &stVencChnAttr);//参数中对h.264 h.265 jpeg等编码做了区分。

(1)主码流进行h.265编码

SAMPLE_COMM_VENC_Start(VencChn[0], enPayLoad[0],enSize[0], enRcMode,u32Profile[0],&stGopAttr);
SAMPLE_COMM_VPSS_Bind_VENC(VpssGrp, VpssChn[0],VencChn[0]);

(2)子码流进行h.264编码

SAMPLE_COMM_VENC_Start(VencChn[1], enPayLoad[1], enSize[1], enRcMode,u32Profile[1],&stGopAttr);
SAMPLE_COMM_VPSS_Bind_VENC(VpssGrp, VpssChn[1],VencChn[1]);

2.HI_MPI_VENC_StartRecvFrame(VencChn,&stRecvParam); 获取编码码流到码流空间中

开启编码通道接收输入图像, 允许指定接收帧数,超出指定的帧数后自动停止接收图像,具体流程如下

开启线程

(1) check & prepare save-file & venc-fd

(2) Start to get streams of each channel.

select(maxfd + 1, &read_fds, NULL, NULL, &TimeoutVal)

step 2.1 : query how many packs in one-frame stream.
                HI_MPI_VENC_QueryStatus(i, &stStat);
step 2.2 :suggest to check both u32CurPacks and u32LeftStreamFrames at the same time,
step 2.3 : malloc corresponding number of pack nodes.
step 2.4 : call mpi to get one-frame stream
step 2.5 : save frame to file

snprintf(aszFileName[i],32, “stream_chn%d_%d%s”, i, u32PictureCnt[i],szFilePostfix);

pFile[i] = fopen(aszFileName[i], “wb”);

#ifndef __HuaweiLite__

直接写文件

s32Ret = SAMPLE_COMM_VENC_SaveStream(pFile[i], &stStream);
   for (i = 0; i < pstStream->u32PackCount; i++)
    {
        fwrite(pstStream->pstPack[i].pu8Addr + pstStream->pstPack[i].u32Offset,
               pstStream->pstPack[i].u32Len - pstStream->pstPack[i].u32Offset, 1, pFd);
       fflush(pFd);
    }
    #else

直接传递物理地址

s32Ret = SAMPLE_COMM_VENC_SaveStream_PhyAddr(pFile[i], &stStreamBufInfo[i], &stStream);
        #endif
stSrcChn.enModId   = HI_ID_VPSS;
stSrcChn.s32DevId  = VpssGrp;
stSrcChn.s32ChnId  = VpssChn;
stDestChn.enModId  = HI_ID_VENC;
stDestChn.s32DevId = 0;
stDestChn.s32ChnId = VencChn;
HI_MPI_SYS_Bind(&stSrcChn, &stDestChn);// h.265 h.264 VpssChn和VencChn的值分别是0和1. VpssGrp = 0

九、stream save process

pthread_create(&gs_VencPid,0,SAMPLE_COMM_VENC_GetVencStreamProc, (HI_VOID*)&gs_stPara);
SAMPLE_COMM_VENC_GetVencStreamProc// get stream from each channels and save them

十、exit process

1.杀死上面创建的获取数据流的线程

pthread_join(gs_VencPid, 0);

2.VPSS 和VENC解绑定VENC停止。要分为H264 H265,参数要求同上面绑定操作一样。

3.下面两步操作需要分为H264 H265, VencChn取值分别为0,1

HI_MPI_VENC_StopRecvFrame(VencChn);//stop recv picture
HI_MPI_VENC_DestroyChn(VencChn);// Distroy Venc Channel

4.VI和VPSS解绑定

stSrcChn.enModId   = HI_ID_VI;
stSrcChn.s32DevId  = ViPipe;
stSrcChn.s32ChnId  = ViChn;
stDestChn.enModId  = HI_ID_VPSS;
stDestChn.s32DevId = VpssGrp;
stDestChn.s32ChnId = 0;
HI_MPI_SYS_UnBind(&stSrcChn, &stDestChn)

5.VPSS停止

HI_MPI_VPSS_StopGrp(VpssGrp);
HI_MPI_VPSS_DisableChn(VpssGrp, VpssChn);
HI_MPI_VPSS_DestroyGrp(VpssGrp);

6.VI stop

SAMPLE_COMM_VI_DestroyIsp(pstViConfig);
SAMPLE_COMM_VI_DestroyVi(pstViConfig);
SAMPLE_COMM_VI_StopMIPI(pstViConfig);

7.sysexit

HI_MPI_SYS_Exit();
HI_MPI_VB_Exit();
相关文章
|
传感器 缓存 编解码
海思3559 sample解析:vio
拿到开发板,编完了平台sample,自然按捺不住要去简单学习测试了。打开最直观相对也比较简单的vio例程做个到手分析和流程梳理吧
2260 0
海思3559 sample解析:vio
|
1月前
|
自然语言处理 数据处理 索引
mindspeed-llm源码解析(一)preprocess_data
mindspeed-llm是昇腾模型套件代码仓,原来叫"modelLink"。这篇文章带大家阅读一下数据处理脚本preprocess_data.py(基于1.0.0分支),数据处理是模型训练的第一步,经常会用到。
53 0
|
2月前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
2月前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
2月前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
2月前
|
安全 搜索推荐 数据挖掘
陪玩系统源码开发流程解析,成品陪玩系统源码的优点
我们自主开发的多客陪玩系统源码,整合了市面上主流陪玩APP功能,支持二次开发。该系统适用于线上游戏陪玩、语音视频聊天、心理咨询等场景,提供用户注册管理、陪玩者资料库、预约匹配、实时通讯、支付结算、安全隐私保护、客户服务及数据分析等功能,打造综合性社交平台。随着互联网技术发展,陪玩系统正成为游戏爱好者的新宠,改变游戏体验并带来新的商业模式。
|
2月前
|
PyTorch Shell API
Ascend Extension for PyTorch的源码解析
本文介绍了Ascend对PyTorch代码的适配过程,包括源码下载、编译步骤及常见问题,详细解析了torch-npu编译后的文件结构和三种实现昇腾NPU算子调用的方式:通过torch的register方式、定义算子方式和API重定向映射方式。这对于开发者理解和使用Ascend平台上的PyTorch具有重要指导意义。
|
3月前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
77 12
|
3月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
133 2
|
3月前
|
存储 安全 Linux
Golang的GMP调度模型与源码解析
【11月更文挑战第11天】GMP 调度模型是 Go 语言运行时系统的核心部分,用于高效管理和调度大量协程(goroutine)。它通过少量的操作系统线程(M)和逻辑处理器(P)来调度大量的轻量级协程(G),从而实现高性能的并发处理。GMP 模型通过本地队列和全局队列来减少锁竞争,提高调度效率。在 Go 源码中,`runtime.h` 文件定义了关键数据结构,`schedule()` 和 `findrunnable()` 函数实现了核心调度逻辑。通过深入研究 GMP 模型,可以更好地理解 Go 语言的并发机制。
106 1

推荐镜像

更多