js 实现sps 解析获取视频分辨率

处理H5 流媒体时,有时需要根据SPS 获取视频宽、高,网上的大多是c/c++,这里我用js 实现类似功能。


function ceil(val)
{
	return Math.ceil(val);
}

//获取buf 的前n个bit组成的值
function u(bitCount, input)
{
	let ret = 0;
	
	for( var i = 0;i< bitCount;i++)
	{
		ret <<= 1;
		
		
		if (input.data[Math.floor(input.index / 8)] & (0x80 >> (input.index % 8)))
		{
			ret += 1;
		}
		
		input.index++;
	}
	
	return ret;
}

/*无符号指数哥伦布编码(UE)
*哥伦布编码的码字code_word由三部分组成:code_word = [M个0] + [1] + [Info]
*其中,Info是一个携带信息的M位数据,每个哥伦布码的长度为(2M+1)位,每个码字都可由code_num产生。
*根据码字code_word解码出code_num值的过程如下:
*1. 首先读入M位以"1"为结尾的0;
*2. 根据得到的M,读入接下来的M位Info数据;
*3. 根据这个公式得到计算结果code_num = Info – 1 + 2M
*/

function ue(input, len)
{
	let zeroNum = 0;
	while(input.index < len * 8)
	{
		if(input.data[Math.floor(input.index/8)] & (0x80 >> (input.index %8)))//遇到1则停止,统计0的个数
		{
			break;
		}
		
		zeroNum++;
		input.index++;
	}
	
	input.index++;
	
	let ret = 0;
	//计算
	for(i = 0;i < zeroNum;i++)
	{
		ret <<= 1;
		if(input.data[Math.floor(input.index/8)] & (0x80 >> input.index %8))
		{
			ret += 1;
		}
		
		input.index++;
	}
	
	return (1<< zeroNum) - 1 + ret;
}

//有符号哥伦布编码
function se(input, len)
{
	let ueVal = ue(input, len);
	let k = ueVal;
	let nValue = ceil(k/2);
	
	if(ueVal %2 == 0)
		nValue = -nValue;
	return nValue;
}


function spsParser(buf)
{
	let startBitIndex = 0;

	buf = buf.slice(4);//去除00 00 00 01竞争码
	let len = buf.length;
	
	//输入参数
	let input = {	
		data:buf,
		index:startBitIndex
	};
	
	
	let forbidden_zero_bit = u(1, input);
	let nal_ref_idc = u(2, input);
	let nal_unit_type = u(5, input);
	let chroma_format_idc;
	
	if(nal_unit_type == 7) 
	{
		let profile_idc = u(8, input);
		let constraint_set0_flag = u(1, input);
		let constraint_set1_flag = u(1, input);
		let constraint_set2_flag = u(1, input);
		let constraint_set3_flag = u(1, input);	
		let constraint_set4_flag = u(1, input);
		let constraint_set5_flag = u(1, input);
		
		let reserved_zero_2bits = u(2, input);
		let level_idc = u(8, input);
		let seq_parameter_set_id = ue(input, len);
		
		if(profile_idc == 100 | profile_idc == 110 || profile_idc == 122 || profile_idc == 144 )
		{				
			chroma_format_idc = ue(input, len);

			if(chroma_format_idc == 3)
			{
				var residual_colour_transform_flag = u(1, input);
			}
					
			let bit_depth_luma_minus8 = ue(input, len);
			let bit_depth_chroma_minus8 = ue(input, len);
			let qpprime_y_zero_transform_bypass_flag = u(1, input);
			let seq_scaling_matrix_present_flag = u(1, input);
			
			let seq_scaling_list_present_flag = new Uint8Array(8);
			if (seq_scaling_matrix_present_flag)
			{
				for (var i = 0; i < 8; i++) 
				{
					seq_scaling_list_present_flag[i] = u(1, input);
				}
			}				
		}
		
		
		let log2_max_frame_num_minus4 = ue(input, len);
		let pic_order_cnt_type = ue(input, len);
		
		if (pic_order_cnt_type == 0)
			log2_max_pic_order_cnt_lsb_minus4 = ue(input, len);
		
		else if (pic_order_cnt_type == 1)
		{
			let delta_pic_order_always_zero_flag = u(1, input);
			let offset_for_non_ref_pic = se(input, len);
			let offset_for_top_to_bottom_field = se(input, len);
			let num_ref_frames_in_pic_order_cnt_cycle = ue(input, len);

			let offset_for_ref_frame = new Uint8Array[num_ref_frames_in_pic_order_cnt_cycle];
			
			for ( var i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++)
				offset_for_ref_frame[i] = se(input, len);
		}
		
		let num_ref_frames = ue(input, len);
		let gaps_in_frame_num_value_allowed_flag = u(1, input);
		let pic_width_in_mbs_minus1 = ue(input, len);
		let pic_height_in_map_units_minus1 = ue(input, len);

		let width = (pic_width_in_mbs_minus1 + 1) * 16;//可能还要进行裁剪处理
		let height = (pic_height_in_map_units_minus1 + 1) * 16;
		
		let frame_mbs_only_flag = u(1, input);
		
		if(!frame_mbs_only_flag)
		{
			u(1, input);
		}
		
		let direct_8x8_inference_flag = u(1, input);
		let frame_cropping_flag = u(1, input);
		
		if(frame_cropping_flag)
		{
			let frame_crop_left_offset = ue(input, len);
            let frame_crop_right_offset = ue(input, len);
            let frame_crop_top_offset = ue(input, len);
            let frame_crop_bottom_offset = ue(input, len);
			
			let crop_unit_x = 1;
            let crop_unit_y = 2 - frame_mbs_only_flag;
			
            if (chroma_format_idc == 1) {   //4:2:0
                crop_unit_x = 2;
                crop_unit_y = 2 * (2 - frame_mbs_only_flag);
            }
            else if (chroma_format_idc == 2) {    //4:2:2
                crop_unit_x = 2;
                crop_unit_y = 2 - frame_mbs_only_flag;
            }
			
			
			width -= crop_unit_x * (frame_crop_left_offset + frame_crop_right_offset);
            height -= crop_unit_y * (frame_crop_top_offset + frame_crop_bottom_offset);
		}
		
		return {
			width:width,
			height:height
		}
		
	}
}

function test()
{
	
	var spsArry = new Array(0x00, 0x00, 0x00, 0x01, 0x27, 0x64, 0x00,0x1F, 0xAC,0x1A, 0xD0, 0x2E,0x0A, 0x3C, 0xBC,0x20, 0x00, 0x00,0x03 ,0x00, 0x20, 0x00, 0x00,0x0C, 0x81, 0xE2, 0x0F,0x50);
	let result = spsParser(spsArry);
}

test();

参考链接:

https://blog.csdn.net/lizhijian21/article/details/80982403

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值