void DPB::prepareEncode(TComPic *pic) { PPAScopeEvent(DPB_prepareEncode); int pocCurr = pic->getSlice()->getPOC(); m_picList.pushFront(*pic); TComSlice* slice = pic->getSlice(); if (getNalUnitType(pocCurr, m_lastIDR, pic) == NAL_UNIT_CODED_SLICE_IDR_W_RADL || getNalUnitType(pocCurr, m_lastIDR, pic) == NAL_UNIT_CODED_SLICE_IDR_N_LP) { m_lastIDR = pocCurr; } slice->setLastIDR(m_lastIDR); slice->setTemporalLayerNonReferenceFlag(!slice->isReferenced()); // Set the nal unit type slice->setNalUnitType(getNalUnitType(pocCurr, m_lastIDR, pic)); // If the slice is un-referenced, change from _R "referenced" to _N "non-referenced" NAL unit type if (slice->getTemporalLayerNonReferenceFlag()) { switch (slice->getNalUnitType()) { case NAL_UNIT_CODED_SLICE_TRAIL_R: slice->setNalUnitType(NAL_UNIT_CODED_SLICE_TRAIL_N); break; case NAL_UNIT_CODED_SLICE_RADL_R: slice->setNalUnitType(NAL_UNIT_CODED_SLICE_RADL_N); break; case NAL_UNIT_CODED_SLICE_RASL_R: slice->setNalUnitType(NAL_UNIT_CODED_SLICE_RASL_N); break; default: break; } } // Do decoding refresh marking if any decodingRefreshMarking(pocCurr, slice->getNalUnitType()); computeRPS(pocCurr, slice->isIRAP(), slice->getLocalRPS(), slice->getSPS()->getMaxDecPicBuffering(0)); slice->setRPS(slice->getLocalRPS()); slice->setRPSidx(-1); // Force use of RPS from slice, rather than from SPS applyReferencePictureSet(slice->getRPS(), pocCurr); // Mark pictures in m_piclist as unreferenced if they are not included in RPS arrangeLongtermPicturesInRPS(slice); slice->setNumRefIdx(REF_PIC_LIST_0, X265_MIN(m_maxRefL0, slice->getRPS()->getNumberOfNegativePictures())); // Ensuring L0 contains just the -ve POC slice->setNumRefIdx(REF_PIC_LIST_1, X265_MIN(m_maxRefL1, slice->getRPS()->getNumberOfPositivePictures())); slice->setRefPicList(m_picList); // Slice type refinement if ((slice->getSliceType() == B_SLICE) && (slice->getNumRefIdx(REF_PIC_LIST_1) == 0)) { slice->setSliceType(P_SLICE); } if (slice->getSliceType() == B_SLICE) { // TODO: Can we estimate this from lookahead? slice->setColFromL0Flag(0); bool bLowDelay = true; int curPOC = slice->getPOC(); int refIdx = 0; for (refIdx = 0; refIdx < slice->getNumRefIdx(REF_PIC_LIST_0) && bLowDelay; refIdx++) { if (slice->getRefPic(REF_PIC_LIST_0, refIdx)->getPOC() > curPOC) { bLowDelay = false; } } for (refIdx = 0; refIdx < slice->getNumRefIdx(REF_PIC_LIST_1) && bLowDelay; refIdx++) { if (slice->getRefPic(REF_PIC_LIST_1, refIdx)->getPOC() > curPOC) { bLowDelay = false; } } slice->setCheckLDC(bLowDelay); } else { slice->setCheckLDC(true); } slice->setRefPOCList(); slice->setEnableTMVPFlag(1); bool bGPBcheck = false; if (slice->getSliceType() == B_SLICE) { if (slice->getNumRefIdx(REF_PIC_LIST_0) == slice->getNumRefIdx(REF_PIC_LIST_1)) { bGPBcheck = true; for (int i = 0; i < slice->getNumRefIdx(REF_PIC_LIST_1); i++) { if (slice->getRefPOC(REF_PIC_LIST_1, i) != slice->getRefPOC(REF_PIC_LIST_0, i)) { bGPBcheck = false; break; } } } } slice->setMvdL1ZeroFlag(bGPBcheck); slice->setNextSlice(false); /* Increment reference count of all motion-referenced frames. This serves two purposes. First * it prevents the frame from being recycled, and second the referenced frames know how many * other FrameEncoders are using them for motion reference */ int numPredDir = slice->isInterP() ? 1 : slice->isInterB() ? 2 : 0; for (int l = 0; l < numPredDir; l++) { for (int ref = 0; ref < slice->getNumRefIdx(l); ref++) { TComPic *refpic = slice->getRefPic(l, ref); ATOMIC_INC(&refpic->m_countRefEncoders); } } }
void FrameEncoder::compressFrame() { PPAScopeEvent(FrameEncoder_compressFrame); int64_t startCompressTime = x265_mdate(); TEncEntropy* entropyCoder = getEntropyCoder(0); TComSlice* slice = m_pic->getSlice(); m_nalCount = 0; int qp = slice->getSliceQp(); double lambda = 0; if (slice->getSliceType() == I_SLICE) { lambda = X265_MAX(1, x265_lambda2_tab_I[qp]); } else { lambda = X265_MAX(1, x265_lambda2_non_I[qp]); } // for RDO // in RdCost there is only one lambda because the luma and chroma bits are not separated, // instead we weight the distortion of chroma. int qpc; int chromaQPOffset = slice->getPPS()->getChromaCbQpOffset() + slice->getSliceQpDeltaCb(); qpc = Clip3(0, 57, qp + chromaQPOffset); double cbWeight = pow(2.0, (qp - g_chromaScale[qpc])); // takes into account of the chroma qp mapping and chroma qp Offset chromaQPOffset = slice->getPPS()->getChromaCrQpOffset() + slice->getSliceQpDeltaCr(); qpc = Clip3(0, 57, qp + chromaQPOffset); double crWeight = pow(2.0, (qp - g_chromaScale[qpc])); // takes into account of the chroma qp mapping and chroma qp Offset double chromaLambda = lambda / crWeight; TComPicYuv *fenc = slice->getPic()->getPicYuvOrg(); for (int i = 0; i < m_numRows; i++) { m_rows[i].m_search.setQPLambda(qp, lambda, chromaLambda); m_rows[i].m_search.m_me.setSourcePlane(fenc->getLumaAddr(), fenc->getStride()); m_rows[i].m_rdCost.setLambda(lambda); m_rows[i].m_rdCost.setCbDistortionWeight(cbWeight); m_rows[i].m_rdCost.setCrDistortionWeight(crWeight); } m_frameFilter.m_sao.lumaLambda = lambda; m_frameFilter.m_sao.chromaLambda = chromaLambda; switch (slice->getSliceType()) { case I_SLICE: m_frameFilter.m_sao.depth = 0; break; case P_SLICE: m_frameFilter.m_sao.depth = 1; break; case B_SLICE: m_frameFilter.m_sao.depth = 2 + !slice->isReferenced(); break; } slice->setSliceQpDelta(0); slice->setSliceQpDeltaCb(0); slice->setSliceQpDeltaCr(0); int numSubstreams = m_cfg->param.bEnableWavefront ? m_pic->getPicSym()->getFrameHeightInCU() : 1; // TODO: these two items can likely be FrameEncoder member variables to avoid re-allocs TComOutputBitstream* bitstreamRedirect = new TComOutputBitstream; TComOutputBitstream* outStreams = new TComOutputBitstream[numSubstreams]; if (m_cfg->getUseASR() && !slice->isIntra()) { int pocCurr = slice->getPOC(); int maxSR = m_cfg->param.searchRange; int numPredDir = slice->isInterP() ? 1 : 2; for (int dir = 0; dir <= numPredDir; dir++) { for (int refIdx = 0; refIdx < slice->getNumRefIdx(dir); refIdx++) { int refPOC = slice->getRefPic(dir, refIdx)->getPOC(); int newSR = Clip3(8, maxSR, (maxSR * ADAPT_SR_SCALE * abs(pocCurr - refPOC) + 4) >> 3); for (int i = 0; i < m_numRows; i++) { m_rows[i].m_search.setAdaptiveSearchRange(dir, refIdx, newSR); } } } }
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; } } }
Bool TDecTop::decode(InputNALUnit& nalu, Int& iSkipFrame, Int& iPOCLastDisplay) { TComPic*& pcPic = m_pcPic; #if E045_SLICE_COMMON_INFO_SHARING static TComPPS* pcNewPPS = NULL; #endif // Initialize entropy decoder m_cEntropyDecoder.setEntropyDecoder (&m_cCavlcDecoder); m_cEntropyDecoder.setBitstream (nalu.m_Bitstream); switch (nalu.m_UnitType) { case NAL_UNIT_SPS: m_cEntropyDecoder.decodeSPS( &m_cSPS ); #if ENABLE_ANAYSIS_OUTPUT TSysuAnalyzerOutput::getInstance()->writeOutSps( &m_cSPS ); #endif #if AMP for (Int i = 0; i < m_cSPS.getMaxCUDepth() - 1; i++) { // m_cSPS.setAMPAcc( i, m_cSPS.getUseAMP() ); m_cSPS.setAMPAcc( i, 1 ); } for (Int i = m_cSPS.getMaxCUDepth() - 1; i < m_cSPS.getMaxCUDepth(); i++) { m_cSPS.setAMPAcc( i, 0 ); } #endif // create ALF temporary buffer m_cAdaptiveLoopFilter.create( m_cSPS.getWidth(), m_cSPS.getHeight(), g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth ); #if MTK_SAO m_cSAO.create( m_cSPS.getWidth(), m_cSPS.getHeight(), g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth ); #endif #if PARALLEL_MERGED_DEBLK m_cLoopFilter.create( m_cSPS.getWidth(), m_cSPS.getHeight(), g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth ); #else m_cLoopFilter. create( g_uiMaxCUDepth ); #endif #if E045_SLICE_COMMON_INFO_SHARING createPPSBuffer(); #endif m_uiValidPS |= 1; return false; case NAL_UNIT_PPS: #if E045_SLICE_COMMON_INFO_SHARING pcNewPPS = getNewPPSBuffer(); #if SUB_LCU_DQP pcNewPPS->setSPS(&m_cSPS); #endif m_cEntropyDecoder.decodePPS( pcNewPPS ); if(pcNewPPS->getSharedPPSInfoEnabled()) { if(m_cSPS.getUseALF()) { m_cEntropyDecoder.decodeAlfParam( pcNewPPS->getSharedAlfParam()); } } signalNewPPSAvailable(); #else #if SUB_LCU_DQP m_cPPS.setSPS(&m_cSPS); #endif m_cEntropyDecoder.decodePPS( &m_cPPS ); #endif m_uiValidPS |= 2; return false; case NAL_UNIT_SEI: m_SEIs = new SEImessages; m_cEntropyDecoder.decodeSEI(*m_SEIs); return false; case NAL_UNIT_CODED_SLICE: case NAL_UNIT_CODED_SLICE_IDR: case NAL_UNIT_CODED_SLICE_CDR: { // make sure we already received both parameter sets assert( 3 == m_uiValidPS ); if (m_bFirstSliceInPicture) { m_apcSlicePilot->initSlice(); m_uiSliceIdx = 0; m_uiLastSliceIdx = 0; #if E045_SLICE_COMMON_INFO_SHARING if(hasNewPPS()) { m_pcPPS = pcNewPPS; updatePPSBuffer(); } #endif } m_apcSlicePilot->setSliceIdx(m_uiSliceIdx); // Read slice header m_apcSlicePilot->setSPS( &m_cSPS ); #if E045_SLICE_COMMON_INFO_SHARING m_apcSlicePilot->setPPS( m_pcPPS ); #else m_apcSlicePilot->setPPS( &m_cPPS ); #endif m_apcSlicePilot->setSliceIdx(m_uiSliceIdx); if (!m_bFirstSliceInPicture) { memcpy(m_apcSlicePilot, pcPic->getPicSym()->getSlice(m_uiSliceIdx-1), sizeof(TComSlice)); } m_apcSlicePilot->setNalUnitType(nalu.m_UnitType); m_apcSlicePilot->setReferenced(nalu.m_RefIDC != NAL_REF_IDC_PRIORITY_LOWEST); m_cEntropyDecoder.decodeSliceHeader (m_apcSlicePilot); if ( m_apcSlicePilot->getSymbolMode() ) { Int numBitsForByteAlignment = nalu.m_Bitstream->getNumBitsUntilByteAligned(); if ( numBitsForByteAlignment > 0 ) { UInt bitsForByteAlignment; nalu.m_Bitstream->read( numBitsForByteAlignment, bitsForByteAlignment ); assert( bitsForByteAlignment == ( ( 1 << numBitsForByteAlignment ) - 1 ) ); } } m_apcSlicePilot->setTLayerInfo(nalu.m_TemporalID); if (m_apcSlicePilot->isNextSlice() && m_apcSlicePilot->getPOC()!=m_uiPrevPOC && !m_bFirstSliceInSequence) { m_uiPrevPOC = m_apcSlicePilot->getPOC(); return true; } if (m_apcSlicePilot->isNextSlice()) m_uiPrevPOC = m_apcSlicePilot->getPOC(); m_bFirstSliceInSequence = false; if (m_apcSlicePilot->isNextSlice()) { // Skip pictures due to random access if (isRandomAccessSkipPicture(iSkipFrame, iPOCLastDisplay)) { return false; } } if (m_bFirstSliceInPicture) { // Buffer initialize for prediction. m_cPrediction.initTempBuff(); // Get a new picture buffer xGetNewPicBuffer (m_apcSlicePilot, pcPic); /* transfer any SEI messages that have been received to the picture */ pcPic->setSEIs(m_SEIs); m_SEIs = NULL; // Recursive structure m_cCuDecoder.create ( g_uiMaxCUDepth, g_uiMaxCUWidth, g_uiMaxCUHeight ); m_cCuDecoder.init ( &m_cEntropyDecoder, &m_cTrQuant, &m_cPrediction ); m_cTrQuant.init ( g_uiMaxCUWidth, g_uiMaxCUHeight, m_apcSlicePilot->getSPS()->getMaxTrSize()); m_cSliceDecoder.create( m_apcSlicePilot, m_apcSlicePilot->getSPS()->getWidth(), m_apcSlicePilot->getSPS()->getHeight(), g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth ); } // Set picture slice pointer TComSlice* pcSlice = m_apcSlicePilot; Bool bNextSlice = pcSlice->isNextSlice(); if (m_bFirstSliceInPicture) { if(pcPic->getNumAllocatedSlice() != 1) { pcPic->clearSliceBuffer(); } } else { pcPic->allocateNewSlice(); } assert(pcPic->getNumAllocatedSlice() == (m_uiSliceIdx + 1)); m_apcSlicePilot = pcPic->getPicSym()->getSlice(m_uiSliceIdx); pcPic->getPicSym()->setSlice(pcSlice, m_uiSliceIdx); pcPic->setTLayer(nalu.m_TemporalID); if (bNextSlice) { // Do decoding refresh marking if any pcSlice->decodingRefreshMarking(m_uiPOCCDR, m_bRefreshPending, m_cListPic); // Set reference list pcSlice->setRefPicList( m_cListPic ); // HierP + GPB case if ( m_cSPS.getUseLDC() && pcSlice->isInterB() ) { if(pcSlice->getRefPicListCombinationFlag() && (pcSlice->getNumRefIdx(REF_PIC_LIST_0) > pcSlice->getNumRefIdx(REF_PIC_LIST_1))) { for (Int iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_1); iRefIdx++) { pcSlice->setRefPic(pcSlice->getRefPic(REF_PIC_LIST_0, iRefIdx), REF_PIC_LIST_1, iRefIdx); } } else { Int iNumRefIdx = pcSlice->getNumRefIdx(REF_PIC_LIST_0); pcSlice->setNumRefIdx( REF_PIC_LIST_1, iNumRefIdx ); for (Int iRefIdx = 0; iRefIdx < iNumRefIdx; iRefIdx++) { pcSlice->setRefPic(pcSlice->getRefPic(REF_PIC_LIST_0, iRefIdx), REF_PIC_LIST_1, iRefIdx); } } } // For generalized B // note: maybe not existed case (always L0 is copied to L1 if L1 is empty) if (pcSlice->isInterB() && pcSlice->getNumRefIdx(REF_PIC_LIST_1) == 0) { Int iNumRefIdx = pcSlice->getNumRefIdx(REF_PIC_LIST_0); pcSlice->setNumRefIdx ( REF_PIC_LIST_1, iNumRefIdx ); for (Int iRefIdx = 0; iRefIdx < iNumRefIdx; iRefIdx++) { pcSlice->setRefPic(pcSlice->getRefPic(REF_PIC_LIST_0, iRefIdx), REF_PIC_LIST_1, iRefIdx); } } #if TMVP_ONE_LIST_CHECK if (pcSlice->isInterB()) { Bool bLowDelay = true; Int iCurrPOC = pcSlice->getPOC(); Int iRefIdx = 0; for (iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_0) && bLowDelay; iRefIdx++) { if ( pcSlice->getRefPic(REF_PIC_LIST_0, iRefIdx)->getPOC() > iCurrPOC ) { bLowDelay = false; } } for (iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_1) && bLowDelay; iRefIdx++) { if ( pcSlice->getRefPic(REF_PIC_LIST_1, iRefIdx)->getPOC() > iCurrPOC ) { bLowDelay = false; } } pcSlice->setCheckLDC(bLowDelay); } #endif //--------------- pcSlice->setRefPOCList(); if(!pcSlice->getRefPicListModificationFlagLC()) { pcSlice->generateCombinedList(); } pcSlice->setNoBackPredFlag( false ); if ( pcSlice->getSliceType() == B_SLICE && !pcSlice->getRefPicListCombinationFlag()) { if ( pcSlice->getNumRefIdx(RefPicList( 0 ) ) == pcSlice->getNumRefIdx(RefPicList( 1 ) ) ) { pcSlice->setNoBackPredFlag( true ); int i; for ( i=0; i < pcSlice->getNumRefIdx(RefPicList( 1 ) ); i++ ) { if ( pcSlice->getRefPOC(RefPicList(1), i) != pcSlice->getRefPOC(RefPicList(0), i) ) { pcSlice->setNoBackPredFlag( false ); break; } } } } } pcPic->setCurrSliceIdx(m_uiSliceIdx); // Decode a picture #if REF_SETTING_FOR_LD m_cGopDecoder.decompressGop(nalu.m_Bitstream, pcPic, false, m_cListPic ); #else m_cGopDecoder.decompressGop(nalu.m_Bitstream, pcPic, false); #endif m_bFirstSliceInPicture = false; m_uiSliceIdx++; } break; default: assert (1); } return false; }
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] ); } } } }