前面两篇已经将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 ); } }