HEVC学习(二十二) —— 熵编码之三
来源:互联网 发布:手机编码软件 编辑:程序博客网 时间:2024/05/29 11:17
在继续介绍CABAC之前,先穿插进另外几种相对而言较为简单的熵编码方式。下图是截取自draft 7.3.2.1的关于VPS(Video Parameter Set)的句法元素描述:
关注表格中"Descriptor”这一栏,当中的描述符有u,ue,分别表示无符号整型、无符号整型0阶指数哥伦布编码方式,可以在HM中找到与表格相对应的一段代码:
Void TEncCavlc::codeVPS( TComVPS* pcVPS ){ WRITE_CODE( pcVPS->getVPSId(), 4, "video_parameter_set_id" ); WRITE_FLAG( pcVPS->getTemporalNestingFlag(), "vps_temporal_id_nesting_flag" );#if VPS_REARRANGE WRITE_CODE( 3, 2, "vps_reserved_three_2bits" );#else WRITE_CODE( 0, 2, "vps_reserved_zero_2bits" );#endif WRITE_CODE( 0, 6, "vps_reserved_zero_6bits" ); WRITE_CODE( pcVPS->getMaxTLayers() - 1, 3, "vps_max_sub_layers_minus1" );#if VPS_REARRANGE WRITE_CODE( 0xffff, 16, "vps_reserved_ffff_16bits" ); codePTL( pcVPS->getPTL(), true, pcVPS->getMaxTLayers() - 1 );#else codePTL( pcVPS->getPTL(), true, pcVPS->getMaxTLayers() - 1 ); WRITE_CODE( 0, 12, "vps_reserved_zero_12bits" );#endif#if SIGNAL_BITRATE_PICRATE_IN_VPS codeBitratePicRateInfo(pcVPS->getBitratePicrateInfo(), 0, pcVPS->getMaxTLayers() - 1);#endif #if HLS_ADD_SUBLAYER_ORDERING_INFO_PRESENT_FLAG const Bool subLayerOrderingInfoPresentFlag = 1; WRITE_FLAG(subLayerOrderingInfoPresentFlag, "vps_sub_layer_ordering_info_present_flag");#endif /* HLS_ADD_SUBLAYER_ORDERING_INFO_PRESENT_FLAG */ for(UInt i=0; i <= pcVPS->getMaxTLayers()-1; i++) { WRITE_UVLC( pcVPS->getMaxDecPicBuffering(i), "vps_max_dec_pic_buffering[i]" ); WRITE_UVLC( pcVPS->getNumReorderPics(i), "vps_num_reorder_pics[i]" ); WRITE_UVLC( pcVPS->getMaxLatencyIncrease(i), "vps_max_latency_increase[i]" );#if HLS_ADD_SUBLAYER_ORDERING_INFO_PRESENT_FLAG if (!subLayerOrderingInfoPresentFlag) { break; }#endif /* HLS_ADD_SUBLAYER_ORDERING_INFO_PRESENT_FLAG */ }#if VPS_OPERATING_POINT assert( pcVPS->getNumHrdParameters() <= MAX_VPS_NUM_HRD_PARAMETERS ); assert( pcVPS->getMaxNuhReservedZeroLayerId() < MAX_VPS_NUH_RESERVED_ZERO_LAYER_ID_PLUS1 ); WRITE_UVLC( pcVPS->getNumHrdParameters(), "vps_num_hrd_parameters" ); WRITE_CODE( pcVPS->getMaxNuhReservedZeroLayerId(), 6, "vps_max_nuh_reserved_zero_layer_id" ); for( UInt opIdx = 0; opIdx < pcVPS->getNumHrdParameters(); opIdx++ ) { if( opIdx > 0 ) { // operation_point_layer_id_flag( opIdx ) for( UInt i = 0; i <= pcVPS->getMaxNuhReservedZeroLayerId(); i++ ) { WRITE_FLAG( pcVPS->getOpLayerIdIncludedFlag( opIdx, i ), "op_layer_id_included_flag[opIdx][i]" ); } } // TODO: add hrd_parameters() }#else WRITE_UVLC( 0, "vps_num_hrd_parameters" ); // hrd_parameters#endif WRITE_FLAG( 0, "vps_extension_flag" ); //future extensions here.. return;}
两者相对照之后,可以发现,WRITE_CODE对应的就是表格中的"u",而WRITE_UVLC对应的就是表格中的"ue"
#define WRITE_CODE( value, length, name) xWriteCode ( value, length )#define WRITE_UVLC( value, name) xWriteUvlc ( value )
WRITE_CODE和WRITE_UVLC都是宏,实际调用的是xWriteCode和xWriteUvlc,宏在这个地方的主要作用是为在代码中处理句法元素的名字提供方便,一方面提高代码的可读性,另一方面,这个句法元素的命名对实际编码并没用处,将其作为函数输入参数不合理。而定义了宏后,则巧妙地解决了这一矛盾。
不罗嗦,直接分析这两个函数:
Void SyntaxElementWriter::xWriteCode ( UInt uiCode, UInt uiLength ){ assert ( uiLength > 0 ); m_pcBitIf->write( uiCode, uiLength ); //!< 将uiCode以二进制的方式写入m_fifo中(长度为uiLength)}Void SyntaxElementWriter::xWriteUvlc ( UInt uiCode ){ UInt uiLength = 1; UInt uiTemp = ++uiCode; assert ( uiTemp ); while( 1 != uiTemp ) { uiTemp >>= 1; uiLength += 2; } // Take care of cases where uiLength > 32 m_pcBitIf->write( 0, uiLength >> 1); m_pcBitIf->write( uiCode, (uiLength+1) >> 1);}
第一个函数比较简单,就不分析了,对于第二个函数,分析它的最好方法就是代入具体值进行调试。比如,当uiCode=0时,经过分析可得到写入m_fifo的数据为1,当uiCode=1时,可得到写入m_fifo的数据为010,当uiCode=2时,可得到写入m_fifo的数据为011,... ... 以此类推。结果可以参考draft中的Table 9-2,如下所示:
与ue(v)相对应的,还有se(v),是带符号的指数哥伦布编码,其相关代码如下所示:
#define WRITE_SVLC( value, name) xWriteSvlc ( value )
Void SyntaxElementWriter::xWriteSvlc ( Int iCode ){ UInt uiCode; uiCode = xConvertToUInt( iCode ); xWriteUvlc( uiCode );}
UInt xConvertToUInt ( Int iValue ) { return ( iValue <= 0) ? -iValue<<1 : (iValue<<1)-1; }
xWriteSvlc先调用xConvertToUInt将带符号的iCode转换为无符号的uiCode,再调用xWriteSvlc完成编码工作,从带符号到无符号的转换过程可以参考draft 的 Table 9-3,如下图所示:
- HEVC学习(二十二) —— 熵编码之三
- HEVC学习(二十一) —— 熵编码之二
- HEVC学习(二十九) —— 量化之三
- HEVC学习(二十) —— 熵编码之一
- HEVC学习(二十三) —— 熵编码之四
- HEVC学习(二十四) —— 熵编码之五
- HEVC学习(二十七) —— 变换编码之二
- Duanxx的HEVC学习(三)HEVC编码框架(二)帧内预测
- HEVC学习(二十八) —— 量化之二
- [HEVC] HEVC学习(五) —— 帧内预测系列之三
- [HEVC] HEVC学习(四) —— 帧内预测系列之二
- HEVC学习(十二) —— CU的最终划分
- HEVC学习(十二) —— CU的最终划分
- HEVC学习(十二) —— CU的最终划分
- HEVC学习(十二) —— CU的最终划分
- HEVC学习(十二) —— CU的最终划分
- HEVC学习(十二) —— CU的最终划分
- HEVC学习(十二) —— CU的最终划分
- C#[WinForm]实现自动更新(Auto Update)
- Sublime text 2 无需注册码的破解方法,只改2个字节
- 动态(程序运行时)生成枚举类型
- linux 下更改swap分区
- android JNI 学习笔记
- HEVC学习(二十二) —— 熵编码之三
- 读书笔记--基本排序(选择、插入、冒泡、希尔)
- linux top命令
- C++ 电子书
- Spring(三) bean注入
- Linux 的多线程编程的高效开发经验
- 关于iOS系统中通讯录的访问
- Java Socket编程(3)初识TCP Socket
- java菜鸟学习数据结构——准备篇1(内存分配原理)