2.3 H264数据封装RTP包

前面已经说过,整个程序是利用多线程的生产者消费者模式,线程SAMPLE_COMM_VENC_GetVencStreamProc产生视频数据,不同于前面的1.1 海思3518 H264编码,这次不是将视频数据保存在本地文件中,而是直接将数据放到一个环形缓冲区里让消费者取走通过网络发送出去。视频数据其实就是一些普通的char数据,有些数据如果太小用ascii码会显示不出来,如ACK是0x06,用ascii显示不出来,因为网络设备的多样性,一些网络设备如路由器交换机会将一些不能用ascii码显示出来的数据会过滤掉,直接丢弃,所以对H264而言,SPS、PPS这样的重要帧(H264少了这些数据就不能解码,显示不出图片),如果直接按照原样发送出去,很可能有数据被过滤掉了,客户端接收到少了数据的SPS,PPS帧,自然也就不能解码,所以必须要采用别的方法再编码一次,让网络设备不过滤,然后在客户端再解码就行了,一般业内最常用的是base64编码。base64编码就是将A~Z,a~z,0~9,+,/总共64个字符(网络设备不会过滤这64个字符)做成一个base64表,然后将SPS、PPS每3个数据总计24位分成4个6位的数据,每6位数据不会大于64,对应base64表中的一个字符,这样就可以将sps、pps安全发送出去了。同样,先下载工程文件和源代码:Hi3518+RTSP,还是结合代码,线程SAMPLE_COMM_VENC_GetVencStreamProc通过select多路复用IO来取得数据,然后不保存,直接调用HisiPutH264DataToBuffer函数将数据发送出去(我在代码里定义了SAVEH264_TO_LOCAL宏,可以决定是否保存到本地,如果保存到本地,可以将H264裸流数据保存下来,与后面的抓包数据比较,有利于发现是怎么将H264打包成RTP包的)。

#if SAVEH264_TO_LOCAL
                    s32Ret = SAMPLE_COMM_VENC_SaveStream(enPayLoadType[i], pFile[i], &stStream);
                    if (HI_SUCCESS != s32Ret)
                    {
                       free(stStream.pstPack);
                        stStream.pstPack = NULL;
                        SAMPLE_PRT("save stream failed!\n");
                        break;
                    }
		#endif
                   HisiPutH264DataToBuffer(&stStream);

HisiPutH264DataToBuffer函数代码如下:

/**************************************************************************************************
**将H264流数据放到ringfifo[iput].buffer里以便schedule_do线程从ringfifo[iput].buffer里取出数据发送出去
**同是在DESCRIBE步骤中会对SPS,PPS编码发送给客户端,后面好像就只编码但没有发送出去
**
**************************************************************************************************/
HI_S32 HisiPutH264DataToBuffer(VENC_STREAM_S *pstStream)
{
	HI_S32 i,j;
	HI_S32 len=0,off=0,len2=2;
	unsigned char *pstr;
	int iframe=0;
	for (i = 0; i < pstStream->u32PackCount; i++)
	{
		len+=pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset;
	}

	int testlen=0;
    if(n<NMAX)
    {
		for (i = 0; i < pstStream->u32PackCount; i++)
		{
			
			memcpy(ringfifo[iput].buffer+off,pstStream->pstPack[i].pu8Addr+pstStream->pstPack[i].u32Offset,pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset);
			//printf("\nff=%x",pstStream->pstPack[i].u32Offset);
			pstr=pstStream->pstPack[i].pu8Addr+pstStream->pstPack[i].u32Offset;//计算当前PACK的有效数据的首地址
			/*
			if(pstr[4]==0x68)
			{
				printf("\nx=%p",ringfifo[iput].buffer+off);
				for(testlen=0;testlen<pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset;testlen++)
					printf(" %x ",*(ringfifo[iput].buffer+off+testlen));
			}
			*/
			//pstr=pstStream->pstPack[i].pu8Addr+pstStream->pstPack[i].u32Offset;//这一行一定要,要不然后面的if判断pstr[4]
			//如果在这里不要,pstr[4]会不存在,从而提示段错误
/*
			if(pstr[4]==0x67)
			{
				printf("a=%d,%p ",*(ringfifo[iput].buffer+off),ringfifo[iput].buffer+off);
			}
			*/
			off+=pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset;//计算下个PACK存放到ring里的首地址
			//上面那个off计算应该移到下面//aaaaaaaaaaaaaa处???????????????????????????????
			//pstr=pstStream->pstPack[i].pu8Addr+pstStream->pstPack[i].u32Offset;//计算当前PACK的有效数据的首地址

			if(pstr[4]==0x67)
			{//使用 base64 对 data 进行编码,设计此种编码是为了使二进制数据可以通过
			//非纯 8-bit 的传输层传输,例如电子邮件的主体
			//在网络上基本上是非纯8位传输,所以要将数据在服务器编码为
			//base64(非8位的,6位的),然后由客户端解码
			//将H264数据用base64编码然后才发送
				UpdateSps(ringfifo[iput].buffer+off,9);
				//printf("b=%d,%p ",*(ringfifo[iput].buffer+off),ringfifo[iput].buffer+off);
				iframe=1;
			}
			if(pstr[4]==0x68)
			{
				//printf("\ny=%p",ringfifo[iput].buffer+off);
				//for(testlen=0;testlen<pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset;testlen++)
				//	printf(" %x ",*(ringfifo[iput].buffer+off+testlen));
				UpdatePps(ringfifo[iput].buffer+off,4);
			}
			//off+=pstStream->pstPack[i].u32Len-pstSt
  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值