Void TDecSlice::decompressSlice(TComInputBitstream* pcBitstream, TComPic*& rpcPic) { TComDataCU* pcCU; UInt uiIsLast = 0; #if FINE_GRANULARITY_SLICES Int iStartCUAddr = max(rpcPic->getSlice(rpcPic->getCurrSliceIdx())->getSliceCurStartCUAddr()/rpcPic->getNumPartInCU(), rpcPic->getSlice(rpcPic->getCurrSliceIdx())->getEntropySliceCurStartCUAddr()/rpcPic->getNumPartInCU()); #else Int iStartCUAddr = max(rpcPic->getSlice(rpcPic->getCurrSliceIdx())->getSliceCurStartCUAddr(), rpcPic->getSlice(rpcPic->getCurrSliceIdx())->getEntropySliceCurStartCUAddr()); #endif // decoder don't need prediction & residual frame buffer rpcPic->setPicYuvPred( 0 ); rpcPic->setPicYuvResi( 0 ); #if ENC_DEC_TRACE g_bJustDoIt = g_bEncDecTraceEnable; #endif DTRACE_CABAC_VL( g_nSymbolCounter++ ); DTRACE_CABAC_T( "\tPOC: " ); DTRACE_CABAC_V( rpcPic->getPOC() ); DTRACE_CABAC_T( "\n" ); #if ENC_DEC_TRACE g_bJustDoIt = g_bEncDecTraceDisable; #endif // for all CUs in slice UInt uiLastCUAddr = iStartCUAddr; for( Int iCUAddr = iStartCUAddr; !uiIsLast && iCUAddr < rpcPic->getNumCUsInFrame(); iCUAddr++, uiLastCUAddr++ ) { pcCU = rpcPic->getCU( iCUAddr ); pcCU->initCU( rpcPic, iCUAddr ); #if ENC_DEC_TRACE g_bJustDoIt = g_bEncDecTraceEnable; #endif m_pcCuDecoder->decodeCU ( pcCU, uiIsLast ); m_pcCuDecoder->decompressCU ( pcCU ); #if ENC_DEC_TRACE g_bJustDoIt = g_bEncDecTraceDisable; #endif } }
Void TEncEntropy::xEncodeTransform( Bool& bCodeDQP, Bool& codeChromaQpAdj, TComTU &rTu ) { //pcCU, absPartIdxCU, uiAbsPartIdx, uiDepth+1, uiTrIdx+1, quadrant, TComDataCU *pcCU=rTu.getCU(); const UInt uiAbsPartIdx=rTu.GetAbsPartIdxTU(); const UInt numValidComponent = pcCU->getPic()->getNumberValidComponents(); const Bool bChroma = isChromaEnabled(pcCU->getPic()->getChromaFormat()); const UInt uiTrIdx = rTu.GetTransformDepthRel(); const UInt uiDepth = rTu.GetTransformDepthTotal(); #if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST const Bool bDebugRQT=pcCU->getSlice()->getFinalized() && DebugOptionList::DebugRQT.getInt()!=0; if (bDebugRQT) { printf("x..codeTransform: offsetLuma=%d offsetChroma=%d absPartIdx=%d, uiDepth=%d\n width=%d, height=%d, uiTrIdx=%d, uiInnerQuadIdx=%d\n", rTu.getCoefficientOffset(COMPONENT_Y), rTu.getCoefficientOffset(COMPONENT_Cb), uiAbsPartIdx, uiDepth, rTu.getRect(COMPONENT_Y).width, rTu.getRect(COMPONENT_Y).height, rTu.GetTransformDepthRel(), rTu.GetSectionNumber()); } #endif const UInt uiSubdiv = pcCU->getTransformIdx( uiAbsPartIdx ) > uiTrIdx;// + pcCU->getDepth( uiAbsPartIdx ) > uiDepth; const UInt uiLog2TrafoSize = rTu.GetLog2LumaTrSize(); UInt cbf[MAX_NUM_COMPONENT] = {0,0,0}; Bool bHaveACodedBlock = false; Bool bHaveACodedChromaBlock = false; for(UInt ch=0; ch<numValidComponent; ch++) { const ComponentID compID = ComponentID(ch); cbf[compID] = pcCU->getCbf( uiAbsPartIdx, compID , uiTrIdx ); if (cbf[ch] != 0) { bHaveACodedBlock = true; if (isChroma(compID)) { bHaveACodedChromaBlock = true; } } } if( pcCU->isIntra(uiAbsPartIdx) && pcCU->getPartitionSize(uiAbsPartIdx) == SIZE_NxN && uiDepth == pcCU->getDepth(uiAbsPartIdx) ) { assert( uiSubdiv ); } else if( pcCU->isInter(uiAbsPartIdx) && (pcCU->getPartitionSize(uiAbsPartIdx) != SIZE_2Nx2N) && uiDepth == pcCU->getDepth(uiAbsPartIdx) && (pcCU->getSlice()->getSPS()->getQuadtreeTUMaxDepthInter() == 1) ) { if ( uiLog2TrafoSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) ) { assert( uiSubdiv ); } else { assert(!uiSubdiv ); } } else if( uiLog2TrafoSize > pcCU->getSlice()->getSPS()->getQuadtreeTULog2MaxSize() ) { assert( uiSubdiv ); } else if( uiLog2TrafoSize == pcCU->getSlice()->getSPS()->getQuadtreeTULog2MinSize() ) { assert( !uiSubdiv ); } else if( uiLog2TrafoSize == pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) ) { assert( !uiSubdiv ); } else { assert( uiLog2TrafoSize > pcCU->getQuadtreeTULog2MinSizeInCU(uiAbsPartIdx) ); m_pcEntropyCoderIf->codeTransformSubdivFlag( uiSubdiv, 5 - uiLog2TrafoSize ); } const UInt uiTrDepthCurr = uiDepth - pcCU->getDepth( uiAbsPartIdx ); const Bool bFirstCbfOfCU = uiTrDepthCurr == 0; for(UInt ch=COMPONENT_Cb; ch<numValidComponent; ch++) { const ComponentID compID=ComponentID(ch); if( bFirstCbfOfCU || rTu.ProcessingAllQuadrants(compID) ) { if( bFirstCbfOfCU || pcCU->getCbf( uiAbsPartIdx, compID, uiTrDepthCurr - 1 ) ) { m_pcEntropyCoderIf->codeQtCbf( rTu, compID, (uiSubdiv == 0) ); } } else { assert( pcCU->getCbf( uiAbsPartIdx, compID, uiTrDepthCurr ) == pcCU->getCbf( uiAbsPartIdx, compID, uiTrDepthCurr - 1 ) ); } } if( uiSubdiv ) { TComTURecurse tuRecurseChild(rTu, true); do { xEncodeTransform( bCodeDQP, codeChromaQpAdj, tuRecurseChild ); } while (tuRecurseChild.nextSection(rTu)); } else { { DTRACE_CABAC_VL( g_nSymbolCounter++ ); DTRACE_CABAC_T( "\tTrIdx: abspart=" ); DTRACE_CABAC_V( uiAbsPartIdx ); DTRACE_CABAC_T( "\tdepth=" ); DTRACE_CABAC_V( uiDepth ); DTRACE_CABAC_T( "\ttrdepth=" ); DTRACE_CABAC_V( pcCU->getTransformIdx( uiAbsPartIdx ) ); DTRACE_CABAC_T( "\n" ); } if( !pcCU->isIntra(uiAbsPartIdx) && uiDepth == pcCU->getDepth( uiAbsPartIdx ) && (!bChroma || (!pcCU->getCbf( uiAbsPartIdx, COMPONENT_Cb, 0 ) && !pcCU->getCbf( uiAbsPartIdx, COMPONENT_Cr, 0 ) ) ) ) { assert( pcCU->getCbf( uiAbsPartIdx, COMPONENT_Y, 0 ) ); // printf( "saved one bin! " ); } else { m_pcEntropyCoderIf->codeQtCbf( rTu, COMPONENT_Y, true ); //luma CBF is always at the lowest level } if ( bHaveACodedBlock ) { // dQP: only for CTU once if ( pcCU->getSlice()->getPPS()->getUseDQP() ) { if ( bCodeDQP ) { encodeQP( pcCU, rTu.GetAbsPartIdxCU() ); bCodeDQP = false; } } if ( pcCU->getSlice()->getUseChromaQpAdj() ) { if ( bHaveACodedChromaBlock && codeChromaQpAdj && !pcCU->getCUTransquantBypass(rTu.GetAbsPartIdxCU()) ) { encodeChromaQpAdjustment( pcCU, rTu.GetAbsPartIdxCU() ); codeChromaQpAdj = false; } } const UInt numValidComp=pcCU->getPic()->getNumberValidComponents(); for(UInt ch=COMPONENT_Y; ch<numValidComp; ch++) { const ComponentID compID=ComponentID(ch); if (rTu.ProcessComponentSection(compID)) { #if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST if (bDebugRQT) { printf("Call NxN for chan %d width=%d height=%d cbf=%d\n", compID, rTu.getRect(compID).width, rTu.getRect(compID).height, 1); } #endif if (rTu.getRect(compID).width != rTu.getRect(compID).height) { //code two sub-TUs TComTURecurse subTUIterator(rTu, false, TComTU::VERTICAL_SPLIT, true, compID); do { const UChar subTUCBF = pcCU->getCbf(subTUIterator.GetAbsPartIdxTU(compID), compID, (uiTrIdx + 1)); if (subTUCBF != 0) { #if ENVIRONMENT_VARIABLE_DEBUG_AND_TEST if (bDebugRQT) { printf("Call NxN for chan %d width=%d height=%d cbf=%d\n", compID, subTUIterator.getRect(compID).width, subTUIterator.getRect(compID).height, 1); } #endif m_pcEntropyCoderIf->codeCoeffNxN( subTUIterator, (pcCU->getCoeff(compID) + subTUIterator.getCoefficientOffset(compID)), compID ); } } while (subTUIterator.nextSection(rTu)); } else { if (isChroma(compID) && (cbf[COMPONENT_Y] != 0)) { m_pcEntropyCoderIf->codeCrossComponentPrediction( rTu, compID ); } if (cbf[compID] != 0) { m_pcEntropyCoderIf->codeCoeffNxN( rTu, (pcCU->getCoeff(compID) + rTu.getCoefficientOffset(compID)), compID ); } } } } } } }
Void TDecSlice::decompressSlice(TComInputBitstream** ppcSubstreams, TComPic* pcPic, TDecSbac* pcSbacDecoder) { TComSlice* pcSlice = pcPic->getSlice(pcPic->getCurrSliceIdx()); const Int startCtuTsAddr = pcSlice->getSliceSegmentCurStartCtuTsAddr(); const Int startCtuRsAddr = pcPic->getPicSym()->getCtuTsToRsAddrMap(startCtuTsAddr); const UInt numCtusInFrame = pcPic->getNumberOfCtusInFrame(); const UInt frameWidthInCtus = pcPic->getPicSym()->getFrameWidthInCtus(); const Bool depSliceSegmentsEnabled = pcSlice->getPPS()->getDependentSliceSegmentsEnabledFlag(); const Bool wavefrontsEnabled = pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag(); m_pcEntropyDecoder->setEntropyDecoder ( pcSbacDecoder ); m_pcEntropyDecoder->setBitstream ( ppcSubstreams[0] ); m_pcEntropyDecoder->resetEntropy (pcSlice); // decoder doesn't need prediction & residual frame buffer pcPic->setPicYuvPred( 0 ); pcPic->setPicYuvResi( 0 ); #if ENC_DEC_TRACE g_bJustDoIt = g_bEncDecTraceEnable; #endif DTRACE_CABAC_VL( g_nSymbolCounter++ ); DTRACE_CABAC_T( "\tPOC: " ); DTRACE_CABAC_V( pcPic->getPOC() ); DTRACE_CABAC_T( "\n" ); #if ENC_DEC_TRACE g_bJustDoIt = g_bEncDecTraceDisable; #endif // The first CTU of the slice is the first coded substream, but the global substream number, as calculated by getSubstreamForCtuAddr may be higher. // This calculates the common offset for all substreams in this slice. const UInt subStreamOffset=pcPic->getSubstreamForCtuAddr(startCtuRsAddr, true, pcSlice); if (depSliceSegmentsEnabled) { // modify initial contexts with previous slice segment if this is a dependent slice. const UInt startTileIdx=pcPic->getPicSym()->getTileIdxMap(startCtuRsAddr); const TComTile *pCurrentTile=pcPic->getPicSym()->getTComTile(startTileIdx); const UInt firstCtuRsAddrOfTile = pCurrentTile->getFirstCtuRsAddr(); if( pcSlice->getDependentSliceSegmentFlag() && startCtuRsAddr != firstCtuRsAddrOfTile) { if ( pCurrentTile->getTileWidthInCtus() >= 2 || !wavefrontsEnabled) { pcSbacDecoder->loadContexts(&m_lastSliceSegmentEndContextState); } } } // for every CTU in the slice segment... Bool isLastCtuOfSliceSegment = false; for( UInt ctuTsAddr = startCtuTsAddr; !isLastCtuOfSliceSegment && ctuTsAddr < numCtusInFrame; ctuTsAddr++) { const UInt ctuRsAddr = pcPic->getPicSym()->getCtuTsToRsAddrMap(ctuTsAddr); const TComTile ¤tTile = *(pcPic->getPicSym()->getTComTile(pcPic->getPicSym()->getTileIdxMap(ctuRsAddr))); const UInt firstCtuRsAddrOfTile = currentTile.getFirstCtuRsAddr(); const UInt tileXPosInCtus = firstCtuRsAddrOfTile % frameWidthInCtus; const UInt tileYPosInCtus = firstCtuRsAddrOfTile / frameWidthInCtus; const UInt ctuXPosInCtus = ctuRsAddr % frameWidthInCtus; const UInt ctuYPosInCtus = ctuRsAddr / frameWidthInCtus; const UInt uiSubStrm=pcPic->getSubstreamForCtuAddr(ctuRsAddr, true, pcSlice)-subStreamOffset; TComDataCU* pCtu = pcPic->getCtu( ctuRsAddr ); pCtu->initCtu( pcPic, ctuRsAddr ); m_pcEntropyDecoder->setBitstream( ppcSubstreams[uiSubStrm] ); // set up CABAC contexts' state for this CTU if (ctuRsAddr == firstCtuRsAddrOfTile) { if (ctuTsAddr != startCtuTsAddr) // if it is the first CTU, then the entropy coder has already been reset { m_pcEntropyDecoder->resetEntropy(pcSlice); } } else if (ctuXPosInCtus == tileXPosInCtus && wavefrontsEnabled) { // Synchronize cabac probabilities with upper-right CTU if it's available and at the start of a line. if (ctuTsAddr != startCtuTsAddr) // if it is the first CTU, then the entropy coder has already been reset { m_pcEntropyDecoder->resetEntropy(pcSlice); } TComDataCU *pCtuUp = pCtu->getCtuAbove(); if ( pCtuUp && ((ctuRsAddr%frameWidthInCtus+1) < frameWidthInCtus) ) { TComDataCU *pCtuTR = pcPic->getCtu( ctuRsAddr - frameWidthInCtus + 1 ); if ( pCtu->CUIsFromSameSliceAndTile(pCtuTR) ) { // Top-right is available, so use it. pcSbacDecoder->loadContexts( &m_entropyCodingSyncContextState ); } } } #if ENC_DEC_TRACE g_bJustDoIt = g_bEncDecTraceEnable; #endif if ( pcSlice->getSPS()->getUseSAO() ) { SAOBlkParam& saoblkParam = (pcPic->getPicSym()->getSAOBlkParam())[ctuRsAddr]; Bool bIsSAOSliceEnabled = false; Bool sliceEnabled[MAX_NUM_COMPONENT]; for(Int comp=0; comp < MAX_NUM_COMPONENT; comp++) { ComponentID compId=ComponentID(comp); sliceEnabled[compId] = pcSlice->getSaoEnabledFlag(toChannelType(compId)) && (comp < pcPic->getNumberValidComponents()); if (sliceEnabled[compId]) bIsSAOSliceEnabled=true; saoblkParam[compId].modeIdc = SAO_MODE_OFF; } if (bIsSAOSliceEnabled) { Bool leftMergeAvail = false; Bool aboveMergeAvail= false; //merge left condition Int rx = (ctuRsAddr % frameWidthInCtus); if(rx > 0) { leftMergeAvail = pcPic->getSAOMergeAvailability(ctuRsAddr, ctuRsAddr-1); } //merge up condition Int ry = (ctuRsAddr / frameWidthInCtus); if(ry > 0) { aboveMergeAvail = pcPic->getSAOMergeAvailability(ctuRsAddr, ctuRsAddr-frameWidthInCtus); } #if SVC_EXTENSION pcSbacDecoder->parseSAOBlkParam( saoblkParam, m_saoMaxOffsetQVal, sliceEnabled, leftMergeAvail, aboveMergeAvail); #else pcSbacDecoder->parseSAOBlkParam( saoblkParam, sliceEnabled, leftMergeAvail, aboveMergeAvail); #endif } } m_pcCuDecoder->decodeCtu ( pCtu, isLastCtuOfSliceSegment ); m_pcCuDecoder->decompressCtu ( pCtu ); #if ENC_DEC_TRACE g_bJustDoIt = g_bEncDecTraceDisable; #endif //Store probabilities of second CTU in line into buffer if ( ctuXPosInCtus == tileXPosInCtus+1 && wavefrontsEnabled) { m_entropyCodingSyncContextState.loadContexts( pcSbacDecoder ); } // Should the sub-stream/stream be terminated after this CTU? // (end of slice-segment, end of tile, end of wavefront-CTU-row) if (isLastCtuOfSliceSegment || ( ctuXPosInCtus + 1 == tileXPosInCtus + currentTile.getTileWidthInCtus() && ( ctuYPosInCtus + 1 == tileYPosInCtus + currentTile.getTileHeightInCtus() || wavefrontsEnabled) ) ) { UInt binVal; pcSbacDecoder->parseTerminatingBit( binVal ); assert( binVal ); #if DECODER_CHECK_SUBSTREAM_AND_SLICE_TRAILING_BYTES pcSbacDecoder->parseRemainingBytes(!isLastCtuOfSliceSegment); #endif if (isLastCtuOfSliceSegment) { if(!pcSlice->getDependentSliceSegmentFlag()) { pcSlice->setSliceCurEndCtuTsAddr( ctuTsAddr+1 ); } pcSlice->setSliceSegmentCurEndCtuTsAddr( ctuTsAddr+1 ); break; } } } assert(isLastCtuOfSliceSegment == true); if( depSliceSegmentsEnabled ) { m_lastSliceSegmentEndContextState.loadContexts( pcSbacDecoder );//ctx end of dep.slice } }
Void TDecSlice::decompressSlice(TComInputBitstream** ppcSubstreams, TComPic*& rpcPic, TDecSbac* pcSbacDecoder, TDecSbac* pcSbacDecoders) { TComDataCU* pcCU; UInt uiIsLast = 0; Int iStartCUEncOrder = max(rpcPic->getSlice(rpcPic->getCurrSliceIdx())->getSliceCurStartCUAddr()/rpcPic->getNumPartInCU(), rpcPic->getSlice(rpcPic->getCurrSliceIdx())->getSliceSegmentCurStartCUAddr()/rpcPic->getNumPartInCU()); Int iStartCUAddr = rpcPic->getPicSym()->getCUOrderMap(iStartCUEncOrder); // decoder don't need prediction & residual frame buffer #if ENABLE_ANAYSIS_OUTPUT #else rpcPic->setPicYuvPred( 0 ); rpcPic->setPicYuvResi( 0 ); #endif #if ENC_DEC_TRACE g_bJustDoIt = g_bEncDecTraceEnable; #endif DTRACE_CABAC_VL( g_nSymbolCounter++ ); DTRACE_CABAC_T( "\tPOC: " ); DTRACE_CABAC_V( rpcPic->getPOC() ); DTRACE_CABAC_T( "\n" ); #if ENC_DEC_TRACE g_bJustDoIt = g_bEncDecTraceDisable; #endif UInt uiTilesAcross = rpcPic->getPicSym()->getNumColumnsMinus1()+1; TComSlice* pcSlice = rpcPic->getSlice(rpcPic->getCurrSliceIdx()); Int iNumSubstreams = pcSlice->getPPS()->getNumSubstreams(); // delete decoders if already allocated in previous slice if (m_pcBufferSbacDecoders) { delete [] m_pcBufferSbacDecoders; } if (m_pcBufferBinCABACs) { delete [] m_pcBufferBinCABACs; } // allocate new decoders based on tile numbaer m_pcBufferSbacDecoders = new TDecSbac [uiTilesAcross]; m_pcBufferBinCABACs = new TDecBinCABAC[uiTilesAcross]; for (UInt ui = 0; ui < uiTilesAcross; ui++) { m_pcBufferSbacDecoders[ui].init(&m_pcBufferBinCABACs[ui]); } //save init. state for (UInt ui = 0; ui < uiTilesAcross; ui++) { m_pcBufferSbacDecoders[ui].load(pcSbacDecoder); } // free memory if already allocated in previous call if (m_pcBufferLowLatSbacDecoders) { delete [] m_pcBufferLowLatSbacDecoders; } if (m_pcBufferLowLatBinCABACs) { delete [] m_pcBufferLowLatBinCABACs; } m_pcBufferLowLatSbacDecoders = new TDecSbac [uiTilesAcross]; m_pcBufferLowLatBinCABACs = new TDecBinCABAC[uiTilesAcross]; for (UInt ui = 0; ui < uiTilesAcross; ui++) { m_pcBufferLowLatSbacDecoders[ui].init(&m_pcBufferLowLatBinCABACs[ui]); } //save init. state for (UInt ui = 0; ui < uiTilesAcross; ui++) { m_pcBufferLowLatSbacDecoders[ui].load(pcSbacDecoder); } UInt uiWidthInLCUs = rpcPic->getPicSym()->getFrameWidthInCU(); //UInt uiHeightInLCUs = rpcPic->getPicSym()->getFrameHeightInCU(); UInt uiCol=0, uiLin=0, uiSubStrm=0; UInt uiTileCol; UInt uiTileStartLCU; UInt uiTileLCUX; Int iNumSubstreamsPerTile = 1; // if independent. Bool depSliceSegmentsEnabled = rpcPic->getSlice(rpcPic->getCurrSliceIdx())->getPPS()->getDependentSliceSegmentsEnabledFlag(); uiTileStartLCU = rpcPic->getPicSym()->getTComTile(rpcPic->getPicSym()->getTileIdxMap(iStartCUAddr))->getFirstCUAddr(); if( depSliceSegmentsEnabled ) { if( (!rpcPic->getSlice(rpcPic->getCurrSliceIdx())->isNextSlice()) && iStartCUAddr != rpcPic->getPicSym()->getTComTile(rpcPic->getPicSym()->getTileIdxMap(iStartCUAddr))->getFirstCUAddr()) { if(pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag()) { uiTileCol = rpcPic->getPicSym()->getTileIdxMap(iStartCUAddr) % (rpcPic->getPicSym()->getNumColumnsMinus1()+1); m_pcBufferSbacDecoders[uiTileCol].loadContexts( CTXMem[1] );//2.LCU if ( (iStartCUAddr%uiWidthInLCUs+1) >= uiWidthInLCUs ) { uiTileLCUX = uiTileStartLCU % uiWidthInLCUs; uiCol = iStartCUAddr % uiWidthInLCUs; if(uiCol==uiTileLCUX) { CTXMem[0]->loadContexts(pcSbacDecoder); } } } pcSbacDecoder->loadContexts(CTXMem[0] ); //end of depSlice-1 pcSbacDecoders[uiSubStrm].loadContexts(pcSbacDecoder); } else { if(pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag()) { CTXMem[1]->loadContexts(pcSbacDecoder); } CTXMem[0]->loadContexts(pcSbacDecoder); } } for( Int iCUAddr = iStartCUAddr; !uiIsLast && iCUAddr < rpcPic->getNumCUsInFrame(); iCUAddr = rpcPic->getPicSym()->xCalculateNxtCUAddr(iCUAddr) ) { pcCU = rpcPic->getCU( iCUAddr ); pcCU->initCU( rpcPic, iCUAddr ); uiTileCol = rpcPic->getPicSym()->getTileIdxMap(iCUAddr) % (rpcPic->getPicSym()->getNumColumnsMinus1()+1); // what column of tiles are we in? uiTileStartLCU = rpcPic->getPicSym()->getTComTile(rpcPic->getPicSym()->getTileIdxMap(iCUAddr))->getFirstCUAddr(); uiTileLCUX = uiTileStartLCU % uiWidthInLCUs; uiCol = iCUAddr % uiWidthInLCUs; // The 'line' is now relative to the 1st line in the slice, not the 1st line in the picture. uiLin = (iCUAddr/uiWidthInLCUs)-(iStartCUAddr/uiWidthInLCUs); // inherit from TR if necessary, select substream to use. if( (pcSlice->getPPS()->getNumSubstreams() > 1) || ( depSliceSegmentsEnabled && (uiCol == uiTileLCUX)&&(pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag()) )) { // independent tiles => substreams are "per tile". iNumSubstreams has already been multiplied. iNumSubstreamsPerTile = iNumSubstreams/rpcPic->getPicSym()->getNumTiles(); uiSubStrm = rpcPic->getPicSym()->getTileIdxMap(iCUAddr)*iNumSubstreamsPerTile + uiLin%iNumSubstreamsPerTile; m_pcEntropyDecoder->setBitstream( ppcSubstreams[uiSubStrm] ); // Synchronize cabac probabilities with upper-right LCU if it's available and we're at the start of a line. if (((pcSlice->getPPS()->getNumSubstreams() > 1) || depSliceSegmentsEnabled ) && (uiCol == uiTileLCUX)&&(pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag())) { // We'll sync if the TR is available. TComDataCU *pcCUUp = pcCU->getCUAbove(); UInt uiWidthInCU = rpcPic->getFrameWidthInCU(); TComDataCU *pcCUTR = NULL; if ( pcCUUp && ((iCUAddr%uiWidthInCU+1) < uiWidthInCU) ) { pcCUTR = rpcPic->getCU( iCUAddr - uiWidthInCU + 1 ); } UInt uiMaxParts = 1<<(pcSlice->getSPS()->getMaxCUDepth()<<1); if ( (true/*bEnforceSliceRestriction*/ && ((pcCUTR==NULL) || (pcCUTR->getSlice()==NULL) || ((pcCUTR->getSCUAddr()+uiMaxParts-1) < pcSlice->getSliceCurStartCUAddr()) || ((rpcPic->getPicSym()->getTileIdxMap( pcCUTR->getAddr() ) != rpcPic->getPicSym()->getTileIdxMap(iCUAddr))) )) ) { // TR not available. } else { // TR is available, we use it. pcSbacDecoders[uiSubStrm].loadContexts( &m_pcBufferSbacDecoders[uiTileCol] ); } } pcSbacDecoder->load(&pcSbacDecoders[uiSubStrm]); //this load is used to simplify the code (avoid to change all the call to pcSbacDecoders) } else if ( pcSlice->getPPS()->getNumSubstreams() <= 1 ) { // Set variables to appropriate values to avoid later code change. iNumSubstreamsPerTile = 1; } if ( (iCUAddr == rpcPic->getPicSym()->getTComTile(rpcPic->getPicSym()->getTileIdxMap(iCUAddr))->getFirstCUAddr()) && // 1st in tile. (iCUAddr!=0) && (iCUAddr!=rpcPic->getPicSym()->getPicSCUAddr(rpcPic->getSlice(rpcPic->getCurrSliceIdx())->getSliceCurStartCUAddr())/rpcPic->getNumPartInCU()) && (iCUAddr!=rpcPic->getPicSym()->getPicSCUAddr(rpcPic->getSlice(rpcPic->getCurrSliceIdx())->getSliceSegmentCurStartCUAddr())/rpcPic->getNumPartInCU()) ) // !1st in frame && !1st in slice { if (pcSlice->getPPS()->getNumSubstreams() > 1) { // We're crossing into another tile, tiles are independent. // When tiles are independent, we have "substreams per tile". Each substream has already been terminated, and we no longer // have to perform it here. // For TILES_DECODER, there can be a header at the start of the 1st substream in a tile. These are read when the substreams // are extracted, not here. } else { SliceType sliceType = pcSlice->getSliceType(); if (pcSlice->getCabacInitFlag()) { switch (sliceType) { case P_SLICE: // change initialization table to B_SLICE intialization sliceType = B_SLICE; break; case B_SLICE: // change initialization table to P_SLICE intialization sliceType = P_SLICE; break; default : // should not occur assert(0); } } m_pcEntropyDecoder->updateContextTables( sliceType, pcSlice->getSliceQp() ); } } #if ENC_DEC_TRACE g_bJustDoIt = g_bEncDecTraceEnable; #endif if ( pcSlice->getSPS()->getUseSAO() && (pcSlice->getSaoEnabledFlag()||pcSlice->getSaoEnabledFlagChroma()) ) { SAOParam *saoParam = rpcPic->getPicSym()->getSaoParam(); saoParam->bSaoFlag[0] = pcSlice->getSaoEnabledFlag(); if (iCUAddr == iStartCUAddr) { saoParam->bSaoFlag[1] = pcSlice->getSaoEnabledFlagChroma(); } Int numCuInWidth = saoParam->numCuInWidth; Int cuAddrInSlice = iCUAddr - rpcPic->getPicSym()->getCUOrderMap(pcSlice->getSliceCurStartCUAddr()/rpcPic->getNumPartInCU()); Int cuAddrUpInSlice = cuAddrInSlice - numCuInWidth; Int rx = iCUAddr % numCuInWidth; Int ry = iCUAddr / numCuInWidth; Int allowMergeLeft = 1; Int allowMergeUp = 1; if (rx!=0) { if (rpcPic->getPicSym()->getTileIdxMap(iCUAddr-1) != rpcPic->getPicSym()->getTileIdxMap(iCUAddr)) { allowMergeLeft = 0; } } if (ry!=0) { if (rpcPic->getPicSym()->getTileIdxMap(iCUAddr-numCuInWidth) != rpcPic->getPicSym()->getTileIdxMap(iCUAddr)) { allowMergeUp = 0; } } pcSbacDecoder->parseSaoOneLcuInterleaving(rx, ry, saoParam,pcCU, cuAddrInSlice, cuAddrUpInSlice, allowMergeLeft, allowMergeUp); } else if ( pcSlice->getSPS()->getUseSAO() ) { Int addr = pcCU->getAddr(); SAOParam *saoParam = rpcPic->getPicSym()->getSaoParam(); for (Int cIdx=0; cIdx<3; cIdx++) { SaoLcuParam *saoLcuParam = &(saoParam->saoLcuParam[cIdx][addr]); if ( ((cIdx == 0) && !pcSlice->getSaoEnabledFlag()) || ((cIdx == 1 || cIdx == 2) && !pcSlice->getSaoEnabledFlagChroma())) { saoLcuParam->mergeUpFlag = 0; saoLcuParam->mergeLeftFlag = 0; saoLcuParam->subTypeIdx = 0; saoLcuParam->typeIdx = -1; saoLcuParam->offset[0] = 0; saoLcuParam->offset[1] = 0; saoLcuParam->offset[2] = 0; saoLcuParam->offset[3] = 0; } } } #if ENABLE_ANAYSIS_OUTPUT UInt uiBefore = ppcSubstreams[uiSubStrm]->getByteLocation(); #endif m_pcCuDecoder->decodeCU ( pcCU, uiIsLast ); #if ENABLE_ANAYSIS_OUTPUT pcCU->getTotalBits() = ppcSubstreams[uiSubStrm]->getByteLocation() - uiBefore; #endif m_pcCuDecoder->decompressCU ( pcCU ); #if ENC_DEC_TRACE g_bJustDoIt = g_bEncDecTraceDisable; #endif pcSbacDecoders[uiSubStrm].load(pcSbacDecoder); //Store probabilities of second LCU in line into buffer if ( (uiCol == uiTileLCUX+1)&& (depSliceSegmentsEnabled || (pcSlice->getPPS()->getNumSubstreams() > 1)) && (pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag()) ) { m_pcBufferSbacDecoders[uiTileCol].loadContexts( &pcSbacDecoders[uiSubStrm] ); } if( uiIsLast && depSliceSegmentsEnabled ) { if (pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag()) { CTXMem[1]->loadContexts( &m_pcBufferSbacDecoders[uiTileCol] );//ctx 2.LCU } CTXMem[0]->loadContexts( pcSbacDecoder );//ctx end of dep.slice return; } } }
Void TDecSlice::decompressSlice(TComInputBitstream* pcBitstream, TComInputBitstream** ppcSubstreams, TComPic*& rpcPic, TDecSbac* pcSbacDecoder, TDecSbac* pcSbacDecoders) { TComDataCU* pcCU; UInt uiIsLast = 0; Int iStartCUEncOrder = max(rpcPic->getSlice(rpcPic->getCurrSliceIdx())->getSliceCurStartCUAddr()/rpcPic->getNumPartInCU(), rpcPic->getSlice(rpcPic->getCurrSliceIdx())->getEntropySliceCurStartCUAddr()/rpcPic->getNumPartInCU()); Int iStartCUAddr = rpcPic->getPicSym()->getCUOrderMap(iStartCUEncOrder); // decoder don't need prediction & residual frame buffer rpcPic->setPicYuvPred( 0 ); rpcPic->setPicYuvResi( 0 ); #if ENC_DEC_TRACE g_bJustDoIt = g_bEncDecTraceEnable; #endif DTRACE_CABAC_VL( g_nSymbolCounter++ ); DTRACE_CABAC_T( "\tPOC: " ); DTRACE_CABAC_V( rpcPic->getPOC() ); DTRACE_CABAC_T( "\n" ); #if ENC_DEC_TRACE g_bJustDoIt = g_bEncDecTraceDisable; #endif UInt uiTilesAcross = rpcPic->getPicSym()->getNumColumnsMinus1()+1; TComSlice* pcSlice = rpcPic->getSlice(rpcPic->getCurrSliceIdx()); UInt iSymbolMode = pcSlice->getPPS()->getEntropyCodingMode(); Int iNumSubstreams = pcSlice->getPPS()->getNumSubstreams(); if( iSymbolMode ) { m_pcBufferSbacDecoders = new TDecSbac [uiTilesAcross]; m_pcBufferBinCABACs = new TDecBinCABAC[uiTilesAcross]; for (UInt ui = 0; ui < uiTilesAcross; ui++) { m_pcBufferSbacDecoders[ui].init(&m_pcBufferBinCABACs[ui]); } //save init. state for (UInt ui = 0; ui < uiTilesAcross; ui++) { m_pcBufferSbacDecoders[ui].load(pcSbacDecoder); } } if( iSymbolMode ) { m_pcBufferLowLatSbacDecoders = new TDecSbac [uiTilesAcross]; m_pcBufferLowLatBinCABACs = new TDecBinCABAC[uiTilesAcross]; for (UInt ui = 0; ui < uiTilesAcross; ui++) m_pcBufferLowLatSbacDecoders[ui].init(&m_pcBufferLowLatBinCABACs[ui]); //save init. state for (UInt ui = 0; ui < uiTilesAcross; ui++) m_pcBufferLowLatSbacDecoders[ui].load(pcSbacDecoder); } UInt uiWidthInLCUs = rpcPic->getPicSym()->getFrameWidthInCU(); //UInt uiHeightInLCUs = rpcPic->getPicSym()->getFrameHeightInCU(); UInt uiCol=0, uiLin=0, uiSubStrm=0; UInt uiTileCol; UInt uiTileStartLCU; UInt uiTileLCUX; UInt uiTileLCUY; UInt uiTileWidth; UInt uiTileHeight; Int iNumSubstreamsPerTile = 1; // if independent. for( Int iCUAddr = iStartCUAddr; !uiIsLast && iCUAddr < rpcPic->getNumCUsInFrame(); iCUAddr = rpcPic->getPicSym()->xCalculateNxtCUAddr(iCUAddr) ) { pcCU = rpcPic->getCU( iCUAddr ); pcCU->initCU( rpcPic, iCUAddr ); uiTileCol = rpcPic->getPicSym()->getTileIdxMap(iCUAddr) % (rpcPic->getPicSym()->getNumColumnsMinus1()+1); // what column of tiles are we in? uiTileStartLCU = rpcPic->getPicSym()->getTComTile(rpcPic->getPicSym()->getTileIdxMap(iCUAddr))->getFirstCUAddr(); uiTileLCUX = uiTileStartLCU % uiWidthInLCUs; uiTileLCUY = uiTileStartLCU / uiWidthInLCUs; uiTileWidth = rpcPic->getPicSym()->getTComTile(rpcPic->getPicSym()->getTileIdxMap(iCUAddr))->getTileWidth(); uiTileHeight = rpcPic->getPicSym()->getTComTile(rpcPic->getPicSym()->getTileIdxMap(iCUAddr))->getTileHeight(); uiCol = iCUAddr % uiWidthInLCUs; uiLin = iCUAddr / uiWidthInLCUs; // inherit from TR if necessary, select substream to use. if( iSymbolMode && pcSlice->getPPS()->getNumSubstreams() > 1 ) { if (pcSlice->getPPS()->getNumSubstreams() > 1) { // independent tiles => substreams are "per tile". iNumSubstreams has already been multiplied. iNumSubstreamsPerTile = iNumSubstreams/rpcPic->getPicSym()->getNumTiles(); uiSubStrm = rpcPic->getPicSym()->getTileIdxMap(iCUAddr)*iNumSubstreamsPerTile + uiLin%iNumSubstreamsPerTile; } else { // dependent tiles => substreams are "per frame". uiSubStrm = uiLin % iNumSubstreams; } m_pcEntropyDecoder->setBitstream( ppcSubstreams[uiSubStrm] ); // Synchronize cabac probabilities with upper-right LCU if it's available and we're at the start of a line. if (pcSlice->getPPS()->getNumSubstreams() > 1 && uiCol == uiTileLCUX) { // We'll sync if the TR is available. TComDataCU *pcCUUp = pcCU->getCUAbove(); UInt uiWidthInCU = rpcPic->getFrameWidthInCU(); TComDataCU *pcCUTR = NULL; if ( pcCUUp && ((iCUAddr%uiWidthInCU+1) < uiWidthInCU) ) { pcCUTR = rpcPic->getCU( iCUAddr - uiWidthInCU + 1 ); } UInt uiMaxParts = 1<<(pcSlice->getSPS()->getMaxCUDepth()<<1); if ( (true/*bEnforceSliceRestriction*/ && ((pcCUTR==NULL) || (pcCUTR->getSlice()==NULL) || ((pcCUTR->getSCUAddr()+uiMaxParts-1) < pcSlice->getSliceCurStartCUAddr()) || ((rpcPic->getPicSym()->getTileIdxMap( pcCUTR->getAddr() ) != rpcPic->getPicSym()->getTileIdxMap(iCUAddr))) ))|| (true/*bEnforceEntropySliceRestriction*/ && ((pcCUTR==NULL) || (pcCUTR->getSlice()==NULL) || ((pcCUTR->getSCUAddr()+uiMaxParts-1) < pcSlice->getEntropySliceCurStartCUAddr()) || ((rpcPic->getPicSym()->getTileIdxMap( pcCUTR->getAddr() ) != rpcPic->getPicSym()->getTileIdxMap(iCUAddr))) )) ) { // TR not available. } else { // TR is available, we use it. pcSbacDecoders[uiSubStrm].loadContexts( &m_pcBufferSbacDecoders[uiTileCol] ); } } pcSbacDecoder->load(&pcSbacDecoders[uiSubStrm]); //this load is used to simplify the code (avoid to change all the call to pcSbacDecoders) } else if ( iSymbolMode && pcSlice->getPPS()->getNumSubstreams() <= 1 ) { // Set variables to appropriate values to avoid later code change. iNumSubstreamsPerTile = 1; } if ( (iCUAddr == rpcPic->getPicSym()->getTComTile(rpcPic->getPicSym()->getTileIdxMap(iCUAddr))->getFirstCUAddr()) && // 1st in tile. (iCUAddr!=0) && (iCUAddr!=rpcPic->getPicSym()->getPicSCUAddr(rpcPic->getSlice(rpcPic->getCurrSliceIdx())->getSliceCurStartCUAddr())/rpcPic->getNumPartInCU())) // !1st in frame && !1st in slice { if (pcSlice->getPPS()->getNumSubstreams() > 1) { // We're crossing into another tile, tiles are independent. // When tiles are independent, we have "substreams per tile". Each substream has already been terminated, and we no longer // have to perform it here. // For TILES_DECODER, there can be a header at the start of the 1st substream in a tile. These are read when the substreams // are extracted, not here. } else { #if CABAC_INIT_FLAG SliceType sliceType = pcSlice->getSliceType(); if (pcSlice->getCabacInitFlag()) { switch (sliceType) { case P_SLICE: // change initialization table to B_SLICE intialization sliceType = B_SLICE; break; case B_SLICE: // change initialization table to P_SLICE intialization sliceType = P_SLICE; break; default : // should not occur assert(0); } } m_pcEntropyDecoder->updateContextTables( sliceType, pcSlice->getSliceQp() ); #else m_pcEntropyDecoder->updateContextTables( pcSlice->getSliceType(), pcSlice->getSliceQp() ); #endif } Bool bTileMarkerFoundFlag = false; TComInputBitstream *pcTmpPtr; pcTmpPtr = ppcSubstreams[uiSubStrm]; // for CABAC for (UInt uiIdx=0; uiIdx<pcTmpPtr->getTileMarkerLocationCount(); uiIdx++) { if ( pcTmpPtr->getByteLocation() == (pcTmpPtr->getTileMarkerLocation( uiIdx )+2) ) { bTileMarkerFoundFlag = true; break; } } if (bTileMarkerFoundFlag) { UInt uiTileIdx; // Read tile index m_pcEntropyDecoder->readTileMarker( uiTileIdx, rpcPic->getPicSym()->getBitsUsedByTileIdx() ); } } #if ENC_DEC_TRACE g_bJustDoIt = g_bEncDecTraceEnable; #endif if ( pcSlice->getSPS()->getUseSAO() && pcSlice->getSaoInterleavingFlag() && pcSlice->getSaoEnabledFlag() ) { pcSlice->getAPS()->getSaoParam()->bSaoFlag[0] = pcSlice->getSaoEnabledFlag(); if (iCUAddr == iStartCUAddr) { pcSlice->getAPS()->getSaoParam()->bSaoFlag[1] = pcSlice->getSaoEnabledFlagCb(); pcSlice->getAPS()->getSaoParam()->bSaoFlag[2] = pcSlice->getSaoEnabledFlagCr(); } Int numCuInWidth = pcSlice->getAPS()->getSaoParam()->numCuInWidth; Int cuAddrInSlice = iCUAddr - pcSlice->getSliceCurStartCUAddr()/rpcPic->getNumPartInCU(); Int cuAddrUpInSlice = cuAddrInSlice - numCuInWidth; Int rx = iCUAddr % numCuInWidth; Int ry = iCUAddr / numCuInWidth; pcSbacDecoder->parseSaoOneLcuInterleaving(rx, ry, pcSlice->getAPS()->getSaoParam(),pcCU, cuAddrInSlice, cuAddrUpInSlice, pcSlice->getSPS()->getLFCrossSliceBoundaryFlag() ); } m_pcCuDecoder->decodeCU ( pcCU, uiIsLast ); m_pcCuDecoder->decompressCU ( pcCU ); #if ENC_DEC_TRACE g_bJustDoIt = g_bEncDecTraceDisable; #endif if( iSymbolMode ) { /*If at the end of a LCU line but not at the end of a substream, perform CABAC flush*/ if (!uiIsLast && pcSlice->getPPS()->getNumSubstreams() > 1) { if ((uiCol == uiTileLCUX+uiTileWidth-1) && (uiLin+iNumSubstreamsPerTile < uiTileLCUY+uiTileHeight)) { m_pcEntropyDecoder->decodeFlush(); } } pcSbacDecoders[uiSubStrm].load(pcSbacDecoder); //Store probabilities of second LCU in line into buffer if (pcSlice->getPPS()->getNumSubstreams() > 1 && (uiCol == uiTileLCUX+1)) { m_pcBufferSbacDecoders[uiTileCol].loadContexts( &pcSbacDecoders[uiSubStrm] ); } } } }