/* 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-2012, ITU/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 ITU/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 TComPic.cpp \brief picture class */ #include "TComPic.h" #include "SEI.h" //! \ingroup TLibCommon //! \{ // ==================================================================================================================== // Constructor / destructor / create / destroy // ==================================================================================================================== TComPic::TComPic() : m_uiTLayer (0) , m_bUsedByCurr (false) , m_bIsLongTerm (false) , m_bIsUsedAsLongTerm (false) , m_apcPicSym (NULL) , m_pcPicYuvPred (NULL) , m_pcPicYuvResi (NULL) , m_bReconstructed (false) , m_bNeededForOutput (false) , m_uiCurrSliceIdx (0) , m_pSliceSUMap (NULL) , m_pbValidSlice (NULL) , m_sliceGranularityForNDBFilter (0) , m_bIndependentSliceBoundaryForNDBFilter (false) , m_bIndependentTileBoundaryForNDBFilter (false) , m_pNDBFilterYuvTmp (NULL) , m_bCheckLTMSB (false) , m_SEIs (NULL) #if SVC_EXTENSION , m_bSpatialEnhLayer( false ) , m_pcFullPelBaseRec( NULL ) #if REF_IDX_ME_AROUND_ZEROMV , m_bIsILR (false) #endif #endif { m_apcPicYuv[0] = NULL; m_apcPicYuv[1] = NULL; } TComPic::~TComPic() { } #if SVC_UPSAMPLING Void TComPic::create( Int iWidth, Int iHeight, UInt uiMaxWidth, UInt uiMaxHeight, UInt uiMaxDepth, TComSPS* pcSps, Bool bIsVirtual ) { m_apcPicSym = new TComPicSym; m_apcPicSym ->create( iWidth, iHeight, uiMaxWidth, uiMaxHeight, uiMaxDepth ); if (!bIsVirtual) { m_apcPicYuv[0] = new TComPicYuv; m_apcPicYuv[0]->create( iWidth, iHeight, uiMaxWidth, uiMaxHeight, uiMaxDepth, pcSps ); } m_apcPicYuv[1] = new TComPicYuv; m_apcPicYuv[1]->create( iWidth, iHeight, uiMaxWidth, uiMaxHeight, uiMaxDepth, pcSps ); if (m_bSpatialEnhLayer) { m_pcFullPelBaseRec = new TComPicYuv; m_pcFullPelBaseRec->create( iWidth, iHeight, uiMaxWidth, uiMaxHeight, uiMaxDepth, pcSps ); } /* there are no SEI messages associated with this picture initially */ m_SEIs = NULL; m_bUsedByCurr = false; return; } #if REF_IDX_FRAMEWORK Void TComPic::createWithOutYuv( Int iWidth, Int iHeight, UInt uiMaxWidth, UInt uiMaxHeight, UInt uiMaxDepth, TComSPS* pcSps, Bool bIsVirtual) { m_apcPicSym = new TComPicSym; m_apcPicSym ->create( iWidth, iHeight, uiMaxWidth, uiMaxHeight, uiMaxDepth ); if (!bIsVirtual) { m_apcPicYuv[0] = new TComPicYuv; m_apcPicYuv[0]->create( iWidth, iHeight, uiMaxWidth, uiMaxHeight, uiMaxDepth, pcSps ); } m_apcPicYuv[1] = NULL; #if SVC_UPSAMPLING if (m_bSpatialEnhLayer) { m_pcFullPelBaseRec = new TComPicYuv; m_pcFullPelBaseRec->create( iWidth, iHeight, uiMaxWidth, uiMaxHeight, uiMaxDepth, pcSps ); } #endif /* there are no SEI messages associated with this picture initially */ m_SEIs = NULL; m_bUsedByCurr = false; return; } #endif #else Void TComPic::create( Int iWidth, Int iHeight, UInt uiMaxWidth, UInt uiMaxHeight, UInt uiMaxDepth, Bool bIsVirtual ) { m_apcPicSym = new TComPicSym; m_apcPicSym ->create( iWidth, iHeight, uiMaxWidth, uiMaxHeight, uiMaxDepth ); if (!bIsVirtual) { m_apcPicYuv[0] = new TComPicYuv; m_apcPicYuv[0]->create( iWidth, iHeight, uiMaxWidth, uiMaxHeight, uiMaxDepth ); } m_apcPicYuv[1] = new TComPicYuv; m_apcPicYuv[1]->create( iWidth, iHeight, uiMaxWidth, uiMaxHeight, uiMaxDepth ); /* there are no SEI messages associated with this picture initially */ m_SEIs = NULL; m_bUsedByCurr = false; return; } #endif Void TComPic::destroy() { if (m_apcPicSym) { m_apcPicSym->destroy(); delete m_apcPicSym; m_apcPicSym = NULL; } if (m_apcPicYuv[0]) { m_apcPicYuv[0]->destroy(); delete m_apcPicYuv[0]; m_apcPicYuv[0] = NULL; } if (m_apcPicYuv[1]) { m_apcPicYuv[1]->destroy(); delete m_apcPicYuv[1]; m_apcPicYuv[1] = NULL; } #if SVC_EXTENSION && SVC_UPSAMPLING if (m_bSpatialEnhLayer) { m_pcFullPelBaseRec->destroy(); delete m_pcFullPelBaseRec; m_pcFullPelBaseRec = NULL; } #endif delete m_SEIs; } Void TComPic::compressMotion() { TComPicSym* pPicSym = getPicSym(); for ( UInt uiCUAddr = 0; uiCUAddr < pPicSym->getFrameHeightInCU()*pPicSym->getFrameWidthInCU(); uiCUAddr++ ) { TComDataCU* pcCU = pPicSym->getCU(uiCUAddr); pcCU->compressMV(); } } /** Create non-deblocked filter information * \param pSliceStartAddress array for storing slice start addresses * \param numSlices number of slices in picture * \param sliceGranularityDepth slice granularity * \param bNDBFilterCrossSliceBoundary cross-slice-boundary in-loop filtering; true for "cross". * \param numTiles number of tiles in picture * \param bNDBFilterCrossTileBoundary cross-tile-boundary in-loop filtering; true for "cross". */ Void TComPic::createNonDBFilterInfo(std::vector sliceStartAddress, Int sliceGranularityDepth ,std::vector* LFCrossSliceBoundary ,Int numTiles ,Bool bNDBFilterCrossTileBoundary) { UInt maxNumSUInLCU = getNumPartInCU(); UInt numLCUInPic = getNumCUsInFrame(); UInt picWidth = getSlice(0)->getSPS()->getPicWidthInLumaSamples(); UInt picHeight = getSlice(0)->getSPS()->getPicHeightInLumaSamples(); Int numLCUsInPicWidth = getFrameWidthInCU(); Int numLCUsInPicHeight= getFrameHeightInCU(); UInt maxNumSUInLCUWidth = getNumPartInWidth(); UInt maxNumSUInLCUHeight= getNumPartInHeight(); Int numSlices = (Int) sliceStartAddress.size() - 1; m_bIndependentSliceBoundaryForNDBFilter = false; if(numSlices > 1) { for(Int s=0; s< numSlices; s++) { if((*LFCrossSliceBoundary)[s] == false) { m_bIndependentSliceBoundaryForNDBFilter = true; } } } m_sliceGranularityForNDBFilter = sliceGranularityDepth; m_bIndependentTileBoundaryForNDBFilter = (bNDBFilterCrossTileBoundary)?(false) :((numTiles > 1)?(true):(false)); m_pbValidSlice = new Bool[numSlices]; for(Int s=0; s< numSlices; s++) { m_pbValidSlice[s] = true; } m_pSliceSUMap = new Int[maxNumSUInLCU * numLCUInPic]; //initialization for(UInt i=0; i< (maxNumSUInLCU * numLCUInPic); i++ ) { m_pSliceSUMap[i] = -1; } for( UInt CUAddr = 0; CUAddr < numLCUInPic ; CUAddr++ ) { TComDataCU* pcCU = getCU( CUAddr ); pcCU->setSliceSUMap(m_pSliceSUMap + (CUAddr* maxNumSUInLCU)); pcCU->getNDBFilterBlocks()->clear(); } m_vSliceCUDataLink.clear(); m_vSliceCUDataLink.resize(numSlices); UInt startAddr, endAddr, firstCUInStartLCU, startLCU, endLCU, lastCUInEndLCU, uiAddr; UInt LPelX, TPelY, LCUX, LCUY; UInt currSU; UInt startSU, endSU; for(Int s=0; s< numSlices; s++) { //1st step: decide the real start address startAddr = sliceStartAddress[s]; endAddr = sliceStartAddress[s+1] -1; startLCU = startAddr / maxNumSUInLCU; firstCUInStartLCU = startAddr % maxNumSUInLCU; endLCU = endAddr / maxNumSUInLCU; lastCUInEndLCU = endAddr % maxNumSUInLCU; uiAddr = m_apcPicSym->getCUOrderMap(startLCU); LCUX = getCU(uiAddr)->getCUPelX(); LCUY = getCU(uiAddr)->getCUPelY(); LPelX = LCUX + g_auiRasterToPelX[ g_auiZscanToRaster[firstCUInStartLCU] ]; TPelY = LCUY + g_auiRasterToPelY[ g_auiZscanToRaster[firstCUInStartLCU] ]; currSU = firstCUInStartLCU; Bool bMoveToNextLCU = false; Bool bSliceInOneLCU = (startLCU == endLCU); while(!( LPelX < picWidth ) || !( TPelY < picHeight )) { currSU ++; if(bSliceInOneLCU) { if(currSU > lastCUInEndLCU) { m_pbValidSlice[s] = false; break; } } if(currSU >= maxNumSUInLCU ) { bMoveToNextLCU = true; break; } LPelX = LCUX + g_auiRasterToPelX[ g_auiZscanToRaster[currSU] ]; TPelY = LCUY + g_auiRasterToPelY[ g_auiZscanToRaster[currSU] ]; } if(!m_pbValidSlice[s]) { continue; } if(currSU != firstCUInStartLCU) { if(!bMoveToNextLCU) { firstCUInStartLCU = currSU; } else { startLCU++; firstCUInStartLCU = 0; assert( startLCU < getNumCUsInFrame()); } assert(startLCU*maxNumSUInLCU + firstCUInStartLCU < endAddr); } //2nd step: assign NonDBFilterInfo to each processing block for(UInt i= startLCU; i <= endLCU; i++) { startSU = (i == startLCU)?(firstCUInStartLCU):(0); endSU = (i == endLCU )?(lastCUInEndLCU ):(maxNumSUInLCU -1); uiAddr = m_apcPicSym->getCUOrderMap(i); Int iTileID= m_apcPicSym->getTileIdxMap(uiAddr); TComDataCU* pcCU = getCU(uiAddr); m_vSliceCUDataLink[s].push_back(pcCU); createNonDBFilterInfoLCU(iTileID, s, pcCU, startSU, endSU, m_sliceGranularityForNDBFilter, picWidth, picHeight); } } //step 3: border availability for(Int s=0; s< numSlices; s++) { if(!m_pbValidSlice[s]) { continue; } for(Int i=0; i< m_vSliceCUDataLink[s].size(); i++) { TComDataCU* pcCU = m_vSliceCUDataLink[s][i]; uiAddr = pcCU->getAddr(); if(pcCU->getPic()==0) { continue; } Int iTileID= m_apcPicSym->getTileIdxMap(uiAddr); Bool bTopTileBoundary = false, bDownTileBoundary= false, bLeftTileBoundary= false, bRightTileBoundary= false; if(m_bIndependentTileBoundaryForNDBFilter) { //left if( uiAddr % numLCUsInPicWidth != 0) { bLeftTileBoundary = ( m_apcPicSym->getTileIdxMap(uiAddr -1) != iTileID )?true:false; } //right if( (uiAddr % numLCUsInPicWidth) != (numLCUsInPicWidth -1) ) { bRightTileBoundary = ( m_apcPicSym->getTileIdxMap(uiAddr +1) != iTileID)?true:false; } //top if( uiAddr >= numLCUsInPicWidth) { bTopTileBoundary = (m_apcPicSym->getTileIdxMap(uiAddr - numLCUsInPicWidth) != iTileID )?true:false; } //down if( uiAddr + numLCUsInPicWidth < numLCUInPic ) { bDownTileBoundary = (m_apcPicSym->getTileIdxMap(uiAddr + numLCUsInPicWidth) != iTileID)?true:false; } } pcCU->setNDBFilterBlockBorderAvailability(numLCUsInPicWidth, numLCUsInPicHeight, maxNumSUInLCUWidth, maxNumSUInLCUHeight,picWidth, picHeight , *LFCrossSliceBoundary ,bTopTileBoundary, bDownTileBoundary, bLeftTileBoundary, bRightTileBoundary ,m_bIndependentTileBoundaryForNDBFilter); } } if( m_bIndependentSliceBoundaryForNDBFilter || m_bIndependentTileBoundaryForNDBFilter) { m_pNDBFilterYuvTmp = new TComPicYuv(); m_pNDBFilterYuvTmp->create(picWidth, picHeight, g_uiMaxCUWidth, g_uiMaxCUHeight, g_uiMaxCUDepth); } } /** Create non-deblocked filter information for LCU * \param tileID tile index * \param sliceID slice index * \param pcCU CU data pointer * \param startSU start SU index in LCU * \param endSU end SU index in LCU * \param sliceGranularyDepth slice granularity * \param picWidth picture width * \param picHeight picture height */ Void TComPic::createNonDBFilterInfoLCU(Int tileID, Int sliceID, TComDataCU* pcCU, UInt startSU, UInt endSU, Int sliceGranularyDepth, UInt picWidth, UInt picHeight) { UInt LCUX = pcCU->getCUPelX(); UInt LCUY = pcCU->getCUPelY(); Int* pCUSliceMap = pcCU->getSliceSUMap(); UInt maxNumSUInLCU = getNumPartInCU(); UInt maxNumSUInSGU = maxNumSUInLCU >> (sliceGranularyDepth << 1); UInt maxNumSUInLCUWidth = getNumPartInWidth(); UInt LPelX, TPelY; UInt currSU; //get the number of valid NBFilterBLock currSU = startSU; while(currSU <= endSU) { LPelX = LCUX + g_auiRasterToPelX[ g_auiZscanToRaster[currSU] ]; TPelY = LCUY + g_auiRasterToPelY[ g_auiZscanToRaster[currSU] ]; while(!( LPelX < picWidth ) || !( TPelY < picHeight )) { currSU += maxNumSUInSGU; if(currSU >= maxNumSUInLCU || currSU > endSU) { break; } LPelX = LCUX + g_auiRasterToPelX[ g_auiZscanToRaster[currSU] ]; TPelY = LCUY + g_auiRasterToPelY[ g_auiZscanToRaster[currSU] ]; } if(currSU >= maxNumSUInLCU || currSU > endSU) { break; } NDBFBlockInfo NDBFBlock; NDBFBlock.tileID = tileID; NDBFBlock.sliceID = sliceID; NDBFBlock.posY = TPelY; NDBFBlock.posX = LPelX; NDBFBlock.startSU = currSU; UInt uiLastValidSU = currSU; UInt uiIdx, uiLPelX_su, uiTPelY_su; for(uiIdx = currSU; uiIdx < currSU + maxNumSUInSGU; uiIdx++) { if(uiIdx > endSU) { break; } uiLPelX_su = LCUX + g_auiRasterToPelX[ g_auiZscanToRaster[uiIdx] ]; uiTPelY_su = LCUY + g_auiRasterToPelY[ g_auiZscanToRaster[uiIdx] ]; if( !(uiLPelX_su < picWidth ) || !( uiTPelY_su < picHeight )) { continue; } pCUSliceMap[uiIdx] = sliceID; uiLastValidSU = uiIdx; } NDBFBlock.endSU = uiLastValidSU; UInt rTLSU = g_auiZscanToRaster[ NDBFBlock.startSU ]; UInt rBRSU = g_auiZscanToRaster[ NDBFBlock.endSU ]; NDBFBlock.widthSU = (rBRSU % maxNumSUInLCUWidth) - (rTLSU % maxNumSUInLCUWidth)+ 1; NDBFBlock.heightSU = (UInt)(rBRSU / maxNumSUInLCUWidth) - (UInt)(rTLSU / maxNumSUInLCUWidth)+ 1; NDBFBlock.width = NDBFBlock.widthSU * getMinCUWidth(); NDBFBlock.height = NDBFBlock.heightSU * getMinCUHeight(); pcCU->getNDBFilterBlocks()->push_back(NDBFBlock); currSU += maxNumSUInSGU; } } /** destroy non-deblocked filter information for LCU */ Void TComPic::destroyNonDBFilterInfo() { if(m_pbValidSlice != NULL) { delete[] m_pbValidSlice; m_pbValidSlice = NULL; } if(m_pSliceSUMap != NULL) { delete[] m_pSliceSUMap; m_pSliceSUMap = NULL; } for( UInt CUAddr = 0; CUAddr < getNumCUsInFrame() ; CUAddr++ ) { TComDataCU* pcCU = getCU( CUAddr ); pcCU->getNDBFilterBlocks()->clear(); } if( m_bIndependentSliceBoundaryForNDBFilter || m_bIndependentTileBoundaryForNDBFilter) { m_pNDBFilterYuvTmp->destroy(); delete m_pNDBFilterYuvTmp; m_pNDBFilterYuvTmp = NULL; } } #if REF_IDX_FRAMEWORK Void copyOnetoOnePicture( // SVC_NONCOLL Pel *in, Pel *out, Int nCols, Int nRows, Int fullRowWidth) { Int rX; for (rX = 0; rX < nRows; rX++) { memcpy( out, in, sizeof(Pel) * nCols ); in = in + fullRowWidth; out = out + fullRowWidth; } } Void TComPic:: copyUpsampledPictureYuv(TComPicYuv* pcPicYuvIn, TComPicYuv* pcPicYuvOut) { Int upsampledRowWidthLuma = pcPicYuvOut->getStride(); // 2 * pcPicYuvOut->getLumaMargin() + pcPicYuvOut->getWidth(); Int upsampledRowWidthCroma = pcPicYuvOut->getCStride(); //2 * pcPicYuvOut->getChromaMargin() + (pcPicYuvOut->getWidth()>>1); copyOnetoOnePicture( pcPicYuvIn->getLumaAddr(), pcPicYuvOut->getLumaAddr(), pcPicYuvOut->getWidth(), pcPicYuvOut->getHeight(), upsampledRowWidthLuma); copyOnetoOnePicture( pcPicYuvIn->getCrAddr(), pcPicYuvOut->getCrAddr(), pcPicYuvOut->getWidth()>>1, pcPicYuvOut->getHeight()>>1, upsampledRowWidthCroma); copyOnetoOnePicture( pcPicYuvIn->getCbAddr(), pcPicYuvOut->getCbAddr(), pcPicYuvOut->getWidth()>>1, pcPicYuvOut->getHeight()>>1, upsampledRowWidthCroma); } #endif //! \}