1.1 海思3518 H264编码

海思的SDK里其实有H264编码的sample,但因为要匹配很多东西,代码有点复杂,让初学都感到有点混乱。我根据sample自己修改了一下代码,从最简单的情况(确定摄像头类型,只选一种尺寸的图片,只用一个通道)来说明海思HI3518是怎么编码为H264的。

先把源代码下载下来,再分析程序。

下载链接:https://download.csdn.net/download/zhanshenrui/10324766

首先从main函数开始。

//./myvenc 
int main(int argc, char *argv[])//main()
{
	HI_S32 s32Ret;
	signal(SIGINT, SAMPLE_VENC_HandleSig);//ctrl+c,delete
	signal(SIGTERM, SAMPLE_VENC_HandleSig);//shell命令kill缺省产生这个信号.
	s32Ret = H264_Venc();
			
	if(s32Ret==HI_SUCCESS)
		printf("normally\n");
	else
		printf("unnormally\n");
	return -1;
}

main函数里先是用signal定义了两个信号来中断程序的运行,在板子上输入./myvenc 执行程序,按ctrl+c来中断程序,然后再往下就是H264编码函数H264_Venc()。

H264_Venc()函数里先去初始化MPI系统,然后根据摄像头设置参数。我这里是AR030摄像头,其拍摄图片大小为720P,编码为H264,为了简单只输出一路。在初始化MPI系统时要计算视频缓存池VB_CONF_S的大小,然后填充VB_CONF_S结构体。填充完VB_CONF_S结构体后再用HI_MPI_VB_SetConf设置,最后初始化视频视频缓存池HI_MPI_VB_Init。这里注意的是基本上每个函数调用后都会判断返回值并作出错出理,后面很多函数也是这样处理的,这样利于程序排错。

//为了简单点,编码类型就选择PT_H264,图片大小就选择PIC_HD720,通道也只用1路s32ChnNum=1
	PAYLOAD_TYPE_E enPayLoad=PT_H264;//264编码
	PIC_SIZE_E	enSize=PIC_HD720;//摄像头拍摄图片的大小,这里只用720P
	HI_S32	s32ChnNum=1;//支持一路摄像
	HI_S32 s32Ret=HI_FAILURE;

	/******************************************
	mpp system init. 
	******************************************/
	HI_MPI_SYS_Exit();
	HI_MPI_VB_Exit();
	
	VB_CONF_S stVbConf;//缓存池参数结构体
	HI_U32 u32BlkSize;//一张图片占多少字节
	memset(&stVbConf,0,sizeof(VB_CONF_S));
	//根据制式,图片大小,图片格式及对齐方式确定图片缓存大小
	//这里用NTSC,720P,YUV420,64字节对齐
	u32BlkSize=SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,enSize, PIXEL_FORMAT_YUV_SEMIPLANAR_420, SAMPLE_SYS_ALIGN_WIDTH);
	printf("u32BlkSize=%d\n",u32BlkSize);
	stVbConf.u32MaxPoolCnt = 128;//用默认值,3518默认是128
	stVbConf.astCommPool[0].u32BlkSize = u32BlkSize;
	stVbConf.astCommPool[0].u32BlkCnt = g_u32BlkCnt;
	s32Ret = HI_MPI_VB_SetConf(&stVbConf);//设置 MPP 视频缓存池属性
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_VB_SetConf failed!\n");
		return HI_FAILURE;
	}
	s32Ret = HI_MPI_VB_Init();//初始化 MPP 视频缓存池
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_VB_Init failed!\n");
		return HI_FAILURE;
	}
视频缓存池初始化后就是初始化MPI系统。海思模块化了各个功能,我们想实现哪一种产品就按这种产品的框架来实现各个模块功能,而实现模块化功能也很简单,基本套路就是定义一个结构体,给结构体赋值,然后设置就可以了,像前面缓存池模块就是先定一个VB_CONF_S结构体,然后对结体体赋值,然后调用函数设置进去,最后初始化。同理,初始化MPI系统也要先定义一个结构体再赋值然后设置最后初始化,这种思路在linux里用得很多。

//定义结构体,对结构体赋值,然后设置,最后初始化
	MPP_SYS_CONF_S stSysConf = {0};
	stSysConf.u32AlignWidth = SAMPLE_SYS_ALIGN_WIDTH;
	s32Ret = HI_MPI_SYS_SetConf(&stSysConf);//配置系统控制参数
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_SYS_SetConf failed\n");
		return HI_FAILURE;
	}
	s32Ret = HI_MPI_SYS_Init();//初始化 MPP 系统
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("HI_MPI_SYS_Init failed!\n");
		return HI_FAILURE;
	}
系统初始化完后还要打开硬件,摄像头用的是MIPI,应用层只需要用open打开MIPI,用ioctl设置

HI_S32 fdmipi;
	combo_dev_attr_t *pstcomboDevAttr = NULL;
	fdmipi = open("/dev/hi_mipi", O_RDWR);
	if (fdmipi < 0)
	{
		printf("warning: open hi_mipi dev failed\n");
		return -1;
	}
	pstcomboDevAttr = &MIPI_CMOS3V3_ATTR;//AR0130模组属性
	if (ioctl(fdmipi, HI_MIPI_SET_DEV_ATTR, pstcomboDevAttr))
	{
		printf("set mipi attr failed\n");
		close(fdmipi);
	return HI_FAILURE;
	}
	close(fdmipi);
根据海思SDK里的文档介绍,H264编码过程应该是:系统初始化--VI--VPSS-VENC.系统初始化前面已完成,现在要做的就是实现输入模块VI.VI模块有通道,所以还要设置通道参数。具体解释和代码如下,不再做过多解释:

HI_S32 i,ViChn=0;//只有一路输出,所以ViChn=0
	//设置输入配置参数
	SAMPLE_VI_CONFIG_S stViConfig = {0};
	stViConfig.enViMode   = APTINA_AR0130_DC_720P_30FPS;//摄像头是AR0130模组
	stViConfig.enRotate   = ROTATE_NONE;//不翻转
	stViConfig.enNorm     = VIDEO_ENCODING_MODE_AUTO;//编码模式自动
	stViConfig.enViChnSet = VI_CHN_SET_NORMAL;//普通
	stViConfig.enWDRMode  = WDR_MODE_NONE;//不设置宽动态

	VI_DEV_ATTR_S  stViDevAttr;
	VI_DEV ViDev=0;//只有一个摄像头设备,所以设备序号为0
	ISP_DEV s32IspDev=0;//同样,ISP序号也为0
	memset(&stViDevAttr,0,sizeof(stViDevAttr));
	memcpy(&stViDevAttr,&DEV_ATTR_9M034_DC_720P_BASE,sizeof(stViDevAttr));
	/******************************************
	step 1: mipi configure
	******************************************/
	/*
	s32Ret = SAMPLE_COMM_VI_StartMIPI(&stViConfig);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("%s: MIPI init failed!\n", __FUNCTION__);
		return HI_FAILURE;
	}  
	*/
	/******************************************
	step 2: configure sensor and ISP (include WDR mode).
	note: you can jump over this step, if you do not use Hi3516A interal isp. 
	//虽然说了不用,但还要需要,因为后面HI_MPI_ISP_GetWDRMode函数会调用ISP_CHECK_MEM_INIT
	//检测内存,所以还是在这里使用
	******************************************/
	s32Ret = SAMPLE_COMM_ISP_Init(stViConfig.enWDRMode);
	if (HI_SUCCESS != s32Ret)
	{
		SAMPLE_PRT("%s: Sensor init failed!\n", __FUNCTION__);
		return HI_FAILURE;
  • 10
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值