SDP的fmtp部分

之前做的SDP对于h264编码的视频没有做"a=fmtp"字段的解析,今天加上,主要是为了解析出视频的宽高信息。


RFC3984的8.2节对field做了介绍,这里只介绍sprop-parameter-sets字段的解码方法,因为我的主要目的是解析出视频宽高信息


该字段用BASE-64编码,因此,首先解码BASE-64,这里给出解码方法:


long CBase64::Decode(const char *pSrc, long srcLen, unsigned char *pDest, long destLen)
{
	int i = 0;
	int iCnt = 0;

	unsigned char * p = pDest;

	for (i=0; i<srcLen; i++)
	{
		if (pSrc[i] > 127)
		{
			continue;
		}

		if (pSrc[i] == '=')
		{
			return p-pDest+1;
		}

		unsigned char a = Base64IdxTab[pSrc[i]];
		if (a == 255)
		{
			continue;
		}

		switch (iCnt)
		{
		case 0:
			{
				*p = a << 2;
				iCnt++;
			}
			break;

		case 1:
			{
				*p++ |= a >> 4;
				*p = a << 4;
				iCnt++;
			}
			break;

		case 2:
			{
				*p++ |= a >> 2;
				*p = a << 6;
				iCnt++;
			}
			break;

		case 3:
			{
				*p++ |= a;
				iCnt = 0;
			}
			break;
		} 
	}

	*p = 0x00;
	return p-pDest;
}

其中返回值为解出的目标串的长度



然后,针对接触的字符串,它的第一个字节是个NUL头,我们希望它的NAL_TYPE为7,也就是序列参数集(sps)

针对该参数集,对照h.264文档的7.3.2.1对语法,我们希望解出pic_width_in_mbs_minus1字段和pic_height_in_map_units_minus1字段


这里遇到了一个问题,因为它是指数哥伦布编码,因此又需要解码:

int GolombDecode(bool *pBinaryArray, int &Des)
{
	if (pBinaryArray == NULL)
	{
		return -1;
	}
	
	int iter = 0;
	int NumOfZero = 0;
	int M_bit = 0;
	int INFO = 0;
	double result;

	//找到第一个1
	while(pBinaryArray[iter++] == 0)
	{
		NumOfZero++;
	}
	for (int i=NumOfZero-1; i>=0; i--)
	{
		INFO += pBinaryArray[iter++]<<i;
	}
	result = pow((double)2, (double)NumOfZero) + INFO - 1;
	Des = result;
 	
	return iter;
}
其中,返回值是二进制字符串的偏移地址


因为指数哥伦布编码不定长的特性,我们需要解出整个SPS(依据ITU-T H264  7.3.2.1.1):

int ParseSPS(unsigned char *pSrc, unsigned long SrcLen, unsigned long &VideoWidth, unsigned long &VideoHeight)
{
	int ret = 0;
	unsigned long offset = 0;
	bool *pBinaryArray = new bool[SrcLen*8];
	unsigned long iter = 0;
	unsigned char mask = 0x80;
	for (int i=0; i<SrcLen; i++)
	{
		mask = 0x80;
		for (int j=0; j<8; j++)
		{
			if (pSrc[i] & (mask >> j))
			{
				pBinaryArray[iter] = 1;
			}
			else
			{
				pBinaryArray[iter] = 0;
			}
			iter++;
		}
	}
	iter = 0;

	unsigned char profile_idc = *pSrc;
	int seq_parameter_set_id;
	offset = 24;
	ret = GolombDecode(pBinaryArray+offset, seq_parameter_set_id);
	offset += ret;
	if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144)
	{
		int chroma_format_idc;
		ret = GolombDecode(pBinaryArray+offset, chroma_format_idc);
		offset += ret;
		if(chroma_format_idc == 3)
		{
			offset += 1;
		}
		int bit_depth_luma_minus8, bit_depth_chroma_minus8;
		ret = GolombDecode(pBinaryArray+offset, bit_depth_luma_minus8);
		offset += ret;
		ret = GolombDecode(pBinaryArray+offset, bit_depth_chroma_minus8);
		offset += ret;
		offset += 2;
		bool seq_scaling_matrix_present_flag = pBinaryArray[offset];
		if (seq_scaling_matrix_present_flag)
		{
			offset += 1;
		}
	}
	int log2_max_frame_num_minus4, pic_order_cnt_type;
	ret = GolombDecode(pBinaryArray+offset, log2_max_frame_num_minus4);
	offset += ret;
	ret = GolombDecode(pBinaryArray+offset, pic_order_cnt_type);
	offset += ret;
	if (pic_order_cnt_type == 0)
	{
		int log2_max_pic_order_cnt_lsb_minus4;
		ret = GolombDecode(pBinaryArray+offset, pic_order_cnt_type);
		offset += ret;
	}
	else if (pic_order_cnt_type == 1)
	{
		offset += 1;
		int offset_for_non_ref_pic, offset_for_top_to_bottom_field, num_ref_frames_in_pic_order_cnt_cycle, offset_for_ref_frame;
		ret = GolombDecode(pBinaryArray+offset, offset_for_non_ref_pic);
		offset += ret;
		ret = GolombDecode(pBinaryArray+offset, offset_for_top_to_bottom_field);
		offset += ret;
		ret = GolombDecode(pBinaryArray+offset, num_ref_frames_in_pic_order_cnt_cycle);
		offset += ret;
		for (int i=0; i<num_ref_frames_in_pic_order_cnt_cycle ;i++)
		{
			ret = GolombDecode(pBinaryArray+offset, offset_for_ref_frame);
			offset += ret;
		}
	}
	int num_ref_frames;
	ret = GolombDecode(pBinaryArray+offset, num_ref_frames);
	offset += ret;
	offset += 1;
	int pic_width_in_mbs_minus1, pic_height_in_map_units_minus1;
	ret = GolombDecode(pBinaryArray+offset, pic_width_in_mbs_minus1);
	offset += ret;
	ret = GolombDecode(pBinaryArray+offset, pic_height_in_map_units_minus1);
	offset += ret;

	VideoWidth = (pic_width_in_mbs_minus1 + 1) * 16;
	VideoHeight = (pic_height_in_map_units_minus1 + 1) * 16;

	delete []pBinaryArray;
	pBinaryArray = NULL;
	return 0;
}

这样,就完成了目标,得到了视频信息的长和宽


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值