HEVC學習(十七) —— NAL unit 的解碼過程之一

下圖爲官方標準中NAL層的句法元素,且以僞代碼的形式給出瞭解碼過程:

在HM中由TAppDecTop::decode()調用byteStreamNALUnit(bytestream, nalUnit, stats)實現如上僞代碼:

/**
 * Parse an AVC AnnexB Bytestream bs to extract a single nalUnit
 * while accumulating bytestream statistics into stats.
 *
 * Returns false if EOF was reached (NB, nalunit data may be valid),
 *         otherwise true.
 */
Bool
byteStreamNALUnit(
  InputByteStream& bs,
  vector<uint8_t>& nalUnit,
  AnnexBStats& stats)
{
  Bool eof = false;
  try
  {
    _byteStreamNALUnit(bs, nalUnit, stats); //!< 實際完成NAL解析工作的函數
  }
  catch (...) //!< 捕獲所有異常
  {
    eof = true;
  }
  stats.m_numBytesInNALUnit = UInt(nalUnit.size());
  return eof;
}

在分析NAL解析過程之前,先介紹幾個會被調用到的子函數,以便更好地理解解析過程。

1. Bool eofBeforeNBytes(UInt n)

如果在讀碼流的接下來的n字節的過程中遇到了文件結束符,則該函數返回true,否則返回false。

  /**
   * returns true if an EOF will be encountered within the next
   * n bytes.
   */
  Bool eofBeforeNBytes(UInt n)
  {
    assert(n <= 4);
    if (m_NumFutureBytes >= n) //!< m_NumFutureBytes大於等於n只會在該函數被調用2次及2次以上的情況下發生,滿足該條件時無須繼續讀多餘的字節,故返回false
      return false;

    n -= m_NumFutureBytes; //!< n先減去m_NumFutureBytes的目的是防止被函數peekBytes調用時再讀入接下來的n字節數據
    try
    {
      for (UInt i = 0; i < n; i++)
      {
        m_FutureBytes = (m_FutureBytes << 8) | m_Input.get(); //!< 每次讀入一個字節,循環結束後,m_FutureBytes存放的是讀入的n個字節的數據
        m_NumFutureBytes++;
      }
    }
    catch (...) //!< 出現異常即讀到文件結尾,返回true
    {
      return true;
    }
    return false;
  }

2. uint32_t peekBytes(UInt n)

該函數在不移動文件指針的前提下返回文件中接下來的n字節。實現的即是僞代碼中的next_bits(n)的功能。

  /**
   * return the next n bytes in the stream without advancing
   * the stream pointer.
   *
   * Returns: an unsigned integer representing an n byte bigendian
   * word.
   *
   * If an attempt is made to read past EOF, an n-byte word is
   * returned, but the portion that required input bytes beyond EOF
   * is undefined.
   *
   */
  uint32_t peekBytes(UInt n)
  {
    eofBeforeNBytes(n);
    return m_FutureBytes >> 8*(m_NumFutureBytes - n); //!< 若m_NumFutureBytes=4, n=3,則返回m_FutureBytes左移8位後(即有效數據位爲3字節)的數據
  }

3. uint8_t readByte()

該函數讀文件的一個字節並返回。

  /**
   * consume and return one byte from the input.
   *
   * If bytestream is already at EOF prior to a call to readByte(),
   * an exception std::ios_base::failure is thrown.
   */
  uint8_t readByte()
  {
    if (!m_NumFutureBytes) //!< m_FutureBytes爲NULL,則從文件中讀入一個字節並返回
    {
      uint8_t byte = m_Input.get();
      return byte;
    }//! m_FutureBytes非NULL,則從它當中取出一個字節出來
    m_NumFutureBytes--; //!< 計數值減1
    uint8_t wanted_byte = m_FutureBytes >> 8*m_NumFutureBytes; //!< m_FutureBytes爲4字節,取出有效數據中的最高字節
    m_FutureBytes &= ~(0xff << 8*m_NumFutureBytes); //!< 對應位置的數據清零
    return wanted_byte;
  }

4. uint32_t readBytes(UInt n)

該函數讀文件的n個字節並返回。

  /**
   * consume and return n bytes from the input.  n bytes from
   * bytestream are interpreted as bigendian when assembling
   * the return value.
   */
  uint32_t readBytes(UInt n)
  {
    uint32_t val = 0;
    for (UInt i = 0; i < n; i++)
      val = (val << 8) | readByte(); //!< 每次調用readByte()讀入一個字節,通過對val左移8位且與輸入值進行或運算實現將n個字節存儲到val這個變量中
    return val;
  }





 

 

發佈了97 篇原創文章 · 獲贊 855 · 訪問量 106萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章