须知少年凌云志,曾许人间第一流。这篇文章主要讲述HEVC/H265 HM10 0 分析TAppDecTop cpp相关的知识,希望能为你提供帮助。
在TAppDecTop.cpp
,最重要的是decode 函数,下面将对其进行分析,是解码上层的一个重要函数。
代码如下,代码后将进行分析。
Void TAppDecTop::decode()
{
Intpoc;
TComList<
TComPic*>
* pcListPic = NULL;
ifstream bitstreamFile(m_pchBitstreamFile, ifstream::in | ifstream::binary);
if (!bitstreamFile)
{
fprintf(stderr, "
failed to open bitstream file `%s‘ for reading
", m_pchBitstreamFile);
exit(EXIT_FAILURE);
}InputByteStream bytestream(bitstreamFile);
// create &
initialize internal classes
xCreateDecLib();
xInitDecLib();
m_iPOCLastDisplay += m_iSkipFrame;
// set the last displayed POC correctly for skip forward.// main decoder loop
Bool recon_opened = false;
// reconstruction file not yet opened. (must be performed after SPS is seen)while (!!bitstreamFile)
{
/* location serves to work around a design fault in the decoder, whereby
* the process of reading a new slice that is the first slice of a new frame
* requires the TDecTop::decode() method to be called again with the same
* nal unit. */
streampos location = bitstreamFile.tellg();
AnnexBStats stats = AnnexBStats();
Bool bPreviousPictureDecoded = false;
vector<
uint8_t>
nalUnit;
InputNALUnit nalu;
byteStreamNALUnit(bytestream, nalUnit, stats);
// call actual decoding function
Bool bNewPicture = false;
if (nalUnit.empty())
{
/* this can happen if the following occur:
*- empty input file
*- two back-to-back start_code_prefixes
*- start_code_prefix immediately followed by EOF
*/
fprintf(stderr, "Warning: Attempt to decode an empty NAL unit
");
}
else
{
read(nalu, nalUnit);
if( (m_iMaxTemporalLayer >
= 0 &
&
nalu.m_temporalId >
m_iMaxTemporalLayer) || !isNaluWithinTargetDecLayerIdSet(&
nalu))
{
if(bPreviousPictureDecoded)
{
bNewPicture = true;
bPreviousPictureDecoded = false;
}
else
{
bNewPicture = false;
}
}
else
{
bNewPicture = m_cTDecTop.decode(nalu, m_iSkipFrame, m_iPOCLastDisplay);
if (bNewPicture)
{
bitstreamFile.clear();
/* location points to the current nalunit payload[1] due to the
* need for the annexB parser to read three extra bytes.
* [1] except for the first NAL unit in the file
*(but bNewPicture doesn‘t happen then) */
bitstreamFile.seekg(location-streamoff(3));
bytestream.reset();
}
bPreviousPictureDecoded = true;
}
}
if (bNewPicture || !bitstreamFile)
{m_cTDecTop.executeLoopFilters(poc, pcListPic);
printf("
poc =%d
",poc);
}if( pcListPic )
{
printf("
naluType =%d
",nalu.m_nalUnitType);
if ( m_pchReconFile &
&
!recon_opened )
{
if (!m_outputBitDepthY) { m_outputBitDepthY = g_bitDepthY;
}
if (!m_outputBitDepthC) { m_outputBitDepthC = g_bitDepthC;
}m_cTVideoIOYuvReconFile.open( m_pchReconFile, true, m_outputBitDepthY, m_outputBitDepthC, g_bitDepthY, g_bitDepthC );
// write mode
recon_opened = true;
}
if ( bNewPicture &
&
(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_BLA_N_LP
|| nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_BLANT
|| nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA ) )
{
xFlushOutput( pcListPic );
}
// write reconstruction to file
if(bNewPicture)
{
xWriteOutput( pcListPic, nalu.m_temporalId );
}
}
}xFlushOutput( pcListPic );
// delete buffers
m_cTDecTop.deletePicBuffer();
// destroy internal classes
xDestroyDecLib();
}
代码xCreateDecLib 和 xInitDecLib 重要是初始化四叉树和解码需要的全局变量和申请内存。
当提供一个码流文件的文件名后,进行ifstream bitstreamFile(m_pchBitstreamFile, ifstream::in | ifstream::binary); 以二进制方式打开文件名,码流以字节方式InputByteStream bytestream(bitstreamFile); 进行读操作。
我们都知道,HEVC/H265 是以NAL方式组织数据的,解析VPS,SPS,PPS,SEI,SEI_SUFFIX 后,其他的是一个个slice的NAL数据,而Deblocking & SAO Filters 等滤波是对整个picuture进行滤波操作,出现从第二帧开始,每帧的第一个slice两次进行解析,这是参考软件的一个bug或不好的地方,其实完全可以知道是否是最后一个slice,不必进行两次打开。
所以出现:
bitstreamFile.clear();
bitstreamFile.seekg(location-streamoff(3));
bytestream.reset();
大家有兴趣,可以先增加一个变量,判断是否是最后一个slice,就不需要执行上面代码了。
【HEVC/H265 HM10 0 分析TAppDecTop cpp】
如下代码是从来不会执行,因为HEVC/H265没有cavlc,也就不会有slice part A ,slice part B,slice part C ,是现实的编解码告诉了设计者,slice part A ,slice part B,slice part C 没有人使用,就被抛弃了,实际的编解码从来没有实现slice part A ,slice part B,slice part C 等编解码的。
if( (m_iMaxTemporalLayer > = 0 & & nalu.m_temporalId > m_iMaxTemporalLayer) || !isNaluWithinTargetDecLayerIdSet(& nalu) )
{
if(bPreviousPictureDecoded)
{
bNewPicture = true;
bPreviousPictureDecoded = false;
}
else
{
bNewPicture = false;
}
}
解码和滤波后当然就是输出重构数据,xWriteOutput( pcListPic, nalu.m_temporalId ), 如果slice是NAL_UNIT_CODED_SLICE_IDR,NAL_UNIT_CODED_SLICE_IDR_N_LP,NAL_UNIT_CODED_SLICE_BLA_N_LP,NAL_UNIT_CODED_SLICE_BLANT,NAL_UNIT_CODED_SLICE_BLA中的一种,将解码产生的picture全部清空,没有任何参考帧,相当于一个新的sequence进行解码了。
其他的代码很简单,请自己分析。
再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow
推荐阅读
- Android Studio之构建项目报错
- Vue2.5开发去哪儿网App 首页开发
- Spring Boot通过application.yml配置文件获取属性及类信息
- android修改便携式热点的默认SSID名称
- android USB OTG功能如何打开及实现
- 在Python中使用PostgreSQL
- 循环学习率简介
- 电子表格入门教程
- 使用Tableau的电子表格