/* The copyright in this software is being made available under the BSD * License, included below. This software may be subject to other third party * and contributor rights, including patent rights, and no such rights are * granted under this license. * * Copyright (c) 2010-2011, ISO/IEC * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the ISO/IEC nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /** \file TDecGop.cpp \brief GOP decoder class */ extern bool g_md5_mismatch; ///< top level flag to signal when there is a decode problem #include "TDecGop.h" #include "TDecCAVLC.h" #include "TDecSbac.h" #include "TDecBinCoder.h" #include "TDecBinCoderCABAC.h" #include "../libmd5/MD5.h" #include "../TLibCommon/SEI.h" #include static void calcAndPrintMD5Status(TComPicYuv& pic, const SEImessages* seis); // ==================================================================================================================== // Constructor / destructor / initialization / destroy // ==================================================================================================================== TDecGop::TDecGop() { m_iGopSize = 0; m_dDecTime = 0; } TDecGop::~TDecGop() { } Void TDecGop::create() { } Void TDecGop::destroy() { } Void TDecGop::init( TDecEntropy* pcEntropyDecoder, TDecSbac* pcSbacDecoder, TDecBinCABAC* pcBinCABAC, TDecCavlc* pcCavlcDecoder, TDecSlice* pcSliceDecoder, TComLoopFilter* pcLoopFilter, TComAdaptiveLoopFilter* pcAdaptiveLoopFilter, #if MTK_SAO TComSampleAdaptiveOffset* pcSAO #endif #if DEPTH_MAP_GENERATION ,TComDepthMapGenerator* pcDepthMapGenerator #endif #if HHI_INTER_VIEW_RESIDUAL_PRED ,TComResidualGenerator* pcResidualGenerator #endif ) { m_pcEntropyDecoder = pcEntropyDecoder; m_pcSbacDecoder = pcSbacDecoder; m_pcBinCABAC = pcBinCABAC; m_pcCavlcDecoder = pcCavlcDecoder; m_pcSliceDecoder = pcSliceDecoder; m_pcLoopFilter = pcLoopFilter; m_pcAdaptiveLoopFilter = pcAdaptiveLoopFilter; #if MTK_SAO m_pcSAO = pcSAO; #endif #if DEPTH_MAP_GENERATION m_pcDepthMapGenerator = pcDepthMapGenerator; #endif #if HHI_INTER_VIEW_RESIDUAL_PRED m_pcResidualGenerator = pcResidualGenerator; #endif } // ==================================================================================================================== // Public member functions // ==================================================================================================================== Void TDecGop::decompressGop (Bool bEos, TComBitstream* pcBitstream, TComPic*& rpcPic, Bool bExecuteDeblockAndAlf) { TComSlice* pcSlice = rpcPic->getSlice(rpcPic->getCurrSliceIdx()); //-- For time output for each slice long iBeforeTime = clock(); UInt uiStartCUAddr = pcSlice->getEntropySliceCurStartCUAddr(); #if MTK_NONCROSS_INLOOP_FILTER static Bool bFirst = true; static UInt uiILSliceCount; static UInt* puiILSliceStartLCU; if (!bExecuteDeblockAndAlf) { if(bFirst) { uiILSliceCount = 0; if(!pcSlice->getSPS()->getLFCrossSliceBoundaryFlag()) { puiILSliceStartLCU = new UInt[rpcPic->getNumCUsInFrame() +1]; } bFirst = false; } if(!pcSlice->getSPS()->getLFCrossSliceBoundaryFlag()) { UInt uiSliceStartCuAddr = pcSlice->getSliceCurStartCUAddr(); if(uiSliceStartCuAddr == uiStartCUAddr) { puiILSliceStartLCU[uiILSliceCount] = uiSliceStartCuAddr; uiILSliceCount++; } } #endif //MTK_NONCROSS_INLOOP_FILTER UInt iSymbolMode = pcSlice->getSymbolMode(); if (iSymbolMode) { m_pcSbacDecoder->init( (TDecBinIf*)m_pcBinCABAC ); m_pcEntropyDecoder->setEntropyDecoder (m_pcSbacDecoder); } else { m_pcEntropyDecoder->setEntropyDecoder (m_pcCavlcDecoder); } m_pcEntropyDecoder->setBitstream (pcBitstream); m_pcEntropyDecoder->resetEntropy (pcSlice); if (uiStartCUAddr==0) // decode ALF params only from first slice header { #if MTK_SAO if( rpcPic->getSlice(0)->getSPS()->getUseSAO() ) { m_pcSAO->InitSao(&m_cSaoParam); m_pcEntropyDecoder->decodeSaoParam(&m_cSaoParam); } #endif if ( rpcPic->getSlice(0)->getSPS()->getUseALF() ) { #if TSB_ALF_HEADER m_pcAdaptiveLoopFilter->setNumCUsInFrame(rpcPic); #endif m_pcAdaptiveLoopFilter->allocALFParam(&m_cAlfParam); m_pcEntropyDecoder->decodeAlfParam( &m_cAlfParam ); } } #if DEPTH_MAP_GENERATION // init view component and predict virtual depth map if( uiStartCUAddr == 0 ) { m_pcDepthMapGenerator->initViewComponent( rpcPic ); m_pcDepthMapGenerator->predictDepthMap ( rpcPic ); #if HHI_INTER_VIEW_RESIDUAL_PRED m_pcResidualGenerator->initViewComponent( rpcPic ); #endif } #endif // decode slice m_pcSliceDecoder->decompressSlice(pcBitstream, rpcPic); m_dDecTime += (double)(clock()-iBeforeTime) / CLOCKS_PER_SEC; } else { #if HHI_INTER_VIEW_RESIDUAL_PRED // set residual picture m_pcResidualGenerator->setRecResidualPic( rpcPic ); #endif #if DEPTH_MAP_GENERATION // update virtual depth map m_pcDepthMapGenerator->updateDepthMap( rpcPic ); #endif // deblocking filter m_pcLoopFilter->setCfg(pcSlice->getLoopFilterDisable(), 0, 0); m_pcLoopFilter->loopFilterPic( rpcPic ); #if MTK_SAO { if( rpcPic->getSlice(0)->getSPS()->getUseSAO()) { m_pcSAO->SAOProcess(rpcPic, &m_cSaoParam); } } #endif // adaptive loop filter if( pcSlice->getSPS()->getUseALF() ) { #if MTK_NONCROSS_INLOOP_FILTER if(pcSlice->getSPS()->getLFCrossSliceBoundaryFlag()) { m_pcAdaptiveLoopFilter->setUseNonCrossAlf(false); } else { puiILSliceStartLCU[uiILSliceCount] = rpcPic->getNumCUsInFrame(); m_pcAdaptiveLoopFilter->setUseNonCrossAlf( (uiILSliceCount > 1) ); if(m_pcAdaptiveLoopFilter->getUseNonCrossAlf()) { m_pcAdaptiveLoopFilter->setNumSlicesInPic( uiILSliceCount ); m_pcAdaptiveLoopFilter->createSlice(); for(UInt i=0; i< uiILSliceCount ; i++) { (*m_pcAdaptiveLoopFilter)[i].create(rpcPic, i, puiILSliceStartLCU[i], puiILSliceStartLCU[i+1]-1); } } } #endif m_pcAdaptiveLoopFilter->ALFProcess(rpcPic, &m_cAlfParam); #if MTK_NONCROSS_INLOOP_FILTER if(m_pcAdaptiveLoopFilter->getUseNonCrossAlf()) { m_pcAdaptiveLoopFilter->destroySlice(); } #endif m_pcAdaptiveLoopFilter->freeALFParam(&m_cAlfParam); } /*#if AMVP_BUFFERCOMPRESS rpcPic->compressMotion(); // move to end of access unit #endif */ //-- For time output for each slice if(rpcPic->getViewIdx()!=-1) { if( !pcSlice->getSPS()->isDepth()) { printf("\nView \t\t%4d\t POC %4d ( %c-SLICE, QP%3d ) ", rpcPic->getViewIdx(), pcSlice->getPOC(), pcSlice->isIntra() ? 'I' : pcSlice->isInterP() ? 'P' : 'B', pcSlice->getSliceQp() ); } else { printf("\nDepth View \t%4d\t POC %4d ( %c-SLICE, QP%3d ) ", rpcPic->getViewIdx(), pcSlice->getPOC(), pcSlice->isIntra() ? 'I' : pcSlice->isInterP() ? 'P' : 'B', pcSlice->getSliceQp() ); } } else printf("\nPOC %4d ( %c-SLICE, QP%3d ) ", pcSlice->getPOC(), pcSlice->isIntra() ? 'I' : pcSlice->isInterP() ? 'P' : 'B', pcSlice->getSliceQp() ); m_dDecTime += (double)(clock()-iBeforeTime) / CLOCKS_PER_SEC; printf ("[DT %6.3f] ", m_dDecTime ); m_dDecTime = 0; for (Int iRefList = 0; iRefList < 2; iRefList++) { printf ("[L%d ", iRefList); for (Int iRefIndex = 0; iRefIndex < pcSlice->getNumRefIdx(RefPicList(iRefList)); iRefIndex++) { if( pcSlice->getViewIdx() != pcSlice->getRefViewIdx( RefPicList(iRefList), iRefIndex ) ) { printf( "V%d", pcSlice->getRefViewIdx( RefPicList(iRefList), iRefIndex ) ); if( pcSlice->getPOC() != pcSlice->getRefPOC( RefPicList(iRefList), iRefIndex ) ) printf( "(%d)", pcSlice->getRefPOC( RefPicList(iRefList), iRefIndex ) ); printf( " " ); } else printf ("%d ", pcSlice->getRefPOC(RefPicList(iRefList), iRefIndex)); } printf ("] "); } #if DCM_COMB_LIST if(pcSlice->getNumRefIdx(REF_PIC_LIST_C)>0 && !pcSlice->getNoBackPredFlag()) { printf ("[LC "); for (Int iRefIndex = 0; iRefIndex < pcSlice->getNumRefIdx(REF_PIC_LIST_C); iRefIndex++) { if( pcSlice->getViewIdx() != pcSlice->getRefViewIdx( (RefPicList)pcSlice->getListIdFromIdxOfLC(iRefIndex), pcSlice->getRefIdxFromIdxOfLC(iRefIndex) ) ) { printf( "V%d", pcSlice->getRefViewIdx( (RefPicList)pcSlice->getListIdFromIdxOfLC(iRefIndex), pcSlice->getRefIdxFromIdxOfLC(iRefIndex) ) ); if( pcSlice->getPOC() != pcSlice->getRefPOC( (RefPicList)pcSlice->getListIdFromIdxOfLC(iRefIndex), pcSlice->getRefIdxFromIdxOfLC(iRefIndex) ) ) printf( "(%d)", pcSlice->getRefPOC( (RefPicList)pcSlice->getListIdFromIdxOfLC(iRefIndex), pcSlice->getRefIdxFromIdxOfLC(iRefIndex) ) ); printf( " " ); } else printf ("%d ", pcSlice->getRefPOC((RefPicList)pcSlice->getListIdFromIdxOfLC(iRefIndex), pcSlice->getRefIdxFromIdxOfLC(iRefIndex))); } printf ("] "); } #endif #if FIXED_ROUNDING_FRAME_MEMORY rpcPic->getPicYuvRec()->xFixedRoundingPic(); #endif if (m_pictureDigestEnabled) { calcAndPrintMD5Status(*rpcPic->getPicYuvRec(), rpcPic->getSEIs()); } rpcPic->setReconMark(true); #if MTK_NONCROSS_INLOOP_FILTER uiILSliceCount = 0; #endif } } /** * Calculate and print MD5 for @pic, compare to picture_digest SEI if * present in @seis. @seis may be NULL. MD5 is printed to stdout, in * a manner suitable for the status line. Theformat is: * [MD5:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,(yyy)] * Where, x..x is the md5 * yyy has the following meanings: * OK - calculated MD5 matches the SEI message * ***ERROR*** - calculated MD5 does not match the SEI message * unk - no SEI message was available for comparison */ static void calcAndPrintMD5Status(TComPicYuv& pic, const SEImessages* seis) { /* calculate MD5sum for entire reconstructed picture */ unsigned char recon_digest[16]; calcMD5(pic, recon_digest); /* compare digest against received version */ const char* md5_ok = "(unk)"; bool md5_mismatch = false; if (seis && seis->picture_digest) { md5_ok = "(OK)"; for (unsigned i = 0; i < 16; i++) { if (recon_digest[i] != seis->picture_digest->digest[i]) { md5_ok = "(***ERROR***)"; md5_mismatch = true; } } } printf("[MD5:%s,%s] ", digestToString(recon_digest), md5_ok); if (md5_mismatch) { g_md5_mismatch = true; printf("[rxMD5:%s] ", digestToString(seis->picture_digest->digest)); } }