您的位置:首页 > 其它

HEVC解码器HM源码阅读(四)解析参数集

2017-05-02 21:14 316 查看

解析视频参数集VPS

    如果NALU的装的是VPS,那么需要从NALU中把VPS解析出来。VPS包含了全局使用的一些信息,包含Profile、Level、Tier、时域层信息、TimingInfo、HRD等。

解析VPS的入口函数

    1、创建VPS对象

    2、解析VPS

    3、把VPS放入参数集管理器中

Void TDecTop::xDecodeVPS()
{
TComVPS* vps = new TComVPS();

// 解析vps
m_cEntropyDecoder.decodeVPS( vps );

// 把vps放入参数集管理器中
m_parameterSetManagerDecoder.storePrefetchedVPS(vps);
}


解析VPS

    按照顺序依次解码VPS中的语法元素,不同的语法元素使用的编解码方法可能不同。另外请注意,VPS、SPS、PPS等参数集使用cavlc进行熵编码/解码,视频数据使用CABAC进行熵编码/解码

Void TDecCavlc::parseVPS(TComVPS* pcVPS)
{
UInt  uiCode;

READ_CODE( 4,  uiCode,  "vps_video_parameter_set_id" );         pcVPS->setVPSId( uiCode );
READ_CODE( 2,  uiCode,  "vps_reserved_three_2bits" );           assert(uiCode == 3);
READ_CODE( 6,  uiCode,  "vps_reserved_zero_6bits" );            assert(uiCode == 0);
READ_CODE( 3,  uiCode,  "vps_max_sub_layers_minus1" );          pcVPS->setMaxTLayers( uiCode + 1 );
READ_FLAG(     uiCode,  "vps_temporal_id_nesting_flag" );       pcVPS->setTemporalNestingFlag( uiCode ? true:false );
assert (pcVPS->getMaxTLayers()>1||pcVPS->getTemporalNestingFlag());
READ_CODE( 16, uiCode,  "vps_reserved_ffff_16bits" );           assert(uiCode == 0xffff);
parsePTL ( pcVPS->getPTL(), true, pcVPS->getMaxTLayers()-1);
UInt subLayerOrderingInfoPresentFlag;
READ_FLAG(subLayerOrderingInfoPresentFlag, "vps_sub_layer_ordering_info_present_flag");
for(UInt i = 0; i <= pcVPS->getMaxTLayers()-1; i++)
{
READ_UVLC( uiCode,  "vps_max_dec_pic_buffering_minus1[i]" );     pcVPS->setMaxDecPicBuffering( uiCode + 1, i );
READ_UVLC( uiCode,  "vps_num_reorder_pics[i]" );          pcVPS->setNumReorderPics( uiCode, i );
READ_UVLC( uiCode,  "vps_max_latency_increase_plus1[i]" );      pcVPS->setMaxLatencyIncrease( uiCode, i );

if (!subLayerOrderingInfoPresentFlag)
{
for (i++; i <= pcVPS->getMaxTLayers()-1; i++)
{
pcVPS->setMaxDecPicBuffering(pcVPS->getMaxDecPicBuffering(0), i);
pcVPS->setNumReorderPics(pcVPS->getNumReorderPics(0), i);
pcVPS->setMaxLatencyIncrease(pcVPS->getMaxLatencyIncrease(0), i);
}
break;
}
}

assert( pcVPS->getNumHrdParameters() < MAX_VPS_OP_SETS_PLUS1 );
assert( pcVPS->getMaxNuhReservedZeroLayerId() < MAX_VPS_NUH_RESERVED_ZERO_LAYER_ID_PLUS1 );
READ_CODE( 6, uiCode, "vps_max_nuh_reserved_zero_layer_id" );   pcVPS->setMaxNuhReservedZeroLayerId( uiCode );
READ_UVLC(    uiCode, "vps_max_op_sets_minus1" );               pcVPS->setMaxOpSets( uiCode + 1 );
for( UInt opsIdx = 1; opsIdx <= ( pcVPS->getMaxOpSets() - 1 ); opsIdx ++ )
{
// Operation point set
for( UInt i = 0; i <= pcVPS->getMaxNuhReservedZeroLayerId(); i ++ )
{
READ_FLAG( uiCode, "layer_id_included_flag[opsIdx][i]" );   pcVPS->setLayerIdIncludedFlag( uiCode == 1 ? true : false, opsIdx, i );
}
}

TimingInfo *timingInfo = pcVPS->getTimingInfo();
READ_FLAG(       uiCode, "vps_timing_info_present_flag");         timingInfo->setTimingInfoPresentFlag      (uiCode ? true : false);
if(timingInfo->getTimingInfoPresentFlag())
{
READ_CODE( 32, uiCode, "vps_num_units_in_tick");                timingInfo->setNumUnitsInTick             (uiCode);
READ_CODE( 32, uiCode, "vps_time_scale");                       timingInfo->setTimeScale                  (uiCode);
READ_FLAG(     uiCode, "vps_poc_proportional_to_timing_flag");  timingInfo->setPocProportionalToTimingFlag(uiCode ? true : false);
if(timingInfo->getPocProportionalToTimingFlag())
{
READ_UVLC(   uiCode, "vps_num_ticks_poc_diff_one_minus1");    timingInfo->setNumTicksPocDiffOneMinus1   (uiCode);
}

READ_UVLC( uiCode, "vps_num_hrd_parameters" );                  pcVPS->setNumHrdParameters( uiCode );

if( pcVPS->getNumHrdParameters() > 0 )
{
pcVPS->createHrdParamBuffer();
}
for( UInt i = 0; i < pcVPS->getNumHrdParameters(); i ++ )
{
READ_UVLC( uiCode, "hrd_op_set_idx" );                       pcVPS->setHrdOpSetIdx( uiCode, i );
if( i > 0 )
{
READ_FLAG( uiCode, "cprms_present_flag[i]" );               pcVPS->setCprmsPresentFlag( uiCode == 1 ? true : false, i );
}
parseHrdParameters(pcVPS->getHrdParameters(i), pcVPS->getCprmsPresentFlag( i ), pcVPS->getMaxTLayers() - 1);
}
}

READ_FLAG( uiCode,  "vps_extension_flag" );
if (uiCode)
{
while ( xMoreRbspData() )
{
READ_FLAG( uiCode, "vps_extension_data_flag");
}
}

return;
}


常见的几种CAVLC解码方法

#define READ_CODE(length, code, name)     xReadCode ( length, code ) // 直接读取指定长度的比特
#define READ_UVLC(        code, name)     xReadUvlc (         code ) // 无符号指数哥伦布解码
#define READ_SVLC(        code, name)     xReadSvlc (         code ) // 有符号指数哥伦布解码
#define READ_FLAG(        code, name)     xReadFlag (         code ) // 读取一个比特

解析SPS、PPS的方法和VPS类似,这里不再赘述。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: