H.264熵解码详细过程


1、三种熵编码形式

熵编码是无损压缩编码方法,它生成的码流可以经熵解码无失真地恢复出数据。
对应熵编码方案,在H.264标准中也有3种熵解码方案: 指数哥伦布解码,CAVLC解码和CABAC解码。在标准中通过描述子(Descriptor)的形式来说明一个语法元素熵解码的方法。对于片层以上的语法元素有定长解码和变长解码方案;对于片层以下的语法元素,当entropy_coding_mode_flag为0时使用指数哥伦布和CAVLC解码,为1时使用CABAC解码。

2、CAVLC解析过程

//coeffLevel存放着解析后的系数
residual_block_cavlc(int coeffLevel, int maxNumCoeff ) 
{
	for( i = 0; i < maxNumCoeff; i++ )
		coeffLevel[ i ] = 0;
	
	int coeff_token = ce(v);	//根据(标准表9-5)计算出非零系数数目(TotalCoeff)、拖尾系数数目(TrailingOnes)

	if( TotalCoeff( coeff_token ) > 0 )		//非零系数的数目 > 0 
	{
		int suffixLength;				//后缀长度
		if( TotalCoeff( coeff_token ) > 10 && TrailingOnes( coeff_token ) < 3 )
			suffixLength = 1;	
		else
			suffixLength = 0;
		
		for( i = 0; i < TotalCoeff( coeff_token ); i++ )
		{
			if( i < TrailingOnes( coeff_token ) ) 	//解码拖尾系数的符号
			{
				int trailing_ones_sign_flag = u(1);
				level[ i ] = 1 – 2 * trailing_ones_sign_flag;
			}
			else 													//解码拖尾系数之外的非零系数的幅值(Levels)
			{
				int level_prefix = ce(v);		//从当前位置不断读取0,直至读到1为止,则0的个数就是level_prefix的值(标准表9-6)
				int levelCode = ( Min( 15,level_prefix ) << suffixLength );
				
				if( suffixLength > 0 || level_prefix >= 14 ) 
				{
					int level_suffix = u(v);	//读入v位并解释成无符号整数
					levelCode += level_suffix;
				}
				
				if( level_prefix >= 15 && suffixLength == 0 )
					levelCode += 15;
				if( level_prefix > = 16 )
					levelCode += ( 1 << ( level_prefix – 3 ) ) – 4096;
				
				if( i == TrailingOnes( coeff_token ) && TrailingOnes( coeff_token ) < 3 )
					levelCode += 2;
				
				//将无符号的levelCode转换成有符号的level
				if( levelCode % 2 == 0 )
					level[ i ] = ( levelCode + 2 ) >> 1;
				else
					level[ i ] = ( -1*levelCode – 1 ) >> 1;

				//更新suffixLength,隐含了上下文自适应过程				
				if( suffixLength == 0 )
					suffixLength = 1;
				if( Abs( level[ i ] ) > ( 3 << ( suffixLength – 1 ) ) && suffixLength < 6 )
					suffixLength++;
			}

			int zerosLeft;
			if( TotalCoeff( coeff_token ) < maxNumCoeff ) 
			{
				int total_zeros = ce(v);	//系数中0的总个数(标准表9-7,9-8,9-9)
				zerosLeft = total_zeros;
			} 
			else
				zerosLeft = 0;
			
			for( i = 0; i < TotalCoeff( coeff_token ) – 1; i++ ) 
			{
				if( zerosLeft > 0 ) 
				{
					int run_before = ce(v);	//解码非零系数前零的个数(标准表9-10)
					run[ i ] = run_before;
				} else
					run[ i ] = 0;
				
				zerosLeft = zerosLeft – run[ i ];
			}			
			run[ TotalCoeff( coeff_token ) – 1 ] = zerosLeft;	//run[i]记录了第i个非零系数前0的个数

			int coeffNum = -1;
			for( i = TotalCoeff( coeff_token ) – 1; i >= 0; i--) 
			{
				coeffNum += run[ i ] + 1
				coeffLevel[ coeffNum ] = level[ i ];
			}
		}
	}
}


K阶指数哥伦布编码

在H.264中,使用CABAC需要进行二值化处理,而指数哥伦布编码就是CABAC的一种二值化处理的方法。k阶指数哥伦布编解码具体过程如下:

**A、编码过程:**假设待编码数字为CodeNum(必须非负整数)

指数哥伦布编码后的形式为[MZeors][1][Info],MZero表示M个0。

1、将CodeNum以二进制形式表示(若不足k位,前面补0),去掉后面k位(若刚好是k位,去掉k位后得0),将结果(数值)加1,得到二进制数T1;

2、M为二进制数T1的二进制位数减一;

3、然后将第一步中舍去的k位接到T1结尾,就得到[1][Info]。

设[Info]的二进制位数为I,编码过程也可以如下描述:

[1 Info] 是CodeNum+2^k的二进制表示,MZeros中0的个数M = I - k。

于是就有总的编码长度CodeLen = M + 1 + I =2M+k+1。

B、解码过程:

1、读入连续0,连续0的个数就是M;

2、计算CodeLen = 2M+k+1,得到[1 Info]的位数是 I=CodeLen - M =M+K+1;

3、读入I位二进制码字,转换成10进制,假设为W。由W = CodeNum + 2^k,得CodeNum = W-2^K。

C、示例:

对于 k =0时:CodeNum=3。
  编码如下:

二进制表示为11,去掉k=0位后加1得100;

所以M=2;

所以编码后结果为[MZeros][1][Info] = [MZeros][1 Info] = 00100

解码如下:

读入连续2个0,所以M=2;CodeLen=2M+1+k=5;所以需要再读入3个码流100,[1 Info]就是100,转成十进制结果W为4,所以CodeNum = W-2^K=4-1=3;

同样对于k=0,CodeNum=6时,编码为:00111;

同样对于k=3,CodeNum=3时,编码为:1011;

同样对于k=3,CodeNum=6时,编码为:1110;

同样对于k=3,CodeNum=10时,编码为:010010;
这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值