留下一些注释:

Void TAppDecTop::decode(){while (!!bitstreamFile){streampos location = bitstreamFile.tellg();// 返回当前字符在流中位置// fpos 可以直接转换成 int 的AnnexBStats stats = AnnexBStats();// AnnexB 格式的流的统计状态InputNALUnit nalu;byteStreamNALUnit(bytestream, nalu.getBitstream().getFifo(), stats);// 从 bytestream 中提取出一个 nalu 单元// 数据放在一个vector中 m_fifo// 统计状态记录在 stats 中if (nalu.getBitstream().getFifo().empty()){...}else{read(nalu);// 两个工作:// 1. 去除防竞争位// 2. 提取头信息:NAL 类型,层ID,时域层ID}}
}
Bool byteStreamNALUnit(InputByteStream& bs, vector<uint8_t>& nalUnit, AnnexBStats& stats)
{Bool eof = false;try{_byteStreamNALUnit(bs, nalUnit, stats);// 从 bs 中提取 NALU 信息给 nalUnit// 并更新 stats 的统计信息}catch (...){eof = true;}stats.m_numBytesInNALUnit = UInt(nalUnit.size());return eof;
}
static Void
_byteStreamNALUnit(InputByteStream& bs,vector<uint8_t>& nalUnit,AnnexBStats& stats)
{/* At the beginning of the decoding process, the decoder initialises its* current position in the byte stream to the beginning of the byte stream.* It then extracts and discards each leading_zero_8bits syntax element (if* present), moving the current position in the byte stream forward one* byte at a time, until the current position in the byte stream is such* that the next four bytes in the bitstream form the four-byte sequence* 0x00000001.*/
#if RExt__DECODER_DEBUG_BIT_STATISTICSTComCodingStatistics::SStat &statBits=TComCodingStatistics::GetStatisticEP(STATS__NAL_UNIT_PACKING);
#endifwhile ((bs.eofBeforeNBytes(24/8) || bs.peekBytes(24/8) != 0x000001)&&     (bs.eofBeforeNBytes(32/8) || bs.peekBytes(32/8) != 0x00000001)){uint8_t leading_zero_8bits = bs.readByte();
#if RExt__DECODER_DEBUG_BIT_STATISTICSstatBits.bits+=8; statBits.count++;
#endifassert(leading_zero_8bits == 0);stats.m_numLeadingZero8BitsBytes++;}// 比特流// leading_zero_8bits -> chunk -> chunk -> chunk -> ... -> chunk// 所以这一步 是为了看前面有几个 leading_zero_8bits// 同时定位到第一个 chunk/* 1. When the next four bytes in the bitstream form the four-byte sequence* 0x00000001, the next byte in the byte stream (which is a zero_byte* syntax element) is extracted and discarded and the current position in* the byte stream is set equal to the position of the byte following this* discarded byte.*//* NB, the previous step guarantees this will succeed -- if EOF was* encountered, an exception will stop execution getting this far */if (bs.peekBytes(24/8) != 0x000001){uint8_t zero_byte = bs.readByte();
#if RExt__DECODER_DEBUG_BIT_STATISTICSstatBits.bits+=8; statBits.count++;
#endifassert(zero_byte == 0);stats.m_numZeroByteBytes++;}// chunk// zero_byte(可选) -> start_code_prefix_one_3bytes -> NALU -> trailing_zero_8bits()// 所以这一步 是为了看是否前面有 ZeroByte// 有的话就是 0x 00 00 00 01// 没有就是 0x 00 00 01/* 2. The next three-byte sequence in the byte stream (which is a* start_code_prefix_one_3bytes) is extracted and discarded and the current* position in the byte stream is set equal to the position of the byte* following this three-byte sequence.*//* NB, (1) guarantees that the next three bytes are 0x00 00 01 */uint32_t start_code_prefix_one_3bytes = bs.readBytes(24/8);
#if RExt__DECODER_DEBUG_BIT_STATISTICSstatBits.bits+=24; statBits.count+=3;
#endifassert(start_code_prefix_one_3bytes == 0x000001);stats.m_numStartCodePrefixBytes += 3;/* 3. NumBytesInNALunit is set equal to the number of bytes starting with* the byte at the current position in the byte stream up to and including* the last byte that precedes the location of any of the following* conditions:*   a. A subsequent byte-aligned three-byte sequence equal to 0x000000, or*   b. A subsequent byte-aligned three-byte sequence equal to 0x000001, or*   c. The end of the byte stream, as determined by unspecified means.*/// zero_byte(可选) -> start_code_prefix_one_3bytes -> NALU -> trailing_zero_8bits()// NumBytesInNALunit 是 NALU 中的 byte 数// 计算起止: 当前位置到// 下一个 0x000000 或者 0x000001/* 4. NumBytesInNALunit bytes are removed from the bitstream and the* current position in the byte stream is advanced by NumBytesInNALunit* bytes. This sequence of bytes is nal_unit( NumBytesInNALunit ) and is* decoded using the NAL unit decoding process*/// 既然前面的 NALU byte数量已经确定为 NumBytesInNALunit// 接下来会把这些 byte 删除掉/* NB, (unsigned)x > 2 implies n!=0 && n!=1 */
#if RExt__DECODER_DEBUG_BIT_STATISTICSTComCodingStatistics::SStat &bodyStats=TComCodingStatistics::GetStatisticEP(STATS__NAL_UNIT_TOTAL_BODY);
#endifwhile (bs.eofBeforeNBytes(24/8) || bs.peekBytes(24/8) > 2){#if RExt__DECODER_DEBUG_BIT_STATISTICSuint8_t thebyte=bs.readByte();bodyStats.bits+=8;bodyStats.count++;nalUnit.push_back(thebyte);
#elsenalUnit.push_back(bs.readByte());
#endif}// 所以 NALU 中的数据应该是 3byte 对齐的// bs.peekBytes(24/8) > 2// 这样就说明不是 NALU之间的间隔符/* 5. When the current position in the byte stream is:*  - not at the end of the byte stream (as determined by unspecified means)*  - and the next bytes in the byte stream do not start with a three-byte*    sequence equal to 0x000001*  - and the next bytes in the byte stream do not start with a four byte*    sequence equal to 0x00000001,* the decoder extracts and discards each trailing_zero_8bits syntax* element, moving the current position in the byte stream forward one byte* at a time, until the current position in the byte stream is such that:*  - the next bytes in the byte stream form the four-byte sequence*    0x00000001 or*  - the end of the byte stream has been encountered (as determined by*    unspecified means).*//* NB, (3) guarantees there are at least three bytes available or none */while ((bs.eofBeforeNBytes(24/8) || bs.peekBytes(24/8) != 0x000001)&&     (bs.eofBeforeNBytes(32/8) || bs.peekBytes(32/8) != 0x00000001)){uint8_t trailing_zero_8bits = bs.readByte();
#if RExt__DECODER_DEBUG_BIT_STATISTICSstatBits.bits+=8; statBits.count++;
#endifassert(trailing_zero_8bits == 0);stats.m_numTrailingZero8BitsBytes++;}// zero_byte(可选) -> start_code_prefix_one_3bytes -> NALU -> trailing_zero_8bits()// 末尾为了 字节对齐,会有一个或者多个 trailing_zero_8bits
}
Void read(InputNALUnit& nalu)
{TComInputBitstream&bitstream = nalu.getBitstream();vector<uint8_t>& nalUnitBuf=bitstream.getFifo();// perform anti-emulation preventionconvertPayloadToRBSP(nalUnitBuf, &bitstream, (nalUnitBuf[0] & 64) == 0);// (nalUnitBuf[0] & 64) == 0 是用来判断当前 NALU 类型是否 > 32// < 32 说明是 VCL 语法// convertPayloadToRBSP 删除 Payload 中的 03// Payload 删除 03 -> RBSPbitstream.resetToStart();readNalUnitHeader(nalu);// 读出NALU的头信息
}
static Void convertPayloadToRBSP(vector<uint8_t>& nalUnitBuf, TComInputBitstream *bitstream, Bool isVclNalUnit)
{UInt zeroCount = 0;vector<uint8_t>::iterator it_read, it_write;// 这个为什么设置两个迭代器呢?// 原 byte 序列是:// 遇见了 0x 00 00 00 或者 0x 00 00 01// 就插入一个 03 使其变成// 0x 00 00 03 00 或者 0x 00 00 03 01// 所以这个函数目的在于 删除其中的 03// 两个迭代器,一个位置标记读到的位置,一个位置标记写到的位置// it_write一直正常++// it_read遇到了03(且前面是 00 00) 就多往后走一个位置UInt pos = 0;bitstream->clearEmulationPreventionByteLocation();for (it_read = it_write = nalUnitBuf.begin(); it_read != nalUnitBuf.end(); it_read++, it_write++, pos++){assert(zeroCount < 2 || *it_read >= 0x03);if (zeroCount == 2 && *it_read == 0x03){bitstream->pushEmulationPreventionByteLocation( pos );pos++;it_read++;zeroCount = 0;
#if RExt__DECODER_DEBUG_BIT_STATISTICSTComCodingStatistics::IncrementStatisticEP(STATS__EMULATION_PREVENTION_3_BYTES, 8, 0);
#endifif (it_read == nalUnitBuf.end()){break;}assert(*it_read <= 0x03);}zeroCount = (*it_read == 0x00) ? zeroCount+1 : 0;*it_write = *it_read;}assert(zeroCount == 0);if (isVclNalUnit){// Remove cabac_zero_word from payload if presentInt n = 0;while (it_write[-1] == 0x00){it_write--;n++;}if (n > 0){printf("\nDetected %d instances of cabac_zero_word\n", n/2);}}nalUnitBuf.resize(it_write - nalUnitBuf.begin());
}
Void readNalUnitHeader(InputNALUnit& nalu)
{TComInputBitstream& bs = nalu.getBitstream();// UInt read(UInt numberOfBits)// read 参数是比特数// NALU 头第一个 比特 是 forbidden_zero_bitBool forbidden_zero_bit = bs.read(1);           // forbidden_zero_bitassert(forbidden_zero_bit == 0);nalu.m_nalUnitType = (NalUnitType) bs.read(6);  // nal_unit_typenalu.m_nuhLayerId = bs.read(6);                 // nuh_layer_idnalu.m_temporalId = bs.read(3) - 1;             // nuh_temporal_id_plus1
#if RExt__DECODER_DEBUG_BIT_STATISTICSTComCodingStatistics::IncrementStatisticEP(STATS__NAL_UNIT_HEADER_BITS, 1+6+6+3, 0);
#endif#if ENC_DEC_TRACE && DEC_NUH_TRACExTraceNalUnitHeader(nalu);
#endif// only check these rules for base layerif (nalu.m_nuhLayerId == 0){if ( nalu.m_temporalId ){assert( nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_BLA_W_LP&& nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_BLA_W_RADL&& nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_BLA_N_LP&& nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_IDR_W_RADL&& 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_TSA_R&& 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 );}}
}

HM解码(一) :提取一个NALU信息相关推荐

  1. HEVC解码器HM源码阅读(三)读取一个NALU

    读取一个NALU 视频数据的两种存储传输方式 视频的压缩数据,有两种存储传输方式: 1.存放在本地文件中,就是所谓的字节流应用(本章节讨论),也就是我们常说的比特流. 2.把数据发送到网络上,就是所谓 ...

  2. QQ群成员怎么提取? 1分钟提取一个群的成员信息

    大家在做QQ营销推广的时候,经常需要把别人QQ群的成员信息导出来,自己在用来营销推广. 怎么才能快速的把别人的QQ群成员信息提取出来呢?今天古圣教大家一个方法,最快1分钟可以提取1个群的成员信息. 我 ...

  3. linux提取基因名称和序列,一种批量提取基因组基因信息并翻译比对分析序列的方法与流程...

    技术特征: 1.一种批量提取基因组基因信息并翻译比对分析序列的方法,其特征在于,将某一物种的转录本id或者基因id,依据供试基因组cds文件.蛋白质文件.gff文件和染色体fasta文件信息,通过6个 ...

  4. 个人永久性免费-Excel催化剂功能第55波-Excel批注相关的批量删除作者、提取所有批注信息等...

    Excel里的批注,许多人很喜欢用,但批注真的值得我们大量使用吗?批注的使用场景在哪里?这些问题可能更值得花时间来思考下. 同样因为不规范地使用批注,也带出了一大堆的后续擦屁股的事情来,从批注中找回有 ...

  5. js实现提取textarea文本信息,然后进行处理

    js实现提取textarea文本信息,然后进行处理 提取textarea文本信息,并提出其中A-Z字母出现的次数,并算出频率,然后从大到小排序 提取textarea文本信息 document.getE ...

  6. 个人永久性免费-Excel催化剂功能第88波-批量提取pdf文件信息(图片、表格、文本等)...

    日常办公场合中,除了常规的Excel.Word.PPT等文档外,还有一个不可忽略的文件格式是pdf格式,而对于想从pdf文件中获取信息时,常规方法将变得非常痛苦和麻烦.此篇给大家送一pdf文件提取信息 ...

  7. Java基础练习题5--[给定一段字符串,将里面的信息进行提取,(注意:需要考虑信息是可变的)String s=“张三:上机成绩=90,笔试成绩=78“+“李四:上机成绩=68,笔试成绩......]

    题目:给定一段字符串,将里面的信息进行提取,(注意:需要考虑信息是可变的) String s = "张三:上机成绩=90,笔试成绩=78;" + "李四:上机成绩=68, ...

  8. 从EXIF JPEG图片中提取GPS位置信息

    符合EXIFJPEG标准的图片,除了记录图片压缩数据之外,在存储了拍摄参数,其中包括拍摄时GPS参数信息,因此,可以利用程序从EXIF元数据信息中解析提取GPS位置信息. 1. Java读取EXIF信 ...

  9. 关于“做一个聊天+信息分享客户端”的设想(SNS?)

    最近有个点子:做一个聊天+信息分享客户端,聊天工具类似QQ.MSN,信息分享一个方面的功能类似博客.微博. 聊天与信息分享分别可以积累评价信息,聊天与信息分享在内容与积累的信誉方面无缝共享.聊天/信息 ...

最新文章

  1. 【 全干货 】5 分钟带你看懂 Docker !
  2. iOS下JS与OC互相调用(七)--Cordova 基础
  3. 江西教育考试院2021年高考成绩查询入口,2021年江西高考网上志愿填报入口:江西省教育考试院...
  4. 简述ospf的工作原理_物联网水表工作原理简述
  5. 基于灰度变换的图像增强
  6. 3.4.3 深度探索linux,3.2.4 vmlinux.bin的构建过程(3)
  7. 异常处理--“System.BadImageFormatException”类型的未经处理的异常在 DataTest.exe 中发生
  8. Spring注解浅入浅出——不吹牛逼不装逼
  9. 超市库存管理java sql_超市仓库管理系统的设计与实现(MySQL)
  10. 渗透测试漏流程(PTES)
  11. 关于oracle端口映射的远程连接
  12. [NLP]OpenNLP介绍
  13. 排查生产环境下CPU飙高的原因
  14. 网络安全工程师年薪百万?到底是干什么的?
  15. 数组中的元素转成Number或者String---数组map方法
  16. Android内存优化(二)之Bitmap的内存申请与回收(Android N和O的对比)
  17. 图像转 ico 图标工具 Any to Icon v3.59
  18. kubectl全部命令用法示例
  19. 生如蝼蚁当立鸿鹄之志,命薄似纸应有不屈之心,乾坤未定,你我都是黑马!(祝大家飞黄腾达前程似锦)
  20. Quartus || 13.1安装

热门文章

  1. 学习明日科技用python实现的学生管理系统
  2. 搭建docker,docker搭建达梦数据库,详细【图文】
  3. 时间序列预测常见模型总结
  4. 【java毕业设计】基于javaEE+ssh+jsp+MySqL的大学生就业信息管理系统设计与实现(毕业论文+程序源码)——大学生就业信息管理系统
  5. 工作流框架flowable6与activiti7的选择
  6. 自然数学的哲学原理--复数理论的扩展
  7. matlab保存符合条件的值到一个新的向量
  8. 聚焦2020九大科技热点,本周三ELEXCON电子展大幕将启!(含展商名单+会议推荐)...
  9. 总说币圈缺钱缺用户,真相是缺资产!
  10. 数据防泄漏有哪些常见误区?