嵌入式 视频编码(H264)hi3518 sample流程及API

stViConfig.enViMode
=(SENSOR_TYPE)
=APTINA_AR0130_DC_720P_30FPS

摄像头获取的模拟信号通过经芯片处理(我们使用的是CX25825),将模拟信号转成数字信号,产生标准的ITU 656 YUV格式的数字信号以帧为单位送到编码卡上的DSP和内存中。分别供视频实时预览、移动侦测处理以及编码等使用。其中编码的作用是将编码卡内存中的YUV数据送到H264编码器中,进过H.264编码产生压缩好的码流,送到主机内存中,供录像或网络传输使用。编码模块完成各个协议编码,协调 MD、VPP 相关模块的管理、同步和控制,配合软件调度和硬件共同完成视频编码相关功能。

一、重要概念

主次码流

主次码流是指硬件逻辑单元启动一次同时产生的 2 路码流,即 1 路主码流和 1 路次码流。主码流和次码流可以为不同的编码协议,但其宽高比例都必须满足 1:1、1:2 或 1:4,次码流不能单独存在(必须和 1 路主码流在同一个通道组中) 。

双码流

双码流是指硬件逻辑单元启动 2 次分时产生的 2 个码流,即 2 路主码流。双码流可以为不同的编码协议,双码流之间的大小比例没有约束关系。

通道组

通道组是指芯片能够同时处理的编码通道的集合,相当于一个容器。一个通道组最多可同时包含 1 路主码流(H.264/MJPEG) 、1路次码流(H.264/MJPEG) ,或者仅包含 1 路 JPEG抓拍(即 JPEG抓拍时,不允许包含任何其他通道) ,或者 1 路MPEG4 编码通道。

12 系统初始化(SYS INT):------------------------
1 初始化并配置VB视频缓冲池;   
{
   
	memset(&stVbConf,0,sizeof(VB_CONF_S));
	SAMPLE_COMM_VI_GetSizeBySensor(&enSize[0]);
}
2 初始化系统   
SAMPLE_COMM_SYS_Init{
   
	2个去初始化 SYS_Exit VB_Exit
	VB和SYS各自的的 配置+Init: ①VB_SetConf     ②VB_Init  ①SYS_SetConf ②SYS_Init
}


3 配置视频捕获(VI+ISP):------------------------ start vi dev & chn to capture--------------
【SAMPLE_COMM_VI_StartVi】→→【SAMPLE_COMM_VI_StartIspAndVi(pstViConfig);】
	配置MIPI     SAMPLE_COMM_VI_StartMIPI
	初始化ISP     SAMPLE_COMM_ISP_Init(pstViConfig->enWDRMode);
	运行ISP线程    SAMPLE_COMM_ISP_Run();
	配置开启VI 设备捕获  SAMPLE_COMM_VI_StartDev(ViDev, enViMode);
	配置开启VI 通道123捕获   SAMPLE_COMM_VI_StartChn   HI_MPI_VI_SetChnAttr(ViChn, &stChnAttr);【设置 源、目标帧率 -1 -1 不设置】

4 配置视频处理子系统(VPSS):------------------------ start vpss and vi bind vpss

绑定:
 ①创建启用启用VPSS GROUP=0 ②vi-chn和vpss-grp绑定
  ③各个通道012:
 填充VPSS通道模式stVpssChnMode
 ↓
 设置HI_MPI_VPSS_SetChnAttr(VpssGrp, VpssChn, VPSS_CHN_ATTR_S);
 【物理通道额外需要HI_MPI_VPSS_SetChnMode】
 ↓
 使能通道HI_MPI_VPSS_EnableChn(VpssGrp, VpssChn);

5 创建配置编码通道(VENC)----------------------------
{
   
	码率控制模式3选一 CBR VBR FIXQP
	创建 开启编码通道           SAMPLE_COMM_VENC_Start      
	绑定VPSS_group_chn到VENC_chn         SAMPLE_COMM_VENC_BindVpss(VencChn, VpssGrp, VpssChn);→→HI_MPI_SYS_Bind
} 

6 获取并处理编码码流---------------------SAMPLE_COMM_VENC_StartGetStream(s32ChnNum);
{
   
	1获取编码通道参数VENC_CHN_ATTR_S
	依据视频类型决定文件后缀 打开并得到存储用的文件描述符*pFile[i]
	获取编码设备文件句柄  VencFd[012] = HI_MPI_VENC_GetFd(012);
	2 while (HI_TRUE == pstPara->bThreadStart)
	{
   
		清零read_fds  +  放入VencFd[012]  +  select IO复用  对编码设备文件句柄VencFd[012]进行IO多路复用 找到就绪的文件句柄
		{
   
			1 查询编码通道状态。   HI_MPI_VENC_Query(i, &stStat); 编码码流buf中的数据 帧数 包数 余下待接收的帧数
			//2核对 核对当前帧的包数和编码buff中余下的帧数→若有0则?
			3 申请帧码流包结构体空间      malloc(sizeof(VENC_PACK_S) * stStat.u32CurPacks); 申请一包*包数的空间
			4 【获取编码码流】     HI_MPI_VENC_GetStream(i, &stStream, HI_TRUE);   →→→→→→→stStream
			5 保存,处理码流 SAMPLE_COMM_VENC_SaveH264 保存至文件
			67 释放编码码流   HI_MPI_VENC_ReleaseStream
		}
	}
	3  close save-file
}
【VENC_CHN_STAT_S stStat编码通道的状态结构体。---码流 buffer 剩余的 byte 数。码流 buffer 剩余的帧数。当前帧的码流包个数。剩余待接收的帧数,】
【每次从编码缓冲池中提取的】VENC_STREAM_S  stStream  帧码流类型结构体{
   帧码流包指针。 包数 码流序列号。 码流特征信息} 】


fifo实现借鉴:填充:【sample中链表是将pstStream中的每一包作为一个链表单元→→那么fifo也模仿 每一个包的内容的【指针和长度】做成一个数组元素12 】
发送:当读写指针指向同一位置表示没有东西号发送 否则调用VENC_SENT发送   然后清理并移动读指针

   printf("please press twice ENTER to exit this sample\n");//结束编码的契机
   getchar();
   getchar();

7 退出 将前一步中循环检测的一个变量设置为false--即venc停止
-------------------------------------------------------------------
//int main(入口在sample_venc.c) 根据传参case '0'在switch中选择一条分支→SAMPLE_VENC_1080P_CLASSIC   
//HI3518E内部的ISP单元是隶属于VI模块的。
//VI模块就包含3大部分:第一部分是和Sensor对接的部分,第二部分就是ISP,第三部分就是VI dev和channel
PAYLOAD_TYPE_E enPayLoad[3]= {
   PT_H264, PT_H264,PT_H264};//视频数据类型
PIC_SIZE_E enSize[3] = {
   PIC_HD1080, PIC_VGA,PIC_QVGA};;//默认的三路码流,后面根据实际sensor可能会改动
HI_U32 u32Profile = 0;

VB_CONF_S stVbConf;//缓冲池结构体
SAMPLE_VI_CONFIG_S stViConfig = {
   0};

VPSS_GRP VpssGrp;
VPSS_CHN VpssChn;
VPSS_GRP_ATTR_S stVpssGrpAttr;//定义 VPSS GROUP 属性
VPSS_CHN_ATTR_S stVpssChnAttr;//定义 VPSS Chn 静态属性
VPSS_CHN_MODE_S stVpssChnMode;//定义 VPSS Chn 模式

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;

step 1: init sys variable

定义视频缓存池属性结构体:

typedef struct hiVB_CONF_S
{
   
	HI_U32 u32MaxPoolCnt; //刺痛中缓冲池最大数量  如128?
	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;
计算缓冲池单帧大小:
enPicSize+制式→长宽→向上对齐 *系数  +头(←宏)
SAMPLE_COMM_SYS_GetPicSize(enNorm, enPicSize, &stSize);
{
   
	switch (enPicSize)
    {
   
     case PIC_HD720:   /* 1280 * 720 */
            pstSize->u32Width  = 1280;
            pstSize->u32Height = 720;
            break;
        case PIC_HD1080:  /* 1920 * 1080 */
            pstSize->u32Width  = 1920;
            pstSize->u32Height = 1080;
            break;
        case PIC_QCIF:
            pstSize->u32Width  = 176;
            pstSize->u32Height = (VIDEO_ENCODING_MODE_PAL==enNorm)?144:120;
            break;

			……
}

u32VbSize = (CEILING_2_POWER(stSize.u32Width, u32AlignWidth) * \
            CEILING_2_POWER(stSize.u32Height,u32AlignWidth) * \
           ((PIXEL_FORMAT_YUV_SEMIPLANAR_422 == enPixFmt)?2:1.5));
//宽高:向上对齐后成为u32AlignWidth的倍数 系数←像素格式如YUV420
    VB_PIC_HEADER_SIZE(stSize.u32Width, stSize.u32Height, enPixFmt, u32HeaderSize);
//宏:计算帧的头大小=如420:size = (VB_HEADER_STRIDE * (Height) * 3) >> 1;
    u32VbSize += u32HeaderSize;


【后面会填充通道012通道的VB】

在这里插入图片描述
是否压缩由VI通道参数决定

#define VB_PIC_BLK_SIZE(Width, Height, Type, size)\
    do{\
        unsigned int u32AlignWidth;\
        unsigned int u32AlignHeight;\
        unsigned int u32HeadSize;\
        u32AlignWidth = VB_ALIGN(Width, 16);\
        u32AlignHeight= VB_ALIGN(Height, 2);\
        u32HeadSize = VB_HEADER_STRIDE * u32AlignHeight;
        /* compress header stride 16 */\
        if (PIXEL_FORMAT_YUV_SEMIPLANAR_422 == Type)\
        {
   \
            size = (u32AlignWidth * u32AlignHeight + u32HeadSize) * 2;\
        }\
        else if (PIXEL_FORMAT_YUV_400 == Type)\
        {
   \
            size = (u32AlignWidth * u32AlignHeight + u32HeadSize);\
        }\
        else\
        {
   \
            size = ((u32AlignWidth * u32AlignHeight + u32HeadSize) * 3) >> 1;\
        }\
    }while(0)

step 2: mpp system init.

SAMPLE_COMM_SYS_Init(VB_CONF_S *pstVbConf)
{
   
	MPP_SYS_CONF_S stSysConf = {
   0};//MPP系统控制属性结构体--只有一个对齐参数
    HI_MPI_SYS_Exit();//去初始化 MPP 系统。
    HI_MPI_VB_Exit();//去初始化 MPP 视频缓存池。
    
    HI_MPI_VB_SetConf(pstVbConf);//设置 MPP 视频缓存池属性
    HI_MPI_VB_Init();//初始化 MPP 视频缓存池
    
    stSysConf.u32AlignWidth = SAMPLE_SYS_ALIGN_WIDTH;//填充对齐参数
    HI_MPI_SYS_SetConf(&stSysConf);//配置系统控制参数(只有一个对齐参数)
    HI_MPI_SYS_Init();//HI_MPI_SYS_Init
    //前面几个函数如果返回有问题→函数回HI_FAILURE
    return HI_SUCCESS;
}

MPP 系统控制属性结构体(其实只有一个对齐参数)

typedef struct hiMPP_SYS_CONF_S
{
   
	// stride of picture buffer must be aligned with this value.
	//这个对齐参数不能是1,必须是16的倍数 范围[1,1024]
	HI_U32 u32AlignWidth;//对齐参数
}MPP_SYS_CONF_S;

step 3: start vi dev & chn to capture

设置VI配置结构体(samplede的)+开启VI(sensor写入+运行ISP)

stViConfig.enViMode   = SENSOR_TYPE;//配置文件中定义的宏 摄像头信号AR0130=APTINA_AR0130_DC_720P_30FPS
stViConfig.enRotate   = ROTATE_NONE;//枚举-不旋转
stViConfig.enNorm     = VIDEO_ENCODING_MODE_AUTO;//视频制式:PAL、NTSC、AUTO暂时不支持
stViConfig.enViChnSet = VI_CHN_SET_NORMAL;//枚举-既不镜像也不翻转
stViConfig.enWDRMode  = WDR_MODE_NONE;//WDR宽动态 NONE不支持

SAMPLE_COMM_VI_StartVi(SAMPLE_VI_CONFIG_S* pstViConfig)
enViMode类型→不同来源sensor或者硬盘(这里选择sensor来源)
				↓							↓
SAMPLE_COMM_VI_StartIspAndVi(SAMPLE_VI_CONFIG_S* pstViConfig)
{
   
step 1: 配置mipi 
	 SAMPLE_COMM_VI_StartMIPI(pstViConfig);
	 
step 2: 配置sensor and ISP (include WDR mode)
	 SAMPLE_COMM_ISP_Init
	 {
   	
 		sensor_register_callback //* 1. 注册一个sensor回调
		HI_MPI_AE_Register  //* 2. 注册isp内部的ae单元-自动曝光
		HI_MPI_AWB_Register	//* 3. 自动白平衡
		HI_MPI_AF_Register  //* 4. 自动对焦
		HI_MPI_ISP_MemInit	//* 5. 给isp单元分配必要的内存
		HI_MPI_ISP_SetWDRMode //* 6. 设置宽动态相关属性
		HI_MPI_ISP_SetPubAttr 	// 7. isp set pub attributes 
		//根据SENSOR_TYPEswitch确定结构体的内容(颜色排序BAYER_RGGB、GRGB、BGGR 帧率 起始xy坐标 长宽)再写到IPS内部单元
		HI_MPI_ISP_Init	//* 8. ISP初始化
	}
	
step 3: run isp thread
	SAMPLE_COMM_ISP_Run
				pthread_create(&gs_IspPid, &attr, (void* (*)(void*))Test_ISP_Run, NULL)
					Test_ISP_Run
						HI_MPI_ISP_Run
						  
step 4 : config & start vicap dev
	SAMPLE_COMM_VI_StartDev
	//根据sensor型号填充stViDevAttr结构体(mamcpy结构体+手动赋值0,0,长宽即分辨率)	
		HI_MPI_VI_SetDevAttr(ViDev, &stViDevAttr);//将stViDevAttr的值设置进去   这里吧参数结构体写进去(前面写好参数结构体)
			HI_MPI_ISP_GetWDRMode
			HI_MPI_VI_SetWDRAttr
			HI_MPI_VI_EnableDev//启动Dev
			
Step 5: config & start vicap chn (max 1)
	SAMPLE_COMM_VI_StartChn
		HI_MPI_VI_SetChnAttr
		HI_MPI_VI_SetRotate
		HI_MPI_VI_EnableChn//打开	
//step45 都是设置一些参数再启动 只有一个dev一个chn	
}

1.定义VENC编码通道属性结构体:
载荷为H264时使用的编码通道属性结构体:

typedef struct hiVENC_ATTR_H264_S
{
   
    HI_U32  u32MaxPicWidth;/*编码图像最大高度 */
    HI_U32  u32MaxPicHeight; /*编码图像最大高度 */
    //必须是 MIN_ALIGN 的整数倍静态属性。
    HI_U32  u32PicWidth;/*编码图像宽度 必须是 MIN_ALIGN 的整数倍*/
    HI_U32  u32PicHeight;/*编码图像高度 必须是 MIN_ALIGN 的整数倍*/  

    HI_U32  u32BufSize;/*码流buffer大小*/
//推荐值:一幅最大编码图像大小。推荐值为 u32MaxPicWidth × u32MaxPicHeight ×1.5 byte
    HI_U32  u32Profile; /*编码的等级  */ 
    //0: baseline; 1:MP; 2:HP; 3: SVC-T [0,3];     
        
    HI_
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值