在TAppDecTop.cpp? ,最重要的是decode 函數,下面將對其進行分析,是解碼上層的一個重要函數。
代碼如下,代碼后將進行分析。
Void TAppDecTop::decode()
{Int poc;TComList<TComPic*>* pcListPic = NULL;ifstream bitstreamFile(m_pchBitstreamFile, ifstream::in | ifstream::binary);if (!bitstreamFile){fprintf(stderr, "\nfailed to open bitstream file `%s' for reading\n", m_pchBitstreamFile);exit(EXIT_FAILURE);}InputByteStream bytestream(bitstreamFile);// create & initialize internal classesxCreateDecLib();xInitDecLib ();m_iPOCLastDisplay += m_iSkipFrame; // set the last displayed POC correctly for skip forward.// main decoder loopBool 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 functionBool 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\n");}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("\npoc =%d\n",poc);}if( pcListPic ){printf("\nnaluType =%d\n",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 moderecon_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 fileif(bNewPicture){xWriteOutput( pcListPic, nalu.m_temporalId );}}}xFlushOutput( pcListPic );// delete buffersm_cTDecTop.deletePicBuffer();// destroy internal classesxDestroyDecLib();
}
代碼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沒有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進行解碼了。
其他的代碼很簡單,請自己分析。