概述
从main函数开始,根据传入参数选择对VI VPSS等模块的操作,等。
一般选择进入 SAMPLE_VENC_1080P_CLASSIC
在 SAMPLE_VENC_1080P_CLASSIC 中进行如下操作
step0:定义了一些视频编解码过程中会用到的变量
setp1:init sys variable video buffer(初始化系统变量 MPP系统缓存池定义)
step2:mpp system init(MPP系统初始化)
step3:start vi dev & chn to capture(开启VI,并捕获视频通道数据)
step4:start vpss and vi bind vpss(开启VPSS,并绑定视频通道等)
step5:start stream venc(开启venc流视频)
step6:stream venc process – get stream, then save it to file (开启venc处理,获取视频流,并保存到文件中)
然后getchar等待程序结束
main函数
主要是根据argv[]来决定具体视频处理的具体码率大小,通道数等,具体见代码。
SAMPLE_VENC_1080P_CLASSIC
step0:定义了一堆变量
#还有一些等下来补充
PAYLOAD_TYPE_E enPayLoad[3]= {PT_H264, PT_H264,PT_H264}; #存放三路视频的编码格式,这里仅仅是默认填充,具体还要在后面根据参数填充
PIC_SIZE_E enSize[3] = {PIC_HD1080, PIC_VGA,PIC_QVGA}; #存放的是视频大小,也是默认填充,具体大小后面填充
HI_U32 u32Profile = 0;
VB_CONF_S stVbConf; #视频缓冲区管理块
SAMPLE_VI_CONFIG_S stViConfig = {0}; #VI模块配置结构体
VPSS_GRP VpssGrp;
VPSS_CHN VpssChn;
VPSS_GRP_ATTR_S stVpssGrpAttr;
VPSS_CHN_ATTR_S stVpssChnAttr;
VPSS_CHN_MODE_S stVpssChnMode;
VENC_CHN VencChn;
SAMPLE_RC_E enRcMode= SAMPLE_RC_CBR;
HI_S32 s32ChnNum=0;
HI_S32 s32Ret = HI_SUCCESS;
HI_U32 u32BlkSize;
SIZE_S stSize;
char c;
setp1:init sys variable video buffer(初始化系统变量 MPP系统缓存池定义)
/**************************************************************************************************************************
step 1: init sys variable
**************************************************************************************************************************/
memset(&stVbConf,0,sizeof(VB_CONF_S)); #清空stVbConf视频缓存池控制块数据
SAMPLE_COMM_VI_GetSizeBySensor(&enSize[0]); #根据VI输入的sensor来填充enSize[0](存放输出视频流的大小)
if (PIC_HD1080 == enSize[0]) #再根据enSize[0]来填充enSize[1]
{
enSize[1] = PIC_VGA;
s32ChnNum = 2;
}
else if (PIC_HD720 == enSize[0])
{
enSize[1] = PIC_VGA;
enSize[2] = PIC_QVGA;
s32ChnNum = 3;
}
else
{
printf("not support this sensor\n");
return HI_FAILURE;
}
#ifdef hi3518ev201
s32ChnNum = 1;
#endif
printf("s32ChnNum = %d\n",s32ChnNum);
stVbConf.u32MaxPoolCnt = 128; #这是设置允许的最大缓存池数量,实际缓存池数量肯定比这个少
/*****************************************video buffer*****************************************/
if(s32ChnNum >= 1) #根据s32ChnNum通道数来选择填充stVbConf元素,
{
u32BlkSize = SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,\
enSize[0], SAMPLE_PIXEL_FORMAT, SAMPLE_SYS_ALIGN_WIDTH);
stVbConf.astCommPool[0].u32BlkSize = u32BlkSize;
stVbConf.astCommPool[0].u32BlkCnt = g_u32BlkCnt;
}
if(s32ChnNum >= 2)
{
u32BlkSize = SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,\
enSize[1], SAMPLE_PIXEL_FORMAT, SAMPLE_SYS_ALIGN_WIDTH);
stVbConf.astCommPool[1].u32BlkSize = u32BlkSize;
stVbConf.astCommPool[1].u32BlkCnt =g_u32BlkCnt;
}
if(s32ChnNum >= 3)
{
u32BlkSize = SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,\
enSize[2], SAMPLE_PIXEL_FORMAT, SAMPLE_SYS_ALIGN_WIDTH);
stVbConf.astCommPool[2].u32BlkSize = u32BlkSize;
stVbConf.astCommPool[2].u32BlkCnt = g_u32BlkCnt;
}
step2:mpp system init(MPP系统初始化)
将 stVbConf 传入 SAMPLE_COMM_SYS_Init ,根据 stVbConf 具体实际初始化缓存池
s32Ret = SAMPLE_COMM_SYS_Init(&stVbConf);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("system init failed with %d!\n", s32Ret);
goto END_VENC_1080P_CLASSIC_0;
}
其中 SAMPLE_COMM_SYS_Init
/******************************************************************************
-
function : vb init & MPI system init
******************************************************************************/
HI_S32 SAMPLE_COMM_SYS_Init(VB_CONF_S *pstVbConf)
{
MPP_SYS_CONF_S stSysConf = {0};
HI_S32 s32Ret = HI_FAILURE;HI_MPI_SYS_Exit(); #EXIT主要防止系统之前已经初始化过了…
HI_MPI_VB_Exit();s32Ret = HI_MPI_VB_SetConf(pstVbConf); #下面这一系列函数都是海思以KO的形式提供的模块库
s32Ret = HI_MPI_VB_Init();
stSysConf.u32AlignWidth = SAMPLE_SYS_ALIGN_WIDTH;
s32Ret = HI_MPI_SYS_SetConf(&stSysConf);
s32Ret = HI_MPI_SYS_Init();
return HI_SUCCESS;
}step3:start vi dev & chn to capture(开启VI,并捕获视频通道数据)
填充 stViConfig 结构体,将 stViConfig 传入 SAMPLE_COMM_VI_StartVi 开启VI模块stViConfig.enViMode = SENSOR_TYPE; #sensor模块的类型
stViConfig.enRotate = ROTATE_NONE; #图像旋转是否
stViConfig.enNorm = VIDEO_ENCODING_MODE_AUTO; #视频自动编解码
stViConfig.enViChnSet = VI_CHN_SET_NORMAL; #VI通道自动设置
stViConfig.enWDRMode = WDR_MODE_NONE; #不设置宽动态模式
s32Ret = SAMPLE_COMM_VI_StartVi(&stViConfig); #根据以上具体设置初始化传感器模块
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT(“start vi failed!\n”);
goto END_VENC_1080P_CLASSIC_1;
}start vpss and vi bind vpss(开启VPSS,并绑定视频通道等)
/******************************************
step 4: start vpss and vi bind vpss
******************************************/
s32Ret = SAMPLE_COMM_SYS_GetPicSize(gs_enNorm, enSize[0], &stSize); #根据 gs_enNorm 、enSize[0] 的值来填充 stSize 结构体
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT(“SAMPLE_COMM_SYS_GetPicSize failed!\n”);
goto END_VENC_1080P_CLASSIC_1;
}
if(s32ChnNum >= 1)
{ #填充 stVpssGrpAttr 结构体
VpssGrp = 0;
stVpssGrpAttr.u32MaxW = stSize.u32Width;
stVpssGrpAttr.u32MaxH = stSize.u32Height;
stVpssGrpAttr.bIeEn = HI_FALSE;
stVpssGrpAttr.bNrEn = HI_TRUE;
stVpssGrpAttr.bHistEn = HI_FALSE;
stVpssGrpAttr.bDciEn = HI_FALSE;
stVpssGrpAttr.enDieMode = VPSS_DIE_MODE_NODIE;
stVpssGrpAttr.enPixFmt = PIXEL_FORMAT_YUV_SEMIPLANAR_420;s32Ret = SAMPLE_COMM_VPSS_StartGroup(VpssGrp, &stVpssGrpAttr); #开启VPSS GRP。 if (HI_SUCCESS != s32Ret) { SAMPLE_PRT("Start Vpss failed!\n"); goto END_VENC_1080P_CLASSIC_2; } s32Ret = SAMPLE_COMM_VI_BindVpss(stViConfig.enViMode); #绑定VPSS通道 if (HI_SUCCESS != s32Ret) { SAMPLE_PRT("Vi bind Vpss failed!\n"); goto END_VENC_1080P_CLASSIC_3; } VpssChn = 0; stVpssChnMode.enChnMode = VPSS_CHN_MODE_USER; #填充VPSS通道模式 stVpssChnMode.bDouble = HI_FALSE; stVpssChnMode.enPixelFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_420; stVpssChnMode.u32Width = stSize.u32Width; stVpssChnMode.u32Height = stSize.u32Height; stVpssChnMode.enCompressMode = COMPRESS_MODE_SEG; memset(&stVpssChnAttr, 0, sizeof(stVpssChnAttr)); stVpssChnAttr.s32SrcFrameRate = -1; stVpssChnAttr.s32DstFrameRate = -1; s32Ret = SAMPLE_COMM_VPSS_EnableChn(VpssGrp, VpssChn, &stVpssChnAttr, &stVpssChnMode, HI_NULL); #根据stVpssChnMode 来使能CHN if (HI_SUCCESS != s32Ret) { SAMPLE_PRT("Enable vpss chn failed!\n"); goto END_VENC_1080P_CLASSIC_4; }
}
step5:start stream venc(开启venc流视频)
/******************************************
step 5: start stream venc
***************************************/
/ HD1080P **/
printf("\t c) cbr.\n");
printf("\t v) vbr.\n");
printf("\t f) fixQp\n");
printf(“please input choose rc mode!\n”);
c = (char)getchar();
switch©
{ #根据输入的字符决定具体哪种模式
case ‘c’:
enRcMode = SAMPLE_RC_CBR;
break;
case ‘v’:
enRcMode = SAMPLE_RC_VBR;
break;
case ‘f’:
enRcMode = SAMPLE_RC_FIXQP;
break;
default:
printf(“rc mode! is invaild!\n”);
goto END_VENC_1080P_CLASSIC_4;
}
/*** enSize[0] **/
if(s32ChnNum >= 1)
{
VpssGrp = 0;
VpssChn = 0;
VencChn = 0;
s32Ret = SAMPLE_COMM_VENC_Start(VencChn, enPayLoad[0],\ #开启venc视频流
gs_enNorm, enSize[0], enRcMode,u32Profile);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("Start Venc failed!\n");
goto END_VENC_1080P_CLASSIC_5;
}
s32Ret = SAMPLE_COMM_VENC_BindVpss(VencChn, VpssGrp, VpssChn); #绑定 VencChn 与 VpssChn
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("Start Venc failed!\n");
goto END_VENC_1080P_CLASSIC_5;
}
}
step6:stream venc process – get stream, then save it to file (开启venc处理,获取视频流,并保存到文件中)
/******************************************
step 6: stream venc process – get stream, then save it to file.
******************************************/
s32Ret = SAMPLE_COMM_VENC_StartGetStream(s32ChnNum); #获取venc视频流,函数源码其实是开启了一个线程来获取视频并保存视频流
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT(“Start Venc failed!\n”);
goto END_VENC_1080P_CLASSIC_5;
}
printf("please press twice ENTER to exit this sample\n");
getchar();
getchar();
step7:exit process
/******************************************
step 7: exit process
******************************************/
SAMPLE_COMM_VENC_StopGetStream(); #键盘按下两次退出程序后释放相关资源,包括关闭线程等操作,然后继续退出程序
VI部分
频输入( VI)模块实现的功能:通过 ITU-R BT656/601/1120 接口或 Digital Camera接口、 MIPI Rx(含 MIPI 接口、 LVDS 接口和 HISPI 接口)接收视频数据。当工作在离线模式时,将接收到的数据存入到指定的内存区域;当工作在在线模式时, VI 会将数据直接送给 VPSS。在此过程中, VI 可以对接收到的原始视频图像数据进行裁