解析视频参数集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类似,这里不再赘述。