logo资料库

海思VENC编码操作流程.docx

第1页 / 共10页
第2页 / 共10页
第3页 / 共10页
第4页 / 共10页
第5页 / 共10页
第6页 / 共10页
第7页 / 共10页
第8页 / 共10页
资料共10页,剩余部分请下载后查看
一、启动VENC编码
step 1: init sys variable
step 2: mpp system init.
step 3: start vi dev & chn to capture
step 4: start vpss and vi bind vpss
step 5: start stream venc
step 6: stream venc process -- get stream, then sa
二、获取VENC编码流
step 1:venc-fd
step 2: Start to get streams of each channel.
step 2.1 : query how many packs in one-frame s
step 2.2 :suggest to check both u32CurPacks and u
if(0 == stStat.u32CurPacks || 0 == stStat.u32Left
{
SAMPLE_PRT("NOTE: Current frame is NULL!\n");
continue;
}
step 2.3 : malloc corresponding number of pack
step 2.4 : call mpi to get one-frame stream
step 2.5 : release stream
step 2.6 : free pack nodes
一、启动 VENC 编码 step 1: init sys variable 根据《HiMPP IPC V2.0 媒体处理软件开发参考》里面说的软件架构来讲,这一步主要是 为了创建视频缓冲池的 conf 配置 配置变量为 VB_CONF_S stVbConf; 结构体定义如下 typedef struct hiVB_CONF_S { HI_U32 u32MaxPoolCnt; struct hiVB_CPOOL_S { //缓冲池最大数量 HI_U32 u32BlkSize; HI_U32 u32BlkCnt; HI_CHAR acMmzName[MAX_MMZ_NAME_LEN]; //每个缓冲池的大小 //每个缓冲池能分为几块 }astCommPool[VB_MAX_COMM_POOLS]; //未用到 } VB_CONF_S; 缓冲池最大数量和每个缓冲池能分几块问题不大,sample 例程给的默认值是 128 和 20 每个缓冲池的大小需要调用函数 SAMPLE_COMM_SYS_CalcPicVbBlkSize 通过返回值获取 函数原型如下 HI_U32 SAMPLE_COMM_SYS_CalcPicVbBlkSize( VIDEO_NORM_E enNorm, PIC_SIZE_E enPicSize, //电视广播制式,有 PLA 或者 NTSC 等等 //长宽尺寸,不过这里是用宏定义的,想要自定义尺寸,需 要在 hiPIC_SIZE_E 枚举里面添加自定的宏定义,然后再 SAMPLE_COMM_SYS_GetPicSize 函数 中返回具体的长宽 PIXEL_FORMAT_E enPixFmt, //像素格式,比如 YUV422,YUV420 等等 HI_U32 u32AlignWidth //系统中使用图像的字节对齐数,在初始化 MPP 系统的 时候传入 ) 所以第一步就是为了填充定义的 stVbConf 变量
step 2: mpp system init. 这一步主要是做两个工作 1.初始化视频缓冲池处理模块(VB) 2.初始化 MPP 系统 调用的接口是 SAMPLE_COMM_SYS_Init,传入上一步中我们填充的配置 stVbConf 即可 step 3: start vi dev & chn to capture 这一步就是调用函数 SAMPLE_COMM_VI_StartVi 来设置 VI 和 chn 并且开始捕获图像 这个函数需要传入一个 SAMPLE_VI_CONFIG_S* pstViConfig 变量,结构体的原型如下 typedef struct sample_vi_config_s { SAMPLE_VI_MODE_E enViMode; //输入的格式,BT656/BT1120 或者是 Digital Camera 等等 VIDEO_NORM_E enNorm; ROTATE_E enRotate; SAMPLE_VI_CHN_SET_E enViChnSet; WDR_MODE_E enWDRMode; } SAMPLE_VI_CONFIG_S; //电视广播制式,有 PLA 或者 NTSC 等等 //旋转角度, //通道设置,镜像或者翻转 //宽动态范围模式 所以这一步就是填充定义的 pstViConfig 变量,然后调用 SAMPLE_COMM_VI_StartVi 开始 捕获输入
step 4: start vpss and vi bind vpss 根据《HiMPP IPC V2.0 媒体处理软件开发参考》里面说的软件架构来讲,数据接收者需 要绑定数据源 绑定后,数据源的数据将直接送给数据接收者,为了编码我们需要将 VPSS 绑定 VI,然 后将 VENC 绑定 VPSS 这里的工作就是两个 1.创建一个 VPSS_GROUP(各 Group 分时复用) 2.将 VPSS 绑定到 VI 3.启动 VPSS(上一步我们已经启动了 VI) 4.1.创建一个 VPSS_GROUP(各 Group 分时复用) 创建一个 VPSS,需要调用 SAMPLE_COMM_VPSS_StartGroup 函数,函数原型如下 HI_S32 SAMPLE_COMM_VPSS_StartGroup( VPSS_GRP VpssGrp, VPSS_GRP_ATTR_S* pstVpssGrpAttr //VPSS 属性变量 //VPSS_GRP 编号,范围是 0 - VPSS_MAX_GRP_NUM 之间 ) 想要创建一个 VPSS,就需要我们构建一个 VPSS_GRP_ATTR_S 属性结构体,这个结构 体的定义如下 typedef struct hiVPSS_GRP_ATTR_S { /*statistic attributes*/ HI_U32 u32MaxW; /*MAX width of the group*/ 不可更改 //最大宽度,创建时设定, HI_U32 u32MaxH; /*MAX height of the group*/ //最大高度,创建时设定, 不可更改 PIXEL_FORMAT_E enPixFmt; /*Pixel format*/ //像素格式,比如 YUV422, YUV420 等等 HI_BOOL bIeEn; /*Image enhance enable*/ //保留,必须设置为 HI_FALSE HI_BOOL bDciEn; HI_BOOL bNrEn; HI_BOOL bHistEn; /*Dynamic contrast Improve enable*/ /*Noise reduce enable*/ /*Hist enable*/ //保留,必须设置为 HI_FALSE //去噪 //保留,必须设置为 HI_FALSE VPSS_DIE_MODE_E enDieMode; /*De-interlace enable*/ // 保 留 , 必 须 设 置 为 VPSS_DIE_MODE_NODIE }VPSS_GRP_ATTR_S;
4.2.将 VPSS 绑定到 VI 将 VPSS 绑定到 VI,需要调用 SAMPLE_COMM_VI_BindVpss 函数,函数原型如下 HI_S32 SAMPLE_COMM_VI_BindVpss( SAMPLE_VI_MODE_E enViMode //输入的格式,BT656/BT1120 或者是 Digital Camera 等等 ) 这里我们调用的时候,enVimode 可以使用第三步创建的结构体 pstViConfig 变量中的 enViMode 即可 4.3.启动 VPSS(上一步我们已经启动了 VI) 这里需要先说一下 VPSS 组通道的概念,手册上是这样说的 VPSS 组的通道。通道分为 2 种:物理通道和扩展通道。 VPSS 硬件提供多个 物理通道,每个通道具有缩放、裁剪等功能。扩展通道具备缩放功能,它通过绑定物理通道, 将物理通道输出作为自己的输入,把图像缩放成用户设置的目标分辨率输出。 所以,我们要启动 VPSS 就需要绑定物理通道,然后启动这个物理通道 需要调用的函数是 SAMPLE_COMM_VPSS_EnableChn,其原型为 HI_S32 SAMPLE_COMM_VPSS_EnableChn( VPSS_GRP VpssGrp, VPSS_CHN VpssChn, VPSS_CHN_ATTR_S* pstVpssChnAttr, VPSS_CHN_MODE_S* pstVpssChnMode, VPSS_EXT_CHN_ATTR_S* pstVpssExtChnAttr //VPSS_GRP 编号,范围是 0 - VPSS_MAX_GRP_NUM 之间 //VPSS_CHN 编号,范围是 0 - VPSS_MAX_CHN_NUM 之间 //VPSS 物理通道属性 //VPSS_CHN 工作模式结构 //VPSS 扩展通道属性 ) 可以看到,这里我们需要定义三个结构体,VPSS_CHN_ATTR_S 结构体定义如下 typedef struct hiVPSS_CHN_ATTR_S { HI_BOOL bSpEn; HI_BOOL bBorderEn; HI_BOOL bMirror; //保留,只能为 HI_FALSE //保留,只能为 HI_FALSE //镜像开关(第三步也有一个开关,那里是 VI 的通道,这里 是 VPSS 的通道) HI_BOOL bFlip; 里是 VPSS 的通道) //翻转开关(第三步也有一个开关,那里是 VI 的通道,这 HI_S32 s32SrcFrameRate; //通道帧率控制:源帧率[-1,60],源帧率与目标帧率都 为-1,则不进行帧率控制 HI_S32 s32DstFrameRate; //通道帧率控制: 目标帧率[-1,60],源帧率与目标帧率都 为-1,则不进行帧率控制 BORDER_S stBorder; //边框属性,可以定义各个边的宽度以及整个框的颜色 }VPSS_CHN_ATTR_S;
VPSS_CHN_MODE_S 结构体定义如下 typedef struct hiVPSS_CHN_MODE_S { VPSS_CHN_MODE_E enChnMode; //VPSS_CHN 工作模式,USER 模式主要用于同一 通道图像进行多路编码的场景 HI_U32 u32Width; HI_U32 u32Height; HI_BOOL bDouble; PIXEL_FORMAT_E COMPRESS_MODE_E enCompressMode; //目标图像宽 //目标图像高 //保留 enPixelFormat; //目标图像像素格式,比如 YUV422,YUV420 等等 //目标图像压缩格式 }VPSS_CHN_MODE_S; 做完这三步,VPSS 就应该开始正常工作了, step 5: start stream venc 截止到上一步,VI 和 VPSS 我们都已经启动了,所以接下来我们就需要绑定 VENC 和 VPSS, 然后启动 VENC 进行编码 1.绑定 VENC 到 VPSS 绑定 VENC 到 VPSS 需要调用 SAMPLE_COMM_VENC_BindVpss 函数,函数原型如下 HI_S32 SAMPLE_COMM_VENC_BindVpss( VENC_CHN VeChn, VPSS_GRP VpssGrp, VPSS_CHN VpssChn ) //VENC 通道编号 //VPSS_GROUP 通道编号 //VPSS 通道编号 这三个参数我们之前都已经用到过了,很简单 2.启动 VNCE 编码 启动 VNCE 编码需要调用 SAMPLE_COMM_VENC_Start 函数,函数原型如下 HI_S32 SAMPLE_COMM_VENC_Start( VENC_CHN VencChn, PAYLOAD_TYPE_E enType, VIDEO_NORM_E enNorm, PIC_SIZE_E enSize, SAMPLE_RC_E enRcMode, HI_U32 u32Profile //VENC 通道编号 //编码类型,即进行哪一种编码 //电视广播制式,有 PLA 或者 NTSC 等等 //长宽尺寸 //码率控制属性 //帧/包模式获取码流,HI_TRUE:按帧获取, HI_FALSE:按包获取 ) 到这一步,从 VI 到 VENC 就已经全部配置完成了
step 6: stream venc process -- get stream, then save it to file. 这个例程中我们只是进行了 VENC 编码,但是编码后的码流截止到目前我们没有获取到 只有获取到编码后的码流,我们才能进行下一步操作 海思在这里启动了一个新线程,用来获取编码后的码流 为了启动新线程我们在这里只需要调用 SAMPLE_COMM_VENC_StartGetStream 函数即可, 函数源码如下 HI_S32 SAMPLE_COMM_VENC_StartGetStream(HI_S32 s32Cnt) { gs_stPara.bThreadStart = HI_TRUE; gs_stPara.s32Cnt = s32Cnt; return pthread_create(&gs_VencPid, 0, SAMPLE_COMM_VENC_GetVencStreamProc, (HI_VOID*)&gs_stPara); } 可以看到,获取编码后码流的流程在 SAMPLE_COMM_VENC_GetVencStreamProc 线程中 进行了处理 截止到这一步,我们就相当于做完了初始化的工作,后面对编码后码流的操作需要去新 线程中处理
二、获取 VENC 编码流 step 1:venc-fd 第一步我们需要获取编码通道对应的设备文件句柄,有了这个句柄我们才能进行后续的 操作 获取句柄需要调用 HI_MPI_VENC_GetFd 函数,函数原型如下 HI_S32 HI_MPI_VENC_GetFd( VENC_CHN VeChn //venv 通道,这里例程的处理是遍历 venc 所有的通道, 然后都存放在数组里 ); step 2: Start to get streams of each channel. 开始编码之后我们并不知道什么时候哪个通道会编码完成,所以这里我们需要使用 select 函数 监听所有通道的句柄,一旦某个通道的句柄可读了,就处理该通道 /******************************************************* step 2.1 : query how many packs in one-frame stream. *******************************************************/ 虽然该通道可读了,但是我们还需要查询编码通道状态来获取已编码帧个数和未编 码帧个数 查询编码通道状态调用 HI_MPI_VENC_Query 函数,该函数原型如下 HI_S32 HI_MPI_VENC_Query( VENC_CHN VeChn, VENC_CHN_STAT_S *pstStat //VENC_CHN 编号 //编码通道的状态指针 ); 编码通道的状态我们通过 pstStat 参数来获取,结构体体的定义如下 typedef struct hiVENC_CHN_STAT_S { HI_U32 u32LeftPics; HI_U32 u32LeftStreamBytes; //待编码的图像数 //码流 buffer 剩余的 byte
数 HI_U32 u32LeftStreamFrames; HI_U32 u32CurPacks; HI_U32 u32LeftRecvPics; 用户设置 HI_MPI_VENC_StartRecvPicEx 后有效 HI_U32 u32LeftEncPics; 用户设置 HI_MPI_VENC_StartRecvPicEx 后有效 }VENC_CHN_STAT_S; //码流 buffer 剩余的帧数 //当前帧的码流包个数 //剩余待接收的帧数,在 //剩余待编码的帧数,在 /******************************************************* step 2.2 :suggest to check both u32CurPacks and u32LeftStreamFrames at the same time,for example: if(0 == stStat.u32CurPacks || 0 == stStat.u32LeftStreamFrames) { } SAMPLE_PRT("NOTE: Current frame is NULL!\n"); continue; ******************************************************/ 这一步如注释所说,要确定当前帧已经编码完成或者当前帧不为空 /******************************************************* step 2.3 : malloc corresponding number of pack nodes. *******************************************************/ 分配空间,准备获取编码流,
分享到:
收藏