HEVC学习(十七) —— NAL unit 的解码过程之一

下图为官方标准中NAL层的句法元素,且以伪代码的形式给出了解码过程:

在HM中由TAppDecTop::decode()调用byteStreamNALUnit(bytestream, nalUnit, stats)实现如上伪代码:

  1. /** 
  2.  * Parse an AVC AnnexB Bytestream bs to extract a single nalUnit 
  3.  * while accumulating bytestream statistics into stats. 
  4.  * 
  5.  * Returns false if EOF was reached (NB, nalunit data may be valid), 
  6.  *         otherwise true. 
  7.  */  
  8. Bool  
  9. byteStreamNALUnit(  
  10.   InputByteStream& bs,  
  11.   vector<uint8_t>& nalUnit,  
  12.   AnnexBStats& stats)  
  13. {  
  14.   Bool eof = false;  
  15.   try  
  16.   {  
  17.     _byteStreamNALUnit(bs, nalUnit, stats); //!< 实际完成NAL解析工作的函数   
  18.   }  
  19.   catch (...) //!< 捕获所有异常   
  20.   {  
  21.     eof = true;  
  22.   }  
  23.   stats.m_numBytesInNALUnit = UInt(nalUnit.size());  
  24.   return eof;  
  25. }  
/**
 * 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。

  1. /** 
  2.  * returns true if an EOF will be encountered within the next 
  3.  * n bytes. 
  4.  */  
  5. Bool eofBeforeNBytes(UInt n)  
  6. {  
  7.   assert(n <= 4);  
  8.   if (m_NumFutureBytes >= n) //!< m_NumFutureBytes大于等于n只会在该函数被调用2次及2次以上的情况下发生,满足该条件时无须继续读多余的字节,故返回false   
  9.     return false;  
  10.   
  11.   n -= m_NumFutureBytes; //!< n先减去m_NumFutureBytes的目的是防止被函数peekBytes调用时再读入接下来的n字节数据   
  12.   try  
  13.   {  
  14.     for (UInt i = 0; i < n; i++)  
  15.     {  
  16.       m_FutureBytes = (m_FutureBytes << 8) | m_Input.get(); //!< 每次读入一个字节,循环结束后,m_FutureBytes存放的是读入的n个字节的数据   
  17.       m_NumFutureBytes++;  
  18.     }  
  19.   }  
  20.   catch (...) //!< 出现异常即读到文件结尾,返回true   
  21.   {  
  22.     return true;  
  23.   }  
  24.   return false;  
  25. }  
  /**
   * 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)的功能。

  1. /** 
  2.  * return the next n bytes in the stream without advancing 
  3.  * the stream pointer. 
  4.  * 
  5.  * Returns: an unsigned integer representing an n byte bigendian 
  6.  * word. 
  7.  * 
  8.  * If an attempt is made to read past EOF, an n-byte word is 
  9.  * returned, but the portion that required input bytes beyond EOF 
  10.  * is undefined. 
  11.  * 
  12.  */  
  13. uint32_t peekBytes(UInt n)  
  14. {  
  15.   eofBeforeNBytes(n);  
  16.   return m_FutureBytes >> 8*(m_NumFutureBytes - n); //!< 若m_NumFutureBytes=4, n=3,则返回m_FutureBytes左移8位后(即有效数据位为3字节)的数据   
  17. }  
  /**
   * 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()

该函数读文件的一个字节并返回。

  1. /** 
  2.  * consume and return one byte from the input. 
  3.  * 
  4.  * If bytestream is already at EOF prior to a call to readByte(), 
  5.  * an exception std::ios_base::failure is thrown. 
  6.  */  
  7. uint8_t readByte()  
  8. {  
  9.   if (!m_NumFutureBytes) //!< m_FutureBytes为NULL,则从文件中读入一个字节并返回   
  10.   {  
  11.     uint8_t byte = m_Input.get();  
  12.     return byte;  
  13.   }//! m_FutureBytes非NULL,则从它当中取出一个字节出来   
  14.   m_NumFutureBytes--; //!< 计数值减1   
  15.   uint8_t wanted_byte = m_FutureBytes >> 8*m_NumFutureBytes; //!< m_FutureBytes为4字节,取出有效数据中的最高字节   
  16.   m_FutureBytes &= ~(0xff << 8*m_NumFutureBytes); //!< 对应位置的数据清零   
  17.   return wanted_byte;  
  18. }  
  /**
   * 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个字节并返回。

  1. /** 
  2.  * consume and return n bytes from the input.  n bytes from 
  3.  * bytestream are interpreted as bigendian when assembling 
  4.  * the return value. 
  5.  */  
  6. uint32_t readBytes(UInt n)  
  7. {  
  8.   uint32_t val = 0;  
  9.   for (UInt i = 0; i < n; i++)  
  10.     val = (val << 8) | readByte(); //!< 每次调用readByte()读入一个字节,通过对val左移8位且与输入值进行或运算实现将n个字节存储到val这个变量中   
  11.   return val;  
  12. }  
  /**
   * 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;
  }


http://blog.csdn.net/hevc_cjl/article/details/8461660#comments

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值