sample_venc解析

本文详细介绍了海思平台上的视频处理流程,从启动VI捕获视频数据,到VPSS图像预处理,再到VENC视频编码。通过SAMPLE_VENC_1080P_CLASSIC实例,展示了如何初始化系统、配置VI、VPSS和VENC,以及选择不同的码率控制模式。整个过程涉及传感器接口、ISP、编码协议和码率控制,为理解海思视频处理提供了清晰的步骤解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

从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 可以对接收到的原始视频图像数据进行裁剪( Crop)等处理,并实现一路原始视频图像输入,输出一路视频图像功能。
主要包括1.与sensor接口对应的部分、2.ISP部分、3.VI dev和channel 部分

stViConfig.enViMode   = SENSOR_TYPE;
	stViConfig.enRotate   = ROTATE_NONE;
	stViConfig.enNorm     = VIDEO_ENCODING_MODE_AUTO;
	stViConfig.enViChnSet = VI_CHN_SET_NORMAL
<think>好的,我现在需要解决用户在使用HI_MPI_VENC_SetChnAttr设置整数帧率时失败的问题。首先,用户提到的错误是设置失败,可能返回错误码或无法生效。我需要逐步分析可能的原因并提供解决方案。 首先,了解HI_MPI_VENC_SetChnAttr这个函数的作用。根据海思SDK文档,这个函数通常用于设置视频编码通道的属性,包括帧率、分辨率等参数。用户的问题集中在设置整数帧率失败,可能是指设置的帧率参数没有被正确应用,或者函数返回了错误码。 接下来,我需要考虑可能的错误原因: 1. **参数合法性检查**:用户可能传递了非法的帧率值。例如,帧率超出设备支持的范围,或者格式不正确。比如,某些编码器可能只支持特定的帧率,如1到30之间的整数,而用户可能设置了超出这个范围的值。此外,帧率可能需要以分数形式表示(如30/1),而不是单独的整数。需要检查参数结构体中的帧率设置是否正确。 2. **编码通道状态**:如果编码通道未处于停止状态(比如正在运行中),直接设置属性可能会失败。通常,修改编码参数需要先停止通道,设置参数后再重新启动。需要确认用户在调用函数前是否已停止通道。 3. **结构体未正确初始化**:可能用户未正确初始化VENC_CHN_ATTR_S结构体,导致其他字段存在无效值,影响帧率设置。需要检查是否所有必要的字段都正确赋值,或者是否存在未初始化的变量。 4. **权限或资源冲突**:可能存在其他进程或线程占用了编码通道资源,导致设置失败。需要确认资源是否被正确释放,或者是否有其他操作冲突。 5. **SDK版本兼容性**:用户使用的SDK版本可能不支持某些帧率设置方式,或者存在已知的bug。需要检查是否有相关的更新或补丁。 接下来,根据这些可能的原因,我需要给出具体的解决步骤: - **检查帧率参数格式**:确保帧率以正确的结构体成员设置,如使用分数形式(numerator/denominator),而不是单独整数。例如,设置30帧为30/1而非直接30。 - **停止编码通道**:在调用设置函数前,先调用HI_MPI_VENC_Stop停止通道,设置属性后再重新启动。 - **验证结构体初始化**:确保VENC_CHN_ATTR_S结构体的所有必要字段都被正确初始化和赋值,避免野指针或未定义值。 - **检查错误码**:函数返回的错误码能提供具体失败原因,查阅SDK文档中的错误码解释,帮助定位问题。 - **查阅SDK文档和示例**:参考官方提供的示例代码,确认帧率设置的正确流程和参数用法。 - **更新SDK或驱动**:确认使用的SDK版本是否存在已知问题,并尝试更新到最新版本。 此外,用户提供的引用内容中提到了NULL的使用,可能在代码中存在指针未正确初始化的问题。例如,如果结构体指针未初始化为NULL,或者在使用前未正确分配内存,可能导致函数调用失败。需要检查相关代码,确保指针操作正确,避免空指针或野指针的问题。 最后,生成相关问题,帮助用户进一步排查问题,例如询问错误码、参数结构体初始化方式、编码通道状态等。</think>### 解决HI_MPI_VENC_SetChnAttr设置整数帧率失败的步骤 1. **检查帧率参数格式** 确保帧率参数以分数形式(如$30/1$)传递,而非单独整数。例如: ```c VENC_CHN_ATTR_S stChnAttr; stChnAttr.stRcAttr.stFrameRate.frmRate = 30; // 分子 stChnAttr.stRcAttr.stFrameRate.frmRateDenom = 1; // 分母 ``` 若未正确设置分母,可能导致参数非法[^1]。 2. **停止编码通道后再修改属性** 修改通道属性前需停止编码: ```c HI_MPI_VENC_Stop(VencChn); // VencChn为通道号 HI_S32 ret = HI_MPI_VENC_SetChnAttr(VencChn, &stChnAttr); HI_MPI_VENC_Start(VencChn); ``` 若通道未停止直接设置属性,可能返回`HI_ERR_VENC_BUSY`错误[^2]。 3. **验证结构体初始化** 初始化`VENC_CHN_ATTR_S`结构体时,需确保所有字段合法: ```c memset(&stChnAttr, 0, sizeof(VENC_CHN_ATTR_S)); // 清空结构体 stChnAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR; // 示例:设置编码模式 ``` 未初始化的结构体可能包含随机值,导致设置失败。 4. **解析错误码** 根据函数返回值排查问题: ```c if (ret != HI_SUCCESS) { printf("Error code: 0x%x\n", ret); // 输出错误码 } ``` 常见错误码: - `0xA0188009`(参数非法):检查帧率范围或格式 - `0xA0188003`(通道未创建):确认通道号是否正确 5. **参考SDK示例代码** 查阅海思提供的`venc_sample.c`,对比帧率设置流程,确认是否遗漏关键步骤。 6. **更新SDK或驱动** 若问题持续,检查SDK版本是否为最新,部分旧版本存在帧率设置兼容性问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值