HEVC学习(十七) —— NAL unit 的解码过程之一
2013-01-11 12:19
447 查看
HEVCHMNAL解码过程
下图为官方标准中NAL层的句法元素,且以伪代码的形式给出了解码过程:
在HM中由TAppDecTop::decode()调用byteStreamNALUnit(bytestream, nalUnit, stats)实现如上伪代码:
[cpp]
view plaincopyprint?
/**
* 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。
[cpp]
view plaincopyprint?
/**
* 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)的功能。
[cpp]
view plaincopyprint?
/**
* 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()
该函数读文件的一个字节并返回。
[cpp]
view plaincopyprint?
/**
* 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个字节并返回。
[cpp]
view plaincopyprint?
/**
* 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)
下图为官方标准中NAL层的句法元素,且以伪代码的形式给出了解码过程:
在HM中由TAppDecTop::decode()调用byteStreamNALUnit(bytestream, nalUnit, stats)实现如上伪代码:
[cpp]
view plaincopyprint?
/**
* 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;
}
/** * 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。
[cpp]
view plaincopyprint?
/**
* 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;
}
/** * 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)的功能。
[cpp]
view plaincopyprint?
/**
* 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字节)的数据
}
/** * 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()
该函数读文件的一个字节并返回。
[cpp]
view plaincopyprint?
/**
* 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;
}
/** * 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个字节并返回。
[cpp]
view plaincopyprint?
/**
* 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;
}
/** * 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)
相关文章推荐
- HEVC学习(十八) —— NAL unit 的解码过程之二
- HEVC学习(十七) —— NAL unit 的解码过程之一
- 【HEVC学习与研究】38、HEVC编码过程中的块分割结构
- 【HEVC学习与研究】38、HEVC编码过程中的块分割结构
- 【HEVC学习与研究】30、解码Coding Unit数据
- 【HEVC学习与研究】14.HEVC解码中VPS参数集解析
- Part2:Unity学习笔记十七 - Space Shooter(从视频最后一课向Done_Main.unity场景修改的过程)
- 【HEVC学习与研究】15、HEVC解码中的SPS解析
- 【HEVC学习与研究】44、HEVC量化系数的解析——反量化过程
- PostgreSQL学习手册(十七) PL/pgSQL过程语言
- 学习硬解码视频过程(安卓)中参考的一些文档
- HEVC学习(十九) —— NAL unit 的解码过程之三
- HEVC学习与研究】11.HEVC参考解码器的设置及参数解析过程
- 【HEVC学习与研究】11.HEVC参考解码器的设置及参数解析过程
- 【HEVC学习与研究】30、解码Coding Unit数据
- 学习编程是不断练习的过程!!!!!
- DirectShow学习之三媒体播放过程分析
- MFC OnFileNew OnFileOpen过程分析代码(以记录MFC学习点滴)