前面兩篇已經將NAL的解析過程的核心部分介紹完了,本篇主要討論如何將NAL的payload部分轉化爲原始數據,即從EBSP到RBSP的過程。
該過程由TAppDecTop::decode()的子函數read(nalu, nalUnit)調用convertPayloadToRBSP(nalUnitBuf, pcBitstream, (nalUnitBuf[0] & 64) == 0)實現。
read(nalu, nalUnit); //!< nalUnit-->nalu (EBSP-->RBSP)
/**
* create a NALunit structure with given header values and storage for
* a bitstream
*/
void read(InputNALUnit& nalu, vector<uint8_t>& nalUnitBuf)
{
/* perform anti-emulation prevention */
TComInputBitstream *pcBitstream = new TComInputBitstream(NULL);
#if HM9_NALU_TYPES
convertPayloadToRBSP(nalUnitBuf, pcBitstream, (nalUnitBuf[0] & 64) == 0); //!< 實現真正的EBSP-->RBSP
#else
convertPayloadToRBSP(nalUnitBuf, pcBitstream);
#endif
nalu.m_Bitstream = new TComInputBitstream(&nalUnitBuf);
delete pcBitstream;
readNalUnitHeader(nalu); //!< 解析NAL的頭部
}
#if HM9_NALU_TYPES
static void convertPayloadToRBSP(vector<uint8_t>& nalUnitBuf, TComInputBitstream *pcBitstream, Bool isVclNalUnit)
#else
static void convertPayloadToRBSP(vector<uint8_t>& nalUnitBuf, TComInputBitstream *pcBitstream)
#endif
{
UInt zeroCount = 0;
vector<uint8_t>::iterator it_read, it_write;
for (it_read = it_write = nalUnitBuf.begin(); it_read != nalUnitBuf.end(); it_read++, it_write++)
{
assert(zeroCount < 2 || *it_read >= 0x03);
if (zeroCount == 2 && *it_read == 0x03) //!< 讀到0x000003時,丟棄0x03
{
it_read++;
zeroCount = 0;
if (it_read == nalUnitBuf.end())
{
break;
}
}
zeroCount = (*it_read == 0x00) ? zeroCount+1 : 0;
*it_write = *it_read;
}
assert(zeroCount == 0);
#if HM9_NALU_TYPES
if (isVclNalUnit)
{
// Remove cabac_zero_word from payload if present
Int n = 0;
while (it_write[-1] == 0x00)
{
it_write--;
n++;
}
if (n > 0)
{
printf("\nDetected %d instances of cabac_zero_word", n/2);
}
}
#endif
nalUnitBuf.resize(it_write - nalUnitBuf.begin());
}
下面這個函數可對照draft 7.3.1.2 NAL unit header syntax進行分析,如下:
Void readNalUnitHeader(InputNALUnit& nalu)
{
TComInputBitstream& bs = *nalu.m_Bitstream;
Bool forbidden_zero_bit = bs.read(1); // forbidden_zero_bit
assert(forbidden_zero_bit == 0);
nalu.m_nalUnitType = (NalUnitType) bs.read(6); // nal_unit_type
nalu.m_reservedZero6Bits = bs.read(6); // nuh_reserved_zero_6bits
assert(nalu.m_reservedZero6Bits == 0);
nalu.m_temporalId = bs.read(3) - 1; // nuh_temporal_id_plus1
if ( nalu.m_temporalId )
{
assert( nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_BLA
&& nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_BLANT
&& nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_BLA_N_LP
&& nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_IDR
&& nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_IDR_N_LP
&& nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_CRA
&& nalu.m_nalUnitType != NAL_UNIT_VPS
&& nalu.m_nalUnitType != NAL_UNIT_SPS
&& nalu.m_nalUnitType != NAL_UNIT_EOS
&& nalu.m_nalUnitType != NAL_UNIT_EOB );
}
else
{
assert( nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_TLA
&& nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_TSA_N
&& nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_STSA_R
&& nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_STSA_N );
}
}