/* 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-2019, 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 EncLib.cpp \brief encoder class */ #include "EncLib.h" #include "EncModeCtrl.h" #include "AQp.h" #include "EncCu.h" #include "CommonLib/Picture.h" #include "CommonLib/CommonDef.h" #include "CommonLib/ChromaFormat.h" #if ENABLE_SPLIT_PARALLELISM #include <omp.h> #endif #if JVET_N0278_FIXES #include "EncLibCommon.h" #endif //! \ingroup EncoderLib //! \{ // ==================================================================================================================== // Constructor / destructor / create / destroy // ==================================================================================================================== #if JVET_N0278_FIXES EncLib::EncLib( EncLibCommon* encLibCommon ) : m_cListPic( encLibCommon->getPictureBuffer() ) , m_cEncALF( encLibCommon->getApsIdStart() ) , m_spsMap( encLibCommon->getSpsMap() ) , m_ppsMap( encLibCommon->getPpsMap() ) , m_apsMap( encLibCommon->getApsMap() ) , m_AUWriterIf( nullptr ) #else EncLib::EncLib() : m_spsMap( MAX_NUM_SPS ) , m_ppsMap( MAX_NUM_PPS ) , m_apsMap(MAX_NUM_APS * MAX_NUM_APS_TYPE) , m_AUWriterIf( nullptr ) #endif #if JVET_J0090_MEMORY_BANDWITH_MEASURE , m_cacheModel() #endif , m_lmcsAPS(nullptr) , m_scalinglistAPS( nullptr ) , m_doPlt( true ) { m_iPOCLast = -1; m_iNumPicRcvd = 0; m_uiNumAllPicCoded = 0; m_iMaxRefPicNum = 0; #if ENABLE_SIMD_OPT_BUFFER g_pelBufOP.initPelBufOpsX86(); #endif #if JVET_O0756_CALCULATE_HDRMETRICS m_metricTime = std::chrono::milliseconds(0); #endif memset(m_apss, 0, sizeof(m_apss)); #if JVET_N0278_FIXES m_layerId = NOT_VALID; m_picIdInGOP = NOT_VALID; #endif } EncLib::~EncLib() { } #if JVET_N0278_FIXES void EncLib::create( const int layerId ) #else void EncLib::create () #endif { #if JVET_N0278_FIXES m_layerId = layerId; #else // initialize global variables initROM(); TComHash::initBlockSizeToIndex(); #endif m_iPOCLast = m_compositeRefEnabled ? -2 : -1; // create processing unit classes m_cGOPEncoder. create( ); #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM #if ENABLE_SPLIT_PARALLELISM m_numCuEncStacks = m_numSplitThreads == 1 ? 1 : NUM_RESERVERD_SPLIT_JOBS; #else m_numCuEncStacks = 1; #endif #if ENABLE_WPP_PARALLELISM m_numCuEncStacks *= ( m_numWppThreads + m_numWppExtraLines ); #endif m_cCuEncoder = new EncCu [m_numCuEncStacks]; m_cInterSearch = new InterSearch [m_numCuEncStacks]; m_cIntraSearch = new IntraSearch [m_numCuEncStacks]; m_cTrQuant = new TrQuant [m_numCuEncStacks]; m_CABACEncoder = new CABACEncoder [m_numCuEncStacks]; m_cRdCost = new RdCost [m_numCuEncStacks]; m_CtxCache = new CtxCache [m_numCuEncStacks]; for( int jId = 0; jId < m_numCuEncStacks; jId++ ) { m_cCuEncoder[jId]. create( this ); } #else m_cCuEncoder. create( this ); #endif #if JVET_J0090_MEMORY_BANDWITH_MEASURE m_cInterSearch.cacheAssign( &m_cacheModel ); #endif m_cLoopFilter.create( m_maxTotalCUDepth ); #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM m_cReshaper = new EncReshape[m_numCuEncStacks]; #endif if (m_lumaReshapeEnable) { #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM for (int jId = 0; jId < m_numCuEncStacks; jId++) { m_cReshaper[jId].createEnc(getSourceWidth(), getSourceHeight(), m_maxCUWidth, m_maxCUHeight, m_bitDepth[COMPONENT_Y]); } #else m_cReshaper.createEnc( getSourceWidth(), getSourceHeight(), m_maxCUWidth, m_maxCUHeight, m_bitDepth[COMPONENT_Y]); #endif } if ( m_RCEnableRateControl ) { m_cRateCtrl.init(m_framesToBeEncoded, m_RCTargetBitrate, (int)((double)m_iFrameRate / m_temporalSubsampleRatio + 0.5), m_iGOPSize, m_iSourceWidth, m_iSourceHeight, m_maxCUWidth, m_maxCUHeight, getBitDepth(CHANNEL_TYPE_LUMA), m_RCKeepHierarchicalBit, m_RCUseLCUSeparateModel, m_GOPList); } } void EncLib::destroy () { // destroy processing unit classes m_cGOPEncoder. destroy(); m_cSliceEncoder. destroy(); #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM for( int jId = 0; jId < m_numCuEncStacks; jId++ ) { m_cCuEncoder[jId].destroy(); } #else m_cCuEncoder. destroy(); #endif if( m_alf ) { m_cEncALF.destroy(); } m_cEncSAO. destroyEncData(); m_cEncSAO. destroy(); m_cLoopFilter. destroy(); m_cRateCtrl. destroy(); #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM for (int jId = 0; jId < m_numCuEncStacks; jId++) { m_cReshaper[jId]. destroy(); } #else m_cReshaper. destroy(); #endif #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM for( int jId = 0; jId < m_numCuEncStacks; jId++ ) { m_cInterSearch[jId]. destroy(); m_cIntraSearch[jId]. destroy(); } #else m_cInterSearch. destroy(); m_cIntraSearch. destroy(); #endif #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM delete[] m_cCuEncoder; delete[] m_cInterSearch; delete[] m_cIntraSearch; delete[] m_cTrQuant; delete[] m_CABACEncoder; delete[] m_cRdCost; delete[] m_CtxCache; #endif #if !JVET_N0278_FIXES // destroy ROM destroyROM(); #endif return; } void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf ) { m_AUWriterIf = auWriterIf; SPS &sps0=*(m_spsMap.allocatePS(0)); // NOTE: implementations that use more than 1 SPS need to be aware of activation issues. #if JVET_N0278_FIXES PPS &pps0 = *( m_ppsMap.allocatePS( m_layerId ) ); #else PPS &pps0=*(m_ppsMap.allocatePS(0)); #endif APS &aps0 = *( m_apsMap.allocatePS( SCALING_LIST_APS ) ); aps0.setAPSId( 0 ); aps0.setAPSType( SCALING_LIST_APS ); // initialize SPS xInitSPS(sps0); xInitVPS(m_cVPS); int dpsId = getDecodingParameterSetEnabled() ? 1 : 0; xInitDPS(m_dps, sps0, dpsId); sps0.setDecodingParameterSetId(m_dps.getDecodingParameterSetId()); #if ENABLE_SPLIT_PARALLELISM if( omp_get_dynamic() ) { omp_set_dynamic( false ); } omp_set_nested( true ); #endif if (getUseCompositeRef() || getDependentRAPIndicationSEIEnabled()) { sps0.setLongTermRefsPresent(true); } #if U0132_TARGET_BITS_SATURATION if (m_RCCpbSaturationEnabled) { m_cRateCtrl.initHrdParam(sps0.getHrdParameters(), m_iFrameRate, m_RCInitialCpbFullness); } #endif #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM for( int jId = 0; jId < m_numCuEncStacks; jId++ ) { m_cRdCost[jId].setCostMode ( m_costMode ); } #else m_cRdCost.setCostMode ( m_costMode ); #endif // initialize PPS pps0.setPicWidthInLumaSamples( m_iSourceWidth ); pps0.setPicHeightInLumaSamples( m_iSourceHeight ); pps0.setConformanceWindow( m_conformanceWindow ); xInitPPS(pps0, sps0); // initialize APS xInitRPL(sps0, isFieldCoding); if( m_rprEnabled ) { PPS &pps = *( m_ppsMap.allocatePS( ENC_PPS_ID_RPR ) ); #if JVET_P0590_SCALING_WINDOW Window& inputScalingWindow = pps0.getScalingWindow(); int scaledWidth = int( ( pps0.getPicWidthInLumaSamples() - inputScalingWindow.getWindowLeftOffset() - inputScalingWindow.getWindowRightOffset() ) / m_scalingRatioHor ); #else Window& inputConfWindow = pps0.getConformanceWindow(); int scaledWidth = int((pps0.getPicWidthInLumaSamples() - (inputConfWindow.getWindowLeftOffset() + inputConfWindow.getWindowRightOffset()) * SPS::getWinUnitX(sps0.getChromaFormatIdc())) / m_scalingRatioHor); #endif int minSizeUnit = std::max(8, (int)(sps0.getMaxCUHeight() >> (sps0.getMaxCodingDepth() - 1))); int temp = scaledWidth / minSizeUnit; int width = ( scaledWidth - ( temp * minSizeUnit) > 0 ? temp + 1 : temp ) * minSizeUnit; #if JVET_P0590_SCALING_WINDOW int scaledHeight = int( ( pps0.getPicHeightInLumaSamples() - inputScalingWindow.getWindowTopOffset() - inputScalingWindow.getWindowBottomOffset() ) / m_scalingRatioVer ); #else int scaledHeight = int((pps0.getPicHeightInLumaSamples() - (inputConfWindow.getWindowTopOffset() + inputConfWindow.getWindowBottomOffset()) * SPS::getWinUnitY(sps0.getChromaFormatIdc())) / m_scalingRatioVer); #endif temp = scaledHeight / minSizeUnit; int height = ( scaledHeight - ( temp * minSizeUnit) > 0 ? temp + 1 : temp ) * minSizeUnit; pps.setPicWidthInLumaSamples( width ); pps.setPicHeightInLumaSamples( height ); Window conformanceWindow; conformanceWindow.setWindow( 0, ( width - scaledWidth ) / SPS::getWinUnitX( sps0.getChromaFormatIdc() ), 0, ( height - scaledHeight ) / SPS::getWinUnitY( sps0.getChromaFormatIdc() ) ); pps.setConformanceWindow( conformanceWindow ); #if JVET_P0590_SCALING_WINDOW Window scalingWindow; scalingWindow.setWindow( 0, width - scaledWidth, 0, height - scaledHeight ); pps.setScalingWindow( scalingWindow ); #endif #if JVET_P1004_REMOVE_BRICKS // disable picture partitioning for scaled RPR pictures (slice/tile config only provided for the original resolution) m_noPicPartitionFlag = true; #endif xInitPPS( pps, sps0 ); // will allocate memory for and initialize pps.pcv inside } #if ER_CHROMA_QP_WCG_PPS if (m_wcgChromaQpControl.isEnabled()) { PPS &pps1=*(m_ppsMap.allocatePS(1)); xInitPPS(pps1, sps0); } #endif if (getUseCompositeRef()) { PPS &pps2 = *(m_ppsMap.allocatePS(2)); xInitPPS(pps2, sps0); xInitPPSforLT(pps2); } #if JVET_P1006_PICTURE_HEADER xInitPicHeader(m_picHeader, sps0, pps0); #endif // initialize processing unit classes m_cGOPEncoder. init( this ); m_cSliceEncoder.init( this, sps0 ); #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM for( int jId = 0; jId < m_numCuEncStacks; jId++ ) { // precache a few objects for( int i = 0; i < 10; i++ ) { auto x = m_CtxCache[jId].get(); m_CtxCache[jId].cache( x ); } m_cCuEncoder[jId].init( this, sps0, jId ); // initialize transform & quantization class m_cTrQuant[jId].init( jId == 0 ? nullptr : m_cTrQuant[0].getQuant(), 1 << m_log2MaxTbSize, m_useRDOQ, m_useRDOQTS, #if T0196_SELECTIVE_RDOQ m_useSelectiveRDOQ, #endif true ); // initialize encoder search class CABACWriter* cabacEstimator = m_CABACEncoder[jId].getCABACEstimator( &sps0 ); m_cIntraSearch[jId].init( this, &m_cTrQuant[jId], &m_cRdCost[jId], cabacEstimator, getCtxCache( jId ), m_maxCUWidth, m_maxCUHeight, m_maxTotalCUDepth , &m_cReshaper[jId] #if JVET_P0077_LINE_CG_PALETTE , sps0.getBitDepth(CHANNEL_TYPE_LUMA) #endif ); m_cInterSearch[jId].init( this, &m_cTrQuant[jId], m_iSearchRange, m_bipredSearchRange, m_motionEstimationSearchMethod, getUseCompositeRef(), m_maxCUWidth, m_maxCUHeight, m_maxTotalCUDepth, &m_cRdCost[jId], cabacEstimator, getCtxCache( jId ) , &m_cReshaper[jId] ); // link temporary buffets from intra search with inter search to avoid unnecessary memory overhead m_cInterSearch[jId].setTempBuffers( m_cIntraSearch[jId].getSplitCSBuf(), m_cIntraSearch[jId].getFullCSBuf(), m_cIntraSearch[jId].getSaveCSBuf() ); } #else // ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM m_cCuEncoder. init( this, sps0 ); // initialize transform & quantization class m_cTrQuant.init( nullptr, 1 << m_log2MaxTbSize, m_useRDOQ, m_useRDOQTS, #if T0196_SELECTIVE_RDOQ m_useSelectiveRDOQ, #endif true ); // initialize encoder search class CABACWriter* cabacEstimator = m_CABACEncoder.getCABACEstimator(&sps0); m_cIntraSearch.init( this, &m_cTrQuant, &m_cRdCost, cabacEstimator, getCtxCache(), m_maxCUWidth, m_maxCUHeight, m_maxTotalCUDepth , &m_cReshaper #if JVET_P0077_LINE_CG_PALETTE , sps0.getBitDepth(CHANNEL_TYPE_LUMA) #endif ); m_cInterSearch.init( this, &m_cTrQuant, m_iSearchRange, m_bipredSearchRange, m_motionEstimationSearchMethod, getUseCompositeRef(), m_maxCUWidth, m_maxCUHeight, m_maxTotalCUDepth, &m_cRdCost, cabacEstimator, getCtxCache() , &m_cReshaper ); // link temporary buffets from intra search with inter search to avoid unneccessary memory overhead m_cInterSearch.setTempBuffers( m_cIntraSearch.getSplitCSBuf(), m_cIntraSearch.getFullCSBuf(), m_cIntraSearch.getSaveCSBuf() ); #endif // ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM m_iMaxRefPicNum = 0; #if ER_CHROMA_QP_WCG_PPS if( m_wcgChromaQpControl.isEnabled() ) { xInitScalingLists( sps0, *m_apsMap.getPS( 1 ) ); xInitScalingLists( sps0, aps0 ); } else #endif { xInitScalingLists( sps0, aps0 ); } if( m_rprEnabled ) { xInitScalingLists( sps0, *m_apsMap.getPS( ENC_PPS_ID_RPR ) ); } #if ENABLE_WPP_PARALLELISM m_entropyCodingSyncContextStateVec.resize( pps0.pcv->heightInCtus ); #endif if (getUseCompositeRef()) { Picture *picBg = new Picture; #if JVET_N0278_FIXES picBg->create( sps0.getChromaFormatIdc(), Size( pps0.getPicWidthInLumaSamples(), pps0.getPicHeightInLumaSamples() ), sps0.getMaxCUWidth(), sps0.getMaxCUWidth() + 16, false, m_layerId ); #else picBg->create( sps0.getChromaFormatIdc(), Size( pps0.getPicWidthInLumaSamples(), pps0.getPicHeightInLumaSamples() ), sps0.getMaxCUWidth(), sps0.getMaxCUWidth() + 16, false ); #endif picBg->getRecoBuf().fill(0); #if JVET_P1006_PICTURE_HEADER picBg->finalInit( sps0, pps0, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); #else picBg->finalInit( sps0, pps0, m_apss, m_lmcsAPS, m_scalinglistAPS ); #endif #if !JVET_P1004_REMOVE_BRICKS pps0.setNumBricksInPic((int)picBg->brickMap->bricks.size()); #endif picBg->allocateNewSlice(); picBg->createSpliceIdx(pps0.pcv->sizeInCtus); m_cGOPEncoder.setPicBg(picBg); Picture *picOrig = new Picture; #if JVET_N0278_FIXES picOrig->create( sps0.getChromaFormatIdc(), Size( pps0.getPicWidthInLumaSamples(), pps0.getPicHeightInLumaSamples() ), sps0.getMaxCUWidth(), sps0.getMaxCUWidth() + 16, false, m_layerId ); #else picOrig->create( sps0.getChromaFormatIdc(), Size( pps0.getPicWidthInLumaSamples(), pps0.getPicHeightInLumaSamples() ), sps0.getMaxCUWidth(), sps0.getMaxCUWidth() + 16, false ); #endif picOrig->getOrigBuf().fill(0); m_cGOPEncoder.setPicOrig(picOrig); } } void EncLib::xInitScalingLists( SPS &sps, APS &aps ) { // Initialise scaling lists // The encoder will only use the SPS scaling lists. The PPS will never be marked present. const int maxLog2TrDynamicRange[MAX_NUM_CHANNEL_TYPE] = { sps.getMaxLog2TrDynamicRange(CHANNEL_TYPE_LUMA), sps.getMaxLog2TrDynamicRange(CHANNEL_TYPE_CHROMA) }; Quant* quant = getTrQuant()->getQuant(); if(getUseScalingListId() == SCALING_LIST_OFF) { quant->setFlatScalingList(maxLog2TrDynamicRange, sps.getBitDepths()); quant->setUseScalingList(false); #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM for( int jId = 1; jId < m_numCuEncStacks; jId++ ) { getTrQuant( jId )->getQuant()->setFlatScalingList( maxLog2TrDynamicRange, sps.getBitDepths() ); getTrQuant( jId )->getQuant()->setUseScalingList( false ); } #endif } else if(getUseScalingListId() == SCALING_LIST_DEFAULT) { aps.getScalingList().setDefaultScalingList (); quant->setScalingList( &( aps.getScalingList() ), maxLog2TrDynamicRange, sps.getBitDepths() ); quant->setUseScalingList(true); #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM for( int jId = 1; jId < m_numCuEncStacks; jId++ ) { getTrQuant( jId )->getQuant()->setUseScalingList( true ); } #if JVET_P0365_SCALING_MATRIX_LFNST aps.getScalingList().setDisableScalingMatrixForLfnstBlks(getDisableScalingMatrixForLfnstBlks()); #endif #endif } else if(getUseScalingListId() == SCALING_LIST_FILE_READ) { aps.getScalingList().setDefaultScalingList(); CHECK( aps.getScalingList().xParseScalingList( getScalingListFileName() ), "Error Parsing Scaling List Input File" ); aps.getScalingList().checkDcOfMatrix(); if( aps.getScalingList().isNotDefaultScalingList() == false ) { setUseScalingListId( SCALING_LIST_DEFAULT ); } quant->setScalingList( &( aps.getScalingList() ), maxLog2TrDynamicRange, sps.getBitDepths() ); quant->setUseScalingList(true); #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM for( int jId = 1; jId < m_numCuEncStacks; jId++ ) { getTrQuant( jId )->getQuant()->setUseScalingList( true ); } #endif #if JVET_P0365_SCALING_MATRIX_LFNST aps.getScalingList().setDisableScalingMatrixForLfnstBlks(getDisableScalingMatrixForLfnstBlks()); #endif } else { THROW("error : ScalingList == " << getUseScalingListId() << " not supported\n"); } if( getUseScalingListId() == SCALING_LIST_FILE_READ ) { // Prepare delta's: #if JVET_P01034_PRED_1D_SCALING_LIST for (uint32_t scalingListId = 0; scalingListId < 28; scalingListId++) { aps.getScalingList().checkPredMode(scalingListId); } #else for (uint32_t sizeId = SCALING_LIST_2x2; sizeId <= SCALING_LIST_64x64; sizeId++) { for (uint32_t listId = 0; listId < SCALING_LIST_NUM; listId++) { if (((sizeId == SCALING_LIST_64x64) && (listId % (SCALING_LIST_NUM / SCALING_LIST_PRED_MODES) != 0)) || ((sizeId == SCALING_LIST_2x2) && (listId % (SCALING_LIST_NUM / SCALING_LIST_PRED_MODES) == 0))) { continue; } aps.getScalingList().checkPredMode( sizeId, listId ); } } #endif } } void EncLib::xInitPPSforLT(PPS& pps) { pps.setOutputFlagPresentFlag(true); pps.setDeblockingFilterControlPresentFlag(true); pps.setPPSDeblockingFilterDisabledFlag(true); } // ==================================================================================================================== // Public member functions // ==================================================================================================================== void EncLib::deletePicBuffer() { PicList::iterator iterPic = m_cListPic.begin(); int iSize = int( m_cListPic.size() ); for ( int i = 0; i < iSize; i++ ) { Picture* pcPic = *(iterPic++); pcPic->destroy(); // get rid of the qpadaption layer while( pcPic->aqlayer.size() ) { delete pcPic->aqlayer.back(); pcPic->aqlayer.pop_back(); } delete pcPic; pcPic = NULL; } #if JVET_N0278_FIXES m_cListPic.clear(); #endif } #if JVET_N0278_FIXES bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* cPicYuvTrueOrg, const InputColourSpaceConversion snrCSC, std::list<PelUnitBuf*>& rcListPicYuvRecOut, int& iNumEncoded ) { if( m_compositeRefEnabled && m_cGOPEncoder.getPicBg()->getSpliceFull() && m_iPOCLast >= 10 && m_iNumPicRcvd == 0 && m_cGOPEncoder.getEncodedLTRef() == false ) { Picture* picCurr = NULL; xGetNewPicBuffer( rcListPicYuvRecOut, picCurr, 2 ); const PPS *pps = m_ppsMap.getPS( 2 ); const SPS *sps = m_spsMap.getPS( pps->getSPSId() ); picCurr->M_BUFS( 0, PIC_ORIGINAL ).copyFrom( m_cGOPEncoder.getPicBg()->getRecoBuf() ); #if JVET_P1006_PICTURE_HEADER picCurr->finalInit( *sps, *pps, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); #else picCurr->finalInit( *sps, *pps, m_apss, m_lmcsAPS, m_scalinglistAPS ); #endif picCurr->poc = m_iPOCLast - 1; m_iPOCLast -= 2; if( getUseAdaptiveQP() ) { AQpPreanalyzer::preanalyze( picCurr ); } if( m_RCEnableRateControl ) { m_cRateCtrl.initRCGOP( m_iNumPicRcvd ); } m_cGOPEncoder.compressGOP( m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut, false, false, snrCSC, m_printFrameMSE, true, 0 ); #if JVET_O0756_CALCULATE_HDRMETRICS m_metricTime = m_cGOPEncoder.getMetricTime(); #endif m_cGOPEncoder.setEncodedLTRef( true ); if( m_RCEnableRateControl ) { m_cRateCtrl.destroyRCGOP(); } iNumEncoded = 0; m_iNumPicRcvd = 0; } //PROF_ACCUM_AND_START_NEW_SET( getProfilerPic(), P_GOP_LEVEL ); if( pcPicYuvOrg != NULL ) { // get original YUV Picture* pcPicCurr = NULL; int ppsID = -1; // Use default PPS ID #if ER_CHROMA_QP_WCG_PPS if( getWCGChromaQPControl().isEnabled() ) { ppsID = getdQPs()[m_iPOCLast / ( m_compositeRefEnabled ? 2 : 1 ) + 1]; ppsID += ( getSwitchPOC() != -1 && ( m_iPOCLast + 1 >= getSwitchPOC() ) ? 1 : 0 ); } #endif if( m_rprEnabled && m_uiIntraPeriod == -1 ) { const int poc = m_iPOCLast + ( m_compositeRefEnabled ? 2 : 1 ); if( poc / m_switchPocPeriod % 2 ) { ppsID = ENC_PPS_ID_RPR; } else { ppsID = 0; } } #if JVET_N0278_FIXES if( m_cVPS.getMaxLayers() > 1 ) { ppsID = m_layerId; } #endif xGetNewPicBuffer( rcListPicYuvRecOut, pcPicCurr, ppsID ); const PPS *pPPS = ( ppsID < 0 ) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS( ppsID ); const SPS *pSPS = m_spsMap.getPS( pPPS->getSPSId() ); if( m_rprEnabled ) { pcPicCurr->M_BUFS( 0, PIC_ORIGINAL_INPUT ).getBuf( COMPONENT_Y ).copyFrom( pcPicYuvOrg->getBuf( COMPONENT_Y ) ); pcPicCurr->M_BUFS( 0, PIC_ORIGINAL_INPUT ).getBuf( COMPONENT_Cb ).copyFrom( pcPicYuvOrg->getBuf( COMPONENT_Cb ) ); pcPicCurr->M_BUFS( 0, PIC_ORIGINAL_INPUT ).getBuf( COMPONENT_Cr ).copyFrom( pcPicYuvOrg->getBuf( COMPONENT_Cr ) ); pcPicCurr->M_BUFS( 0, PIC_TRUE_ORIGINAL_INPUT ).getBuf( COMPONENT_Y ).copyFrom( cPicYuvTrueOrg->getBuf( COMPONENT_Y ) ); pcPicCurr->M_BUFS( 0, PIC_TRUE_ORIGINAL_INPUT ).getBuf( COMPONENT_Cb ).copyFrom( cPicYuvTrueOrg->getBuf( COMPONENT_Cb ) ); pcPicCurr->M_BUFS( 0, PIC_TRUE_ORIGINAL_INPUT ).getBuf( COMPONENT_Cr ).copyFrom( cPicYuvTrueOrg->getBuf( COMPONENT_Cr ) ); const ChromaFormat chromaFormatIDC = pSPS->getChromaFormatIdc(); const PPS *refPPS = m_ppsMap.getPS( 0 ); #if JVET_P0590_SCALING_WINDOW const Window& curScalingWindow = pPPS->getScalingWindow(); int curPicWidth = pPPS->getPicWidthInLumaSamples() - curScalingWindow.getWindowLeftOffset() - curScalingWindow.getWindowRightOffset(); int curPicHeight = pPPS->getPicHeightInLumaSamples() - curScalingWindow.getWindowTopOffset() - curScalingWindow.getWindowBottomOffset(); const Window& refScalingWindow = refPPS->getScalingWindow(); int refPicWidth = refPPS->getPicWidthInLumaSamples() - refScalingWindow.getWindowLeftOffset() - refScalingWindow.getWindowRightOffset(); int refPicHeight = refPPS->getPicHeightInLumaSamples() - refScalingWindow.getWindowTopOffset() - refScalingWindow.getWindowBottomOffset(); int xScale = ( ( refPicWidth << SCALE_RATIO_BITS ) + ( curPicWidth >> 1 ) ) / curPicWidth; int yScale = ( ( refPicHeight << SCALE_RATIO_BITS ) + ( curPicHeight >> 1 ) ) / curPicHeight; std::pair<int, int> scalingRatio = std::pair<int, int>( xScale, yScale ); #if JVET_P0592_CHROMA_PHASE Picture::rescalePicture( scalingRatio, *pcPicYuvOrg, refPPS->getScalingWindow(), pcPicCurr->getOrigBuf(), pPPS->getScalingWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true, pSPS->getHorCollocatedChromaFlag(), pSPS->getVerCollocatedChromaFlag() ); Picture::rescalePicture( scalingRatio, *cPicYuvTrueOrg, refPPS->getScalingWindow(), pcPicCurr->getTrueOrigBuf(), pPPS->getScalingWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true, pSPS->getHorCollocatedChromaFlag(), pSPS->getVerCollocatedChromaFlag() ); #else Picture::rescalePicture( scalingRatio, *pcPicYuvOrg, refPPS->getScalingWindow(), pcPicCurr->getOrigBuf(), pPPS->getScalingWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true ); Picture::rescalePicture( scalingRatio, *cPicYuvTrueOrg, refPPS->getScalingWindow(), pcPicCurr->getTrueOrigBuf(), pPPS->getScalingWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true ); #endif #elif JVET_P0592_CHROMA_PHASE const Window& curWindow = pPPS->getConformanceWindow(); int curPicWidth = pPPS->getPicWidthInLumaSamples() - ( curWindow.getWindowLeftOffset() + curWindow.getWindowRightOffset() ) * SPS::getWinUnitX( chromaFormatIDC ); int curPicHeight = pPPS->getPicHeightInLumaSamples() - ( curWindow.getWindowTopOffset() + curWindow.getWindowBottomOffset() ) * SPS::getWinUnitY( chromaFormatIDC ); const Window& refWindow = refPPS->getConformanceWindow(); int refPicWidth = refPPS->getPicWidthInLumaSamples() - ( refWindow.getWindowLeftOffset() + refWindow.getWindowRightOffset() ) * SPS::getWinUnitX( chromaFormatIDC ); int refPicHeight = refPPS->getPicHeightInLumaSamples() - ( refWindow.getWindowTopOffset() + refWindow.getWindowBottomOffset() ) * SPS::getWinUnitY( chromaFormatIDC ); int xScale = ( ( refPicWidth << SCALE_RATIO_BITS ) + ( curPicWidth >> 1 ) ) / curPicWidth; int yScale = ( ( refPicHeight << SCALE_RATIO_BITS ) + ( curPicHeight >> 1 ) ) / curPicHeight; std::pair<int, int> scalingRatio = std::pair<int, int>( xScale, yScale ); Picture::rescalePicture( scalingRatio, *pcPicYuvOrg, refPPS->getConformanceWindow(), pcPicCurr->getOrigBuf(), pPPS->getConformanceWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true, pSPS->getHorCollocatedChromaFlag(), pSPS->getVerCollocatedChromaFlag() ); Picture::rescalePicture( scalingRatio, *cPicYuvTrueOrg, refPPS->getConformanceWindow(), pcPicCurr->getTrueOrigBuf(), pPPS->getConformanceWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true, pSPS->getHorCollocatedChromaFlag(), pSPS->getVerCollocatedChromaFlag() ); #else Picture::rescalePicture( *pcPicYuvOrg, refPPS->getConformanceWindow(), pcPicCurr->getOrigBuf(), pPPS->getConformanceWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true ); Picture::rescalePicture( *cPicYuvTrueOrg, refPPS->getConformanceWindow(), pcPicCurr->getTrueOrigBuf(), pPPS->getConformanceWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true ); #endif } else { pcPicCurr->M_BUFS( 0, PIC_ORIGINAL ).swap( *pcPicYuvOrg ); pcPicCurr->M_BUFS( 0, PIC_TRUE_ORIGINAL ).swap( *cPicYuvTrueOrg ); } #if JVET_P1006_PICTURE_HEADER pcPicCurr->finalInit( *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); #else pcPicCurr->finalInit( *pSPS, *pPPS, m_apss, m_lmcsAPS, m_scalinglistAPS ); #endif #if !JVET_P1004_REMOVE_BRICKS PPS *ptrPPS = ( ppsID < 0 ) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS( ppsID ); ptrPPS->setNumBricksInPic( (int)pcPicCurr->brickMap->bricks.size() ); #endif pcPicCurr->poc = m_iPOCLast; // compute image characteristics if( getUseAdaptiveQP() ) { AQpPreanalyzer::preanalyze( pcPicCurr ); } } if( ( m_iNumPicRcvd == 0 ) || ( !flush && ( m_iPOCLast != 0 ) && ( m_iNumPicRcvd != m_iGOPSize ) && ( m_iGOPSize != 0 ) ) ) { iNumEncoded = 0; return true; } if( m_RCEnableRateControl ) { m_cRateCtrl.initRCGOP( m_iNumPicRcvd ); } m_picIdInGOP = 0; return false; } /** - Application has picture buffer list with size of GOP + 1 - Picture buffer list acts like as ring buffer - End of the list has the latest picture . \param flush cause encoder to encode a partial GOP \param pcPicYuvOrg original YUV picture \param pcPicYuvTrueOrg \param snrCSC \retval rcListPicYuvRecOut list of reconstruction YUV pictures \retval accessUnitsOut list of output access units \retval iNumEncoded number of encoded pictures */ bool EncLib::encode( const InputColourSpaceConversion snrCSC, std::list<PelUnitBuf*>& rcListPicYuvRecOut, int& iNumEncoded ) { // compress GOP m_cGOPEncoder.compressGOP( m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut, false, false, snrCSC, m_printFrameMSE, false, m_picIdInGOP ); m_picIdInGOP++; // go over all pictures in a GOP excluding the first IRAP if( m_picIdInGOP != m_iGOPSize && m_iPOCLast ) { return true; } #if JVET_O0756_CALCULATE_HDRMETRICS m_metricTime = m_cGOPEncoder.getMetricTime(); #endif if( m_RCEnableRateControl ) { m_cRateCtrl.destroyRCGOP(); } iNumEncoded = m_iNumPicRcvd; m_iNumPicRcvd = 0; m_uiNumAllPicCoded += iNumEncoded; return false; } #else /** - Application has picture buffer list with size of GOP + 1 - Picture buffer list acts like as ring buffer - End of the list has the latest picture . \param flush cause encoder to encode a partial GOP \param pcPicYuvOrg original YUV picture \param pcPicYuvTrueOrg \param snrCSC \retval rcListPicYuvRecOut list of reconstruction YUV pictures \retval accessUnitsOut list of output access units \retval iNumEncoded number of encoded pictures */ void EncLib::encode( bool flush, PelStorage* pcPicYuvOrg, PelStorage* cPicYuvTrueOrg, const InputColourSpaceConversion snrCSC, std::list<PelUnitBuf*>& rcListPicYuvRecOut, int& iNumEncoded ) { if (m_compositeRefEnabled && m_cGOPEncoder.getPicBg()->getSpliceFull() && m_iPOCLast >= 10 && m_iNumPicRcvd == 0 && m_cGOPEncoder.getEncodedLTRef() == false) { Picture* picCurr = NULL; xGetNewPicBuffer(rcListPicYuvRecOut, picCurr, 2); const PPS *pps = m_ppsMap.getPS(2); const SPS *sps = m_spsMap.getPS(pps->getSPSId()); picCurr->M_BUFS(0, PIC_ORIGINAL).copyFrom(m_cGOPEncoder.getPicBg()->getRecoBuf()); #if JVET_P1006_PICTURE_HEADER picCurr->finalInit( *sps, *pps, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); #else picCurr->finalInit( *sps, *pps, m_apss, m_lmcsAPS, m_scalinglistAPS ); #endif picCurr->poc = m_iPOCLast - 1; m_iPOCLast -= 2; if (getUseAdaptiveQP()) { AQpPreanalyzer::preanalyze(picCurr); } if (m_RCEnableRateControl) { m_cRateCtrl.initRCGOP(m_iNumPicRcvd); } m_cGOPEncoder.compressGOP(m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut, false, false, snrCSC, m_printFrameMSE, true); #if JVET_O0756_CALCULATE_HDRMETRICS m_metricTime = m_cGOPEncoder.getMetricTime(); #endif m_cGOPEncoder.setEncodedLTRef(true); if (m_RCEnableRateControl) { m_cRateCtrl.destroyRCGOP(); } iNumEncoded = 0; m_iNumPicRcvd = 0; } //PROF_ACCUM_AND_START_NEW_SET( getProfilerPic(), P_GOP_LEVEL ); if (pcPicYuvOrg != NULL) { // get original YUV Picture* pcPicCurr = NULL; int ppsID=-1; // Use default PPS ID #if ER_CHROMA_QP_WCG_PPS if (getWCGChromaQPControl().isEnabled()) { ppsID = getdQPs()[m_iPOCLast / (m_compositeRefEnabled ? 2 : 1) + 1]; ppsID+=(getSwitchPOC() != -1 && (m_iPOCLast+1 >= getSwitchPOC())?1:0); } #endif if( m_rprEnabled && m_uiIntraPeriod == -1 ) { const int poc = m_iPOCLast + ( m_compositeRefEnabled ? 2 : 1 ); if( poc / m_switchPocPeriod % 2 ) { ppsID = ENC_PPS_ID_RPR; } else { ppsID = 0; } } xGetNewPicBuffer( rcListPicYuvRecOut, pcPicCurr, ppsID ); const PPS *pPPS = ( ppsID < 0 ) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS( ppsID ); const SPS *pSPS = m_spsMap.getPS( pPPS->getSPSId() ); if( m_rprEnabled ) { pcPicCurr->M_BUFS( 0, PIC_ORIGINAL_INPUT ).getBuf( COMPONENT_Y ).copyFrom( pcPicYuvOrg->getBuf( COMPONENT_Y ) ); pcPicCurr->M_BUFS( 0, PIC_ORIGINAL_INPUT ).getBuf( COMPONENT_Cb ).copyFrom( pcPicYuvOrg->getBuf( COMPONENT_Cb ) ); pcPicCurr->M_BUFS( 0, PIC_ORIGINAL_INPUT ).getBuf( COMPONENT_Cr ).copyFrom( pcPicYuvOrg->getBuf( COMPONENT_Cr ) ); pcPicCurr->M_BUFS( 0, PIC_TRUE_ORIGINAL_INPUT ).getBuf( COMPONENT_Y ).copyFrom( cPicYuvTrueOrg->getBuf( COMPONENT_Y ) ); pcPicCurr->M_BUFS( 0, PIC_TRUE_ORIGINAL_INPUT ).getBuf( COMPONENT_Cb ).copyFrom( cPicYuvTrueOrg->getBuf( COMPONENT_Cb ) ); pcPicCurr->M_BUFS( 0, PIC_TRUE_ORIGINAL_INPUT ).getBuf( COMPONENT_Cr ).copyFrom( cPicYuvTrueOrg->getBuf( COMPONENT_Cr ) ); const ChromaFormat chromaFormatIDC = pSPS->getChromaFormatIdc(); const PPS *refPPS = m_ppsMap.getPS( 0 ); #if JVET_P0590_SCALING_WINDOW const Window& curScalingWindow = pPPS->getScalingWindow(); int curPicWidth = pPPS->getPicWidthInLumaSamples() - curScalingWindow.getWindowLeftOffset() - curScalingWindow.getWindowRightOffset(); int curPicHeight = pPPS->getPicHeightInLumaSamples() - curScalingWindow.getWindowTopOffset() - curScalingWindow.getWindowBottomOffset(); const Window& refScalingWindow = refPPS->getScalingWindow(); int refPicWidth = refPPS->getPicWidthInLumaSamples() - refScalingWindow.getWindowLeftOffset() - refScalingWindow.getWindowRightOffset(); int refPicHeight = refPPS->getPicHeightInLumaSamples() - refScalingWindow.getWindowTopOffset() - refScalingWindow.getWindowBottomOffset(); int xScale = ( ( refPicWidth << SCALE_RATIO_BITS ) + ( curPicWidth >> 1 ) ) / curPicWidth; int yScale = ( ( refPicHeight << SCALE_RATIO_BITS ) + ( curPicHeight >> 1 ) ) / curPicHeight; std::pair<int, int> scalingRatio = std::pair<int, int>( xScale, yScale ); #if JVET_P0592_CHROMA_PHASE Picture::rescalePicture( scalingRatio, *pcPicYuvOrg, refPPS->getScalingWindow(), pcPicCurr->getOrigBuf(), pPPS->getScalingWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true, pSPS->getHorCollocatedChromaFlag(), pSPS->getVerCollocatedChromaFlag() ); Picture::rescalePicture( scalingRatio, *cPicYuvTrueOrg, refPPS->getScalingWindow(), pcPicCurr->getTrueOrigBuf(), pPPS->getScalingWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true, pSPS->getHorCollocatedChromaFlag(), pSPS->getVerCollocatedChromaFlag() ); #else Picture::rescalePicture( scalingRatio, *pcPicYuvOrg, refPPS->getScalingWindow(), pcPicCurr->getOrigBuf(), pPPS->getScalingWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true ); Picture::rescalePicture( scalingRatio, *cPicYuvTrueOrg, refPPS->getScalingWindow(), pcPicCurr->getTrueOrigBuf(), pPPS->getScalingWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true ); #endif #elif JVET_P0592_CHROMA_PHASE const Window& curWindow = pPPS->getConformanceWindow(); int curPicWidth = pPPS->getPicWidthInLumaSamples() - ( curWindow.getWindowLeftOffset() + curWindow.getWindowRightOffset() ) * SPS::getWinUnitX( chromaFormatIDC ); int curPicHeight = pPPS->getPicHeightInLumaSamples() - ( curWindow.getWindowTopOffset() + curWindow.getWindowBottomOffset() ) * SPS::getWinUnitY( chromaFormatIDC ); const Window& refWindow = refPPS->getConformanceWindow(); int refPicWidth = refPPS->getPicWidthInLumaSamples() - ( refWindow.getWindowLeftOffset() + refWindow.getWindowRightOffset() ) * SPS::getWinUnitX( chromaFormatIDC ); int refPicHeight = refPPS->getPicHeightInLumaSamples() - ( refWindow.getWindowTopOffset() + refWindow.getWindowBottomOffset() ) * SPS::getWinUnitY( chromaFormatIDC ); int xScale = ( ( refPicWidth << SCALE_RATIO_BITS ) + ( curPicWidth >> 1 ) ) / curPicWidth; int yScale = ( ( refPicHeight << SCALE_RATIO_BITS ) + ( curPicHeight >> 1 ) ) / curPicHeight; std::pair<int, int> scalingRatio = std::pair<int, int>( xScale, yScale ); Picture::rescalePicture( scalingRatio, *pcPicYuvOrg, refPPS->getConformanceWindow(), pcPicCurr->getOrigBuf(), pPPS->getConformanceWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true, pSPS->getHorCollocatedChromaFlag(), pSPS->getVerCollocatedChromaFlag() ); Picture::rescalePicture( scalingRatio, *cPicYuvTrueOrg, refPPS->getConformanceWindow(), pcPicCurr->getTrueOrigBuf(), pPPS->getConformanceWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true, pSPS->getHorCollocatedChromaFlag(), pSPS->getVerCollocatedChromaFlag() ); #else Picture::rescalePicture( *pcPicYuvOrg, refPPS->getConformanceWindow(), pcPicCurr->getOrigBuf(), pPPS->getConformanceWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true ); Picture::rescalePicture( *cPicYuvTrueOrg, refPPS->getConformanceWindow(), pcPicCurr->getTrueOrigBuf(), pPPS->getConformanceWindow(), chromaFormatIDC, pSPS->getBitDepths(), true, true ); #endif } else { pcPicCurr->M_BUFS( 0, PIC_ORIGINAL ).swap( *pcPicYuvOrg ); pcPicCurr->M_BUFS( 0, PIC_TRUE_ORIGINAL ).swap( *cPicYuvTrueOrg ); } #if JVET_P1006_PICTURE_HEADER pcPicCurr->finalInit( *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); #else pcPicCurr->finalInit( *pSPS, *pPPS, m_apss, m_lmcsAPS, m_scalinglistAPS ); #endif PPS *ptrPPS = ( ppsID < 0 ) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS( ppsID ); ptrPPS->setNumBricksInPic( (int)pcPicCurr->brickMap->bricks.size() ); pcPicCurr->poc = m_iPOCLast; // compute image characteristics if ( getUseAdaptiveQP() ) { AQpPreanalyzer::preanalyze( pcPicCurr ); } } if ((m_iNumPicRcvd == 0) || (!flush && (m_iPOCLast != 0) && (m_iNumPicRcvd != m_iGOPSize) && (m_iGOPSize != 0))) { iNumEncoded = 0; return; } if ( m_RCEnableRateControl ) { m_cRateCtrl.initRCGOP( m_iNumPicRcvd ); } // compress GOP m_cGOPEncoder.compressGOP(m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut, false, false, snrCSC, m_printFrameMSE , false ); #if JVET_O0756_CALCULATE_HDRMETRICS m_metricTime = m_cGOPEncoder.getMetricTime(); #endif if ( m_RCEnableRateControl ) { m_cRateCtrl.destroyRCGOP(); } iNumEncoded = m_iNumPicRcvd; m_iNumPicRcvd = 0; m_uiNumAllPicCoded += iNumEncoded; } #endif /**------------------------------------------------ Separate interlaced frame into two fields -------------------------------------------------**/ void separateFields(Pel* org, Pel* dstField, uint32_t stride, uint32_t width, uint32_t height, bool isTop) { if (!isTop) { org += stride; } for (int y = 0; y < height>>1; y++) { for (int x = 0; x < width; x++) { dstField[x] = org[x]; } dstField += stride; org += stride*2; } } #if JVET_N0278_FIXES bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* pcPicYuvTrueOrg, const InputColourSpaceConversion snrCSC, std::list<PelUnitBuf*>& rcListPicYuvRecOut, int& iNumEncoded, bool isTff ) { iNumEncoded = 0; bool keepDoing = true; for( int fieldNum = 0; fieldNum < 2; fieldNum++ ) { if( pcPicYuvOrg ) { /* -- field initialization -- */ const bool isTopField = isTff == ( fieldNum == 0 ); Picture *pcField; xGetNewPicBuffer( rcListPicYuvRecOut, pcField, -1 ); for( uint32_t comp = 0; comp < ::getNumberValidComponents( pcPicYuvOrg->chromaFormat ); comp++ ) { const ComponentID compID = ComponentID( comp ); { PelBuf compBuf = pcPicYuvOrg->get( compID ); separateFields( compBuf.buf, pcField->getOrigBuf().get( compID ).buf, compBuf.stride, compBuf.width, compBuf.height, isTopField ); } } { int ppsID = -1; // Use default PPS ID const PPS *pPPS = ( ppsID < 0 ) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS( ppsID ); const SPS *pSPS = m_spsMap.getPS( pPPS->getSPSId() ); #if JVET_P1006_PICTURE_HEADER pcField->finalInit( *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); #else pcField->finalInit( *pSPS, *pPPS, m_apss, m_lmcsAPS, m_scalinglistAPS ); #endif } pcField->poc = m_iPOCLast; pcField->reconstructed = false; pcField->setBorderExtension( false );// where is this normally? pcField->topField = isTopField; // interlaced requirement // compute image characteristics if( getUseAdaptiveQP() ) { AQpPreanalyzer::preanalyze( pcField ); } } if( m_iNumPicRcvd && ( ( flush&&fieldNum == 1 ) || ( m_iPOCLast / 2 ) == 0 || m_iNumPicRcvd == m_iGOPSize ) ) { keepDoing = false; } } return keepDoing; } bool EncLib::encode( const InputColourSpaceConversion snrCSC, std::list<PelUnitBuf*>& rcListPicYuvRecOut, int& iNumEncoded, bool isTff ) { iNumEncoded = 0; for( int fieldNum = 0; fieldNum < 2; fieldNum++ ) { // compress GOP m_cGOPEncoder.compressGOP( m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut, true, isTff, snrCSC, m_printFrameMSE, false, m_picIdInGOP ); #if JVET_O0756_CALCULATE_HDRMETRICS m_metricTime = m_cGOPEncoder.getMetricTime(); #endif m_picIdInGOP++; // go over all pictures in a GOP excluding the first IRAP if( m_picIdInGOP != m_iGOPSize && m_iPOCLast / 2 ) { return true; } iNumEncoded += m_iNumPicRcvd; m_uiNumAllPicCoded += m_iNumPicRcvd; m_iNumPicRcvd = 0; } return false; } #else void EncLib::encode( bool flush, PelStorage* pcPicYuvOrg, PelStorage* pcPicYuvTrueOrg, const InputColourSpaceConversion snrCSC, std::list<PelUnitBuf*>& rcListPicYuvRecOut, int& iNumEncoded, bool isTff ) { iNumEncoded = 0; for (int fieldNum=0; fieldNum<2; fieldNum++) { if (pcPicYuvOrg) { /* -- field initialization -- */ const bool isTopField=isTff==(fieldNum==0); Picture *pcField; xGetNewPicBuffer( rcListPicYuvRecOut, pcField, -1 ); for (uint32_t comp = 0; comp < ::getNumberValidComponents(pcPicYuvOrg->chromaFormat); comp++) { const ComponentID compID = ComponentID(comp); { PelBuf compBuf = pcPicYuvOrg->get( compID ); separateFields( compBuf.buf, pcField->getOrigBuf().get(compID).buf, compBuf.stride, compBuf.width, compBuf.height, isTopField); } } { int ppsID=-1; // Use default PPS ID const PPS *pPPS=(ppsID<0) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS(ppsID); const SPS *pSPS=m_spsMap.getPS(pPPS->getSPSId()); #if JVET_P1006_PICTURE_HEADER pcField->finalInit( *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); #else pcField->finalInit( *pSPS, *pPPS, m_apss, m_lmcsAPS, m_scalinglistAPS ); #endif } pcField->poc = m_iPOCLast; pcField->reconstructed = false; pcField->setBorderExtension(false);// where is this normally? pcField->topField = isTopField; // interlaced requirement // compute image characteristics if ( getUseAdaptiveQP() ) { AQpPreanalyzer::preanalyze( pcField ); } } if ( m_iNumPicRcvd && ((flush&&fieldNum==1) || (m_iPOCLast/2)==0 || m_iNumPicRcvd==m_iGOPSize ) ) { // compress GOP m_cGOPEncoder.compressGOP(m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut, true, isTff, snrCSC, m_printFrameMSE , false ); #if JVET_O0756_CALCULATE_HDRMETRICS m_metricTime = m_cGOPEncoder.getMetricTime(); #endif iNumEncoded += m_iNumPicRcvd; m_uiNumAllPicCoded += m_iNumPicRcvd; m_iNumPicRcvd = 0; } } } #endif // ==================================================================================================================== // Protected member functions // ==================================================================================================================== /** - Application has picture buffer list with size of GOP + 1 - Picture buffer list acts like as ring buffer - End of the list has the latest picture . \retval rpcPic obtained picture buffer */ void EncLib::xGetNewPicBuffer ( std::list<PelUnitBuf*>& rcListPicYuvRecOut, Picture*& rpcPic, int ppsId ) { // rotate he output buffer rcListPicYuvRecOut.push_back( rcListPicYuvRecOut.front() ); rcListPicYuvRecOut.pop_front(); rpcPic=0; // At this point, the SPS and PPS can be considered activated - they are copied to the new Pic. const PPS *pPPS=(ppsId<0) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS(ppsId); CHECK(!(pPPS!=0), "Unspecified error"); const PPS &pps=*pPPS; const SPS *pSPS=m_spsMap.getPS(pps.getSPSId()); CHECK(!(pSPS!=0), "Unspecified error"); const SPS &sps=*pSPS; Slice::sortPicList(m_cListPic); // use an entry in the buffered list if the maximum number that need buffering has been reached: if( m_cListPic.size() >= (uint32_t)( m_iGOPSize + getMaxDecPicBuffering( MAX_TLAYER - 1 ) + 2 ) ) { PicList::iterator iterPic = m_cListPic.begin(); int iSize = int( m_cListPic.size() ); for( int i = 0; i < iSize; i++ ) { rpcPic = *iterPic; #if JVET_N0278_FIXES if( !rpcPic->referenced && rpcPic->layerId == m_layerId ) { break; } else { rpcPic = nullptr; } #else if( !rpcPic->referenced ) { break; } #endif iterPic++; } // If PPS ID is the same, we will assume that it has not changed since it was last used // and return the old object. #if JVET_N0278_FIXES if( rpcPic && pps.getPPSId() != rpcPic->cs->pps->getPPSId() ) #else if (pps.getPPSId() != rpcPic->cs->pps->getPPSId()) #endif { // the IDs differ - free up an entry in the list, and then create a new one, as with the case where the max buffering state has not been reached. rpcPic->destroy(); delete rpcPic; m_cListPic.erase(iterPic); rpcPic=0; } } if (rpcPic==0) { rpcPic = new Picture; #if JVET_N0278_FIXES rpcPic->create( sps.getChromaFormatIdc(), Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + 16, false, m_layerId ); #else rpcPic->create( sps.getChromaFormatIdc(), Size( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples() ), sps.getMaxCUWidth(), sps.getMaxCUWidth() + 16, false ); #endif if( m_rprEnabled ) { rpcPic->M_BUFS( 0, PIC_ORIGINAL_INPUT ).create( sps.getChromaFormatIdc(), Area( Position(), Size( sps.getMaxPicWidthInLumaSamples(), sps.getMaxPicHeightInLumaSamples() ) ) ); rpcPic->M_BUFS( 0, PIC_TRUE_ORIGINAL_INPUT ).create( sps.getChromaFormatIdc(), Area( Position(), Size( sps.getMaxPicWidthInLumaSamples(), sps.getMaxPicHeightInLumaSamples() ) ) ); } if ( getUseAdaptiveQP() ) { #if JVET_P1006_PICTURE_HEADER const uint32_t iMaxDQPLayer = m_picHeader.getCuQpDeltaSubdivIntra()/2+1; #else const uint32_t iMaxDQPLayer = pps.getCuQpDeltaSubdiv()/2+1; #endif rpcPic->aqlayer.resize( iMaxDQPLayer ); for (uint32_t d = 0; d < iMaxDQPLayer; d++) { rpcPic->aqlayer[d] = new AQpLayer( pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples(), sps.getMaxCUWidth() >> d, sps.getMaxCUHeight() >> d ); } } m_cListPic.push_back( rpcPic ); } rpcPic->setBorderExtension( false ); rpcPic->reconstructed = false; rpcPic->referenced = true; rpcPic->getHashMap()->clearAll(); m_iPOCLast += (m_compositeRefEnabled ? 2 : 1); m_iNumPicRcvd++; } void EncLib::xInitVPS(VPS &vps) { // The SPS must have already been set up. // set the VPS profile information. #if !JVET_N0278_FIXES vps.setMaxLayers(1); #endif for (uint32_t i = 0; i < vps.getMaxLayers(); i++) { vps.setVPSIncludedLayerId(0, i); } } void EncLib::xInitDPS(DPS &dps, const SPS &sps, const int dpsId) { // The SPS must have already been set up. // set the DPS profile information. dps.setDecodingParameterSetId(dpsId); dps.setMaxSubLayersMinus1(sps.getMaxTLayers()-1); dps.setProfileTierLevel(*sps.getProfileTierLevel()); } void EncLib::xInitSPS(SPS &sps) { ProfileTierLevel* profileTierLevel = sps.getProfileTierLevel(); ConstraintInfo* cinfo = profileTierLevel->getConstraintInfo(); cinfo->setProgressiveSourceFlag (m_progressiveSourceFlag); cinfo->setInterlacedSourceFlag (m_interlacedSourceFlag); cinfo->setNonPackedConstraintFlag (m_nonPackedConstraintFlag); cinfo->setFrameOnlyConstraintFlag (m_frameOnlyConstraintFlag); cinfo->setIntraOnlyConstraintFlag (m_intraConstraintFlag); cinfo->setMaxBitDepthConstraintIdc (m_maxBitDepthConstraintIdc); cinfo->setMaxChromaFormatConstraintIdc((ChromaFormat)m_maxChromaFormatConstraintIdc); cinfo->setNoQtbttDualTreeIntraConstraintFlag(m_bNoQtbttDualTreeIntraConstraintFlag); cinfo->setNoPartitionConstraintsOverrideConstraintFlag(m_noPartitionConstraintsOverrideConstraintFlag); cinfo->setNoSaoConstraintFlag(m_bNoSaoConstraintFlag); cinfo->setNoAlfConstraintFlag(m_bNoAlfConstraintFlag); cinfo->setNoRefWraparoundConstraintFlag(m_bNoRefWraparoundConstraintFlag); cinfo->setNoTemporalMvpConstraintFlag(m_bNoTemporalMvpConstraintFlag); cinfo->setNoSbtmvpConstraintFlag(m_bNoSbtmvpConstraintFlag); cinfo->setNoAmvrConstraintFlag(m_bNoAmvrConstraintFlag); cinfo->setNoBdofConstraintFlag(m_bNoBdofConstraintFlag); cinfo->setNoDmvrConstraintFlag(m_noDmvrConstraintFlag); cinfo->setNoCclmConstraintFlag(m_bNoCclmConstraintFlag); cinfo->setNoMtsConstraintFlag(m_bNoMtsConstraintFlag); cinfo->setNoSbtConstraintFlag(m_noSbtConstraintFlag); cinfo->setNoAffineMotionConstraintFlag(m_bNoAffineMotionConstraintFlag); cinfo->setNoGbiConstraintFlag(m_bNoGbiConstraintFlag); cinfo->setNoIbcConstraintFlag(m_noIbcConstraintFlag); cinfo->setNoMhIntraConstraintFlag(m_bNoMhIntraConstraintFlag); cinfo->setNoFPelMmvdConstraintFlag(m_noFPelMmvdConstraintFlag); cinfo->setNoTriangleConstraintFlag(m_bNoTriangleConstraintFlag); cinfo->setNoLadfConstraintFlag(m_bNoLadfConstraintFlag); cinfo->setNoTransformSkipConstraintFlag(m_noTransformSkipConstraintFlag); cinfo->setNoBDPCMConstraintFlag(m_noBDPCMConstraintFlag); cinfo->setNoJointCbCrConstraintFlag(m_noJointCbCrConstraintFlag); cinfo->setNoQpDeltaConstraintFlag(m_bNoQpDeltaConstraintFlag); cinfo->setNoDepQuantConstraintFlag(m_bNoDepQuantConstraintFlag); cinfo->setNoSignDataHidingConstraintFlag(m_bNoSignDataHidingConstraintFlag); #if JVET_P0366_NUT_CONSTRAINT_FLAGS cinfo->setNoTrailConstraintFlag(m_noTrailConstraintFlag); cinfo->setNoStsaConstraintFlag(m_noStsaConstraintFlag); cinfo->setNoRaslConstraintFlag(m_noRaslConstraintFlag); cinfo->setNoRadlConstraintFlag(m_noRadlConstraintFlag); cinfo->setNoIdrConstraintFlag(m_noIdrConstraintFlag); cinfo->setNoCraConstraintFlag(m_noCraConstraintFlag); cinfo->setNoGdrConstraintFlag(m_noGdrConstraintFlag); cinfo->setNoApsConstraintFlag(m_noApsConstraintFlag); #endif profileTierLevel->setLevelIdc (m_level); profileTierLevel->setTierFlag (m_levelTier); profileTierLevel->setProfileIdc (m_profile); profileTierLevel->setNumSubProfile(m_numSubProfile); for (int k = 0; k < m_numSubProfile; k++) { profileTierLevel->setSubProfileIdc(k, m_subProfile[k]); } /* XXX: should Main be marked as compatible with still picture? */ /* XXX: may be a good idea to refactor the above into a function * that chooses the actual compatibility based upon options */ sps.setMaxPicWidthInLumaSamples( m_iSourceWidth ); sps.setMaxPicHeightInLumaSamples( m_iSourceHeight ); sps.setMaxCUWidth ( m_maxCUWidth ); sps.setMaxCUHeight ( m_maxCUHeight ); sps.setMaxCodingDepth ( m_maxTotalCUDepth ); sps.setChromaFormatIdc ( m_chromaFormatIDC ); sps.setLog2DiffMaxMinCodingBlockSize(m_log2DiffMaxMinCodingBlockSize); sps.setCTUSize ( m_CTUSize ); sps.setSplitConsOverrideEnabledFlag ( m_useSplitConsOverride ); sps.setMinQTSizes ( m_uiMinQT ); sps.setMaxMTTHierarchyDepth ( m_uiMaxMTTHierarchyDepth, m_uiMaxMTTHierarchyDepthI, m_uiMaxMTTHierarchyDepthIChroma ); unsigned maxBtSize[3], maxTtSize[3]; memcpy(maxBtSize, m_uiMinQT, sizeof(maxBtSize)); memcpy(maxTtSize, m_uiMinQT, sizeof(maxTtSize)); if (m_uiMaxMTTHierarchyDepth) { maxBtSize[1] = std::min(m_CTUSize, (unsigned)MAX_BT_SIZE_INTER); maxTtSize[1] = std::min(m_CTUSize, (unsigned)MAX_TT_SIZE_INTER); } if (m_uiMaxMTTHierarchyDepthI) { maxBtSize[0] = std::min(m_CTUSize, (unsigned)MAX_BT_SIZE); maxTtSize[0] = std::min(m_CTUSize, (unsigned)MAX_TT_SIZE); } if (m_uiMaxMTTHierarchyDepthIChroma) { maxBtSize[2] = std::min(m_CTUSize, (unsigned)MAX_BT_SIZE_C); maxTtSize[2] = std::min(m_CTUSize, (unsigned)MAX_TT_SIZE_C); } sps.setMaxBTSize ( maxBtSize[1], maxBtSize[0], maxBtSize[2] ); sps.setMaxTTSize ( maxTtSize[1], maxTtSize[0], maxTtSize[2] ); sps.setIDRRefParamListPresent ( m_idrRefParamList ); sps.setUseDualITree ( m_dualITree ); sps.setUseLFNST ( m_LFNST ); sps.setSBTMVPEnabledFlag ( m_SubPuMvpMode ); sps.setAMVREnabledFlag ( m_ImvMode != IMV_OFF ); sps.setBDOFEnabledFlag ( m_BIO ); sps.setUseAffine ( m_Affine ); sps.setUseAffineType ( m_AffineType ); sps.setUsePROF ( m_PROF ); sps.setUseLMChroma ( m_LMChroma ? true : false ); #if JVET_P0592_CHROMA_PHASE sps.setHorCollocatedChromaFlag( m_horCollocatedChromaFlag ); sps.setVerCollocatedChromaFlag( m_verCollocatedChromaFlag ); #else sps.setCclmCollocatedChromaFlag( m_cclmCollocatedChromaFlag ); #endif sps.setUseMTS ( m_IntraMTS || m_InterMTS || m_ImplicitMTS ); sps.setUseIntraMTS ( m_IntraMTS ); sps.setUseInterMTS ( m_InterMTS ); sps.setUseSBT ( m_SBT ); #if !JVET_P0983_REMOVE_SPS_SBT_MAX_SIZE_FLAG if( sps.getUseSBT() ) { sps.setMaxSbtSize ( std::min((int)(1 << m_log2MaxTbSize), m_iSourceWidth >= 1920 ? 64 : 32) ); } #endif sps.setUseSMVD ( m_SMVD ); sps.setUseGBi ( m_GBi ); #if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET sps.setLadfEnabled ( m_LadfEnabled ); if ( m_LadfEnabled ) { sps.setLadfNumIntervals ( m_LadfNumIntervals ); for ( int k = 0; k < m_LadfNumIntervals; k++ ) { sps.setLadfQpOffset( m_LadfQpOffset[k], k ); sps.setLadfIntervalLowerBound( m_LadfIntervalLowerBound[k], k ); } CHECK( m_LadfIntervalLowerBound[0] != 0, "abnormal value set to LadfIntervalLowerBound[0]" ); } #endif sps.setUseMHIntra ( m_MHIntra ); sps.setUseTriangle ( m_Triangle ); sps.setUseMMVD ( m_MMVD ); sps.setFpelMmvdEnabledFlag (( m_MMVD ) ? m_allowDisFracMMVD : false); #if JVET_P0314_PROF_BDOF_DMVR_HLS sps.setBdofControlPresentFlag(m_BIO); sps.setDmvrControlPresentFlag(m_DMVR); sps.setProfControlPresentFlag(m_PROF); #else sps.setBdofDmvrSlicePresentFlag(m_DMVR || m_BIO); #endif sps.setAffineAmvrEnabledFlag ( m_AffineAmvr ); sps.setUseDMVR ( m_DMVR ); #if JVET_P0517_ADAPTIVE_COLOR_TRANSFORM sps.setUseColorTrans(m_useColorTrans); #endif sps.setPLTMode ( m_PLTMode); sps.setIBCFlag ( m_IBCMode); sps.setWrapAroundEnabledFlag ( m_wrapAround ); sps.setWrapAroundOffset ( m_wrapAroundOffset ); // ADD_NEW_TOOL : (encoder lib) set tool enabling flags and associated parameters here sps.setUseISP ( m_ISP ); sps.setUseReshaper ( m_lumaReshapeEnable ); sps.setUseMIP ( m_MIP ); int minCUSize = sps.getMaxCUWidth() >> sps.getLog2DiffMaxMinCodingBlockSize(); int log2MinCUSize = 0; while(minCUSize > 1) { minCUSize >>= 1; log2MinCUSize++; } sps.setLog2MinCodingBlockSize(log2MinCUSize); #if JVET_P0578_MINIMUM_CU_SIZE_CONSTRAINT CHECK(log2MinCUSize > std::min(6, floorLog2(sps.getMaxCUWidth())), "log2_min_luma_coding_block_size_minus2 shall be in the range of 0 to min (4, log2_ctu_size - 2)"); #endif #if JVET_P0347_MAX_MTT_DEPTH_CONSTRAINT CHECK(m_uiMaxMTTHierarchyDepth > 2 * (floorLog2(sps.getCTUSize()) - sps.getLog2MinCodingBlockSize()), "sps_max_mtt_hierarchy_depth_inter_slice shall be in the range 0 to 2*(ctbLog2SizeY - log2MinCUSize)"); CHECK(m_uiMaxMTTHierarchyDepthI > 2 * (floorLog2(sps.getCTUSize()) - sps.getLog2MinCodingBlockSize()), "sps_max_mtt_hierarchy_depth_intra_slice_luma shall be in the range 0 to 2*(ctbLog2SizeY - log2MinCUSize)"); CHECK(m_uiMaxMTTHierarchyDepthIChroma > 2 * (floorLog2(sps.getCTUSize()) - sps.getLog2MinCodingBlockSize()), "sps_max_mtt_hierarchy_depth_intra_slice_chroma shall be in the range 0 to 2*(ctbLog2SizeY - log2MinCUSize)"); #endif sps.setTransformSkipEnabledFlag(m_useTransformSkip); #if JVET_P0059_CHROMA_BDPCM sps.setBDPCMEnabled(m_useBDPCM); #else sps.setBDPCMEnabledFlag(m_useBDPCM); #endif sps.setSPSTemporalMVPEnabledFlag((getTMVPModeId() == 2 || getTMVPModeId() == 1)); sps.setLog2MaxTbSize ( m_log2MaxTbSize ); for (uint32_t channelType = 0; channelType < MAX_NUM_CHANNEL_TYPE; channelType++) { sps.setBitDepth (ChannelType(channelType), m_bitDepth[channelType] ); sps.setQpBDOffset (ChannelType(channelType), (6 * (m_bitDepth[channelType] - 8))); sps.setMinQpPrimeTsMinus4(ChannelType(channelType), (6 * (m_bitDepth[channelType] - m_inputBitDepth[channelType]))); } sps.setUseWP( m_useWeightedPred ); sps.setUseWPBiPred( m_useWeightedBiPred ); sps.setSAOEnabledFlag( m_bUseSAO ); sps.setJointCbCrEnabledFlag( m_JointCbCrMode ); sps.setMaxTLayers( m_maxTempLayer ); sps.setTemporalIdNestingFlag( ( m_maxTempLayer == 1 ) ? true : false ); for (int i = 0; i < std::min(sps.getMaxTLayers(), (uint32_t) MAX_TLAYER); i++ ) { sps.setMaxDecPicBuffering(m_maxDecPicBuffering[i], i); sps.setNumReorderPics(m_numReorderPics[i], i); } sps.setScalingListFlag ( (m_useScalingListId == SCALING_LIST_OFF) ? 0 : 1 ); sps.setALFEnabledFlag( m_alf ); sps.setVuiParametersPresentFlag(getVuiParametersPresentFlag()); if (sps.getVuiParametersPresentFlag()) { VUI* pcVUI = sps.getVuiParameters(); pcVUI->setAspectRatioInfoPresentFlag(getAspectRatioInfoPresentFlag()); pcVUI->setAspectRatioIdc(getAspectRatioIdc()); pcVUI->setSarWidth(getSarWidth()); pcVUI->setSarHeight(getSarHeight()); pcVUI->setColourDescriptionPresentFlag(getColourDescriptionPresentFlag()); pcVUI->setColourPrimaries(getColourPrimaries()); pcVUI->setTransferCharacteristics(getTransferCharacteristics()); pcVUI->setMatrixCoefficients(getMatrixCoefficients()); pcVUI->setFieldSeqFlag(false); pcVUI->setChromaLocInfoPresentFlag(getChromaLocInfoPresentFlag()); pcVUI->setChromaSampleLocTypeTopField(getChromaSampleLocTypeTopField()); pcVUI->setChromaSampleLocTypeBottomField(getChromaSampleLocTypeBottomField()); pcVUI->setChromaSampleLocType(getChromaSampleLocType()); pcVUI->setOverscanInfoPresentFlag(getOverscanInfoPresentFlag()); pcVUI->setOverscanAppropriateFlag(getOverscanAppropriateFlag()); pcVUI->setVideoSignalTypePresentFlag(getVideoSignalTypePresentFlag()); pcVUI->setVideoFullRangeFlag(getVideoFullRangeFlag()); } sps.setNumLongTermRefPicSPS(NUM_LONG_TERM_REF_PIC_SPS); CHECK(!(NUM_LONG_TERM_REF_PIC_SPS <= MAX_NUM_LONG_TERM_REF_PICS), "Unspecified error"); for (int k = 0; k < NUM_LONG_TERM_REF_PIC_SPS; k++) { sps.setLtRefPicPocLsbSps(k, 0); sps.setUsedByCurrPicLtSPSFlag(k, 0); } #if JVET_P0667_QP_OFFSET_TABLE_SIGNALING_JCCR int numQpTables = m_chromaQpMappingTableParams.getSameCQPTableForAllChromaFlag() ? 1 : (sps.getJointCbCrEnabledFlag() ? 3 : 2); m_chromaQpMappingTableParams.setNumQpTables(numQpTables); #endif sps.setChromaQpMappingTableFromParams(m_chromaQpMappingTableParams, sps.getQpBDOffset(CHANNEL_TYPE_CHROMA)); sps.derivedChromaQPMappingTables(); #if U0132_TARGET_BITS_SATURATION if( getPictureTimingSEIEnabled() || getDecodingUnitInfoSEIEnabled() || getCpbSaturationEnabled() ) #else if( getPictureTimingSEIEnabled() || getDecodingUnitInfoSEIEnabled() ) #endif { xInitHrdParameters(sps); } if( getBufferingPeriodSEIEnabled() || getPictureTimingSEIEnabled() || getDecodingUnitInfoSEIEnabled() ) { sps.setHrdParametersPresentFlag( true ); } // Set up SPS range extension settings sps.getSpsRangeExtension().setTransformSkipRotationEnabledFlag(m_transformSkipRotationEnabledFlag); sps.getSpsRangeExtension().setTransformSkipContextEnabledFlag(m_transformSkipContextEnabledFlag); for (uint32_t signallingModeIndex = 0; signallingModeIndex < NUMBER_OF_RDPCM_SIGNALLING_MODES; signallingModeIndex++) { sps.getSpsRangeExtension().setRdpcmEnabledFlag(RDPCMSignallingMode(signallingModeIndex), m_rdpcmEnabledFlag[signallingModeIndex]); } sps.getSpsRangeExtension().setExtendedPrecisionProcessingFlag(m_extendedPrecisionProcessingFlag); sps.getSpsRangeExtension().setIntraSmoothingDisabledFlag( m_intraSmoothingDisabledFlag ); sps.getSpsRangeExtension().setHighPrecisionOffsetsEnabledFlag(m_highPrecisionOffsetsEnabledFlag); sps.getSpsRangeExtension().setPersistentRiceAdaptationEnabledFlag(m_persistentRiceAdaptationEnabledFlag); sps.getSpsRangeExtension().setCabacBypassAlignmentEnabledFlag(m_cabacBypassAlignmentEnabledFlag); if( m_uiIntraPeriod < 0 ) { sps.setRPL1CopyFromRPL0Flag( true ); } #if JVET_P1006_PICTURE_HEADER sps.setNumSubPics(1); // TODO: modify for subpicture support sps.setSubPicIdSignallingPresentFlag(false); sps.setSubPicIdLen(16); for(int picIdx=0; picIdx<MAX_NUM_SUB_PICS; picIdx++) { sps.setSubPicId(picIdx, picIdx); } sps.setLoopFilterAcrossVirtualBoundariesDisabledFlag( m_loopFilterAcrossVirtualBoundariesDisabledFlag ); sps.setNumVerVirtualBoundaries ( m_numVerVirtualBoundaries ); sps.setNumHorVirtualBoundaries ( m_numHorVirtualBoundaries ); for( unsigned int i = 0; i < m_numVerVirtualBoundaries; i++ ) { sps.setVirtualBoundariesPosX ( m_virtualBoundariesPosX[i], i ); } for( unsigned int i = 0; i < m_numHorVirtualBoundaries; i++ ) { sps.setVirtualBoundariesPosY ( m_virtualBoundariesPosY[i], i ); } #endif #if JVET_P0590_SCALING_WINDOW sps.setRprEnabledFlag( m_rprEnabled ); #endif } void EncLib::xInitHrdParameters(SPS &sps) { m_encHRD.initHRDParameters((EncCfg*) this); HRDParameters *hrdParams = sps.getHrdParameters(); *hrdParams = m_encHRD.getHRDParameters(); TimingInfo *timingInfo = sps.getTimingInfo(); *timingInfo = m_encHRD.getTimingInfo(); } void EncLib::xInitPPS(PPS &pps, const SPS &sps) { // pps ID already initialised. pps.setSPSId(sps.getSPSId()); pps.setConstantSliceHeaderParamsEnabledFlag(getConstantSliceHeaderParamsEnabledFlag()); pps.setPPSDepQuantEnabledIdc(getPPSDepQuantEnabledIdc()); pps.setPPSRefPicListSPSIdc0(getPPSRefPicListSPSIdc0()); pps.setPPSRefPicListSPSIdc1(getPPSRefPicListSPSIdc1()); #if !JVET_P0206_TMVP_flags pps.setPPSTemporalMVPEnabledIdc(getPPSTemporalMVPEnabledIdc()); #endif pps.setPPSMvdL1ZeroIdc(getPPSMvdL1ZeroIdc()); pps.setPPSCollocatedFromL0Idc(getPPSCollocatedFromL0Idc()); pps.setPPSSixMinusMaxNumMergeCandPlus1(getPPSSixMinusMaxNumMergeCandPlus1()); #if !JVET_P0152_REMOVE_PPS_NUM_SUBBLOCK_MERGE_CAND pps.setPPSFiveMinusMaxNumSubblockMergeCandPlus1(getPPSFiveMinusMaxNumSubblockMergeCandPlus1()); #endif pps.setPPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1(getPPSMaxNumMergeCandMinusMaxNumTriangleCandPlus1()); #if JVET_P1006_PICTURE_HEADER pps.setNumSubPics(sps.getNumSubPics()); pps.setSubPicIdSignallingPresentFlag(false); pps.setSubPicIdLen(sps.getSubPicIdLen()); for(int picIdx=0; picIdx<pps.getNumSubPics(); picIdx++) { pps.setSubPicId(picIdx, sps.getSubPicId(picIdx)); } #endif bool bUseDQP = (getCuQpDeltaSubdiv() > 0)? true : false; if((getMaxDeltaQP() != 0 )|| getUseAdaptiveQP()) { bUseDQP = true; } #if SHARP_LUMA_DELTA_QP if ( getLumaLevelToDeltaQPMapping().isEnabled() ) { bUseDQP = true; } #endif #if ENABLE_QPA if (getUsePerceptQPA() && !bUseDQP) { CHECK( m_cuQpDeltaSubdiv != 0, "max. delta-QP subdiv must be zero!" ); bUseDQP = (getBaseQP() < 38) && (getSourceWidth() > 512 || getSourceHeight() > 320); } #endif if (m_costMode==COST_SEQUENCE_LEVEL_LOSSLESS || m_costMode==COST_LOSSLESS_CODING) { bUseDQP=false; } if ( m_RCEnableRateControl ) { pps.setUseDQP(true); #if !JVET_P1006_PICTURE_HEADER pps.setCuQpDeltaSubdiv( 0 ); #endif } else if(bUseDQP) { pps.setUseDQP(true); #if !JVET_P1006_PICTURE_HEADER pps.setCuQpDeltaSubdiv( m_cuQpDeltaSubdiv ); #endif } else { pps.setUseDQP(false); #if !JVET_P1006_PICTURE_HEADER pps.setCuQpDeltaSubdiv( 0 ); #endif } if ( m_cuChromaQpOffsetSubdiv >= 0 ) { #if !JVET_P1006_PICTURE_HEADER pps.setCuChromaQpOffsetSubdiv(m_cuChromaQpOffsetSubdiv); #endif pps.clearChromaQpOffsetList(); pps.setChromaQpOffsetListEntry(1, 6, 6, 6); /* todo, insert table entries from command line (NB, 0 should not be touched) */ } else { #if !JVET_P1006_PICTURE_HEADER pps.setCuChromaQpOffsetSubdiv(0); #endif pps.clearChromaQpOffsetList(); } pps.getPpsRangeExtension().setCrossComponentPredictionEnabledFlag(m_crossComponentPredictionEnabledFlag); pps.getPpsRangeExtension().setLog2SaoOffsetScale(CHANNEL_TYPE_LUMA, m_log2SaoOffsetScale[CHANNEL_TYPE_LUMA ]); pps.getPpsRangeExtension().setLog2SaoOffsetScale(CHANNEL_TYPE_CHROMA, m_log2SaoOffsetScale[CHANNEL_TYPE_CHROMA]); { int baseQp = 26; if( 16 == getGOPSize() ) { baseQp = getBaseQP()-24; } else { baseQp = getBaseQP()-26; } const int maxDQP = 37; const int minDQP = -26 + sps.getQpBDOffset(CHANNEL_TYPE_LUMA); pps.setPicInitQPMinus26( std::min( maxDQP, std::max( minDQP, baseQp ) )); } #if JVET_P0667_QP_OFFSET_TABLE_SIGNALING_JCCR if (sps.getJointCbCrEnabledFlag() == false || getChromaFormatIdc() == CHROMA_400) { pps.setJointCbCrQpOffsetPresentFlag(false); } else { pps.setJointCbCrQpOffsetPresentFlag(true); } #endif #if ER_CHROMA_QP_WCG_PPS if (getWCGChromaQPControl().isEnabled()) { const int baseQp=m_iQP+pps.getPPSId(); const double chromaQp = m_wcgChromaQpControl.chromaQpScale * baseQp + m_wcgChromaQpControl.chromaQpOffset; const double dcbQP = m_wcgChromaQpControl.chromaCbQpScale * chromaQp; const double dcrQP = m_wcgChromaQpControl.chromaCrQpScale * chromaQp; const int cbQP =(int)(dcbQP + ( dcbQP < 0 ? -0.5 : 0.5) ); const int crQP =(int)(dcrQP + ( dcrQP < 0 ? -0.5 : 0.5) ); pps.setQpOffset(COMPONENT_Cb, Clip3( -12, 12, min(0, cbQP) + m_chromaCbQpOffset )); pps.setQpOffset(COMPONENT_Cr, Clip3( -12, 12, min(0, crQP) + m_chromaCrQpOffset)); #if JVET_P0667_QP_OFFSET_TABLE_SIGNALING_JCCR if(pps.getJointCbCrQpOffsetPresentFlag()) pps.setQpOffset(JOINT_CbCr, Clip3(-12, 12, (min(0, cbQP) + min(0, crQP)) / 2 + m_chromaCbCrQpOffset)); else pps.setQpOffset(JOINT_CbCr, 0); #else pps.setQpOffset(JOINT_CbCr, Clip3( -12, 12, ( min(0, cbQP) + min(0, crQP) ) / 2 + m_chromaCbCrQpOffset)); #endif } else { #endif pps.setQpOffset(COMPONENT_Cb, m_chromaCbQpOffset ); pps.setQpOffset(COMPONENT_Cr, m_chromaCrQpOffset ); #if JVET_P0667_QP_OFFSET_TABLE_SIGNALING_JCCR if (pps.getJointCbCrQpOffsetPresentFlag()) pps.setQpOffset(JOINT_CbCr, m_chromaCbCrQpOffset); else pps.setQpOffset(JOINT_CbCr, 0); #else pps.setQpOffset(JOINT_CbCr, m_chromaCbCrQpOffset ); #endif #if ER_CHROMA_QP_WCG_PPS } #endif #if W0038_CQP_ADJ bool bChromaDeltaQPEnabled = false; { bChromaDeltaQPEnabled = ( m_sliceChromaQpOffsetIntraOrPeriodic[0] || m_sliceChromaQpOffsetIntraOrPeriodic[1] ); if( !bChromaDeltaQPEnabled ) { for( int i=0; i<m_iGOPSize; i++ ) { if( m_GOPList[i].m_CbQPoffset || m_GOPList[i].m_CrQPoffset ) { bChromaDeltaQPEnabled = true; break; } } } } #if ENABLE_QPA if ((getUsePerceptQPA() || getSliceChromaOffsetQpPeriodicity() > 0) && (getChromaFormatIdc() != CHROMA_400)) { bChromaDeltaQPEnabled = true; } #endif pps.setSliceChromaQpFlag(bChromaDeltaQPEnabled); #endif if ( !pps.getSliceChromaQpFlag() && sps.getUseDualITree() && (getChromaFormatIdc() != CHROMA_400)) { pps.setSliceChromaQpFlag(m_chromaCbQpOffsetDualTree != 0 || m_chromaCrQpOffsetDualTree != 0 || m_chromaCbCrQpOffsetDualTree != 0); } pps.setEntropyCodingSyncEnabledFlag( m_entropyCodingSyncEnabledFlag ); #if JVET_P1004_REMOVE_BRICKS pps.setNoPicPartitionFlag( m_noPicPartitionFlag ); if( m_noPicPartitionFlag == false ) { pps.setLog2CtuSize( ceilLog2( sps.getCTUSize()) ); pps.setNumExpTileColumns( (uint32_t) m_tileColumnWidth.size() ); pps.setNumExpTileRows( (uint32_t) m_tileRowHeight.size() ); pps.setTileColumnWidths( m_tileColumnWidth ); pps.setTileRowHeights( m_tileRowHeight ); pps.initTiles(); pps.setRectSliceFlag( m_rectSliceFlag ); if( m_rectSliceFlag ) { pps.setNumSlicesInPic( m_numSlicesInPic ); pps.setTileIdxDeltaPresentFlag( m_tileIdxDeltaPresentFlag ); pps.setRectSlices( m_rectSlices ); pps.initRectSliceMap( ); } else { pps.initRasterSliceMap( m_rasterSliceSize ); } pps.setLoopFilterAcrossTilesEnabledFlag( m_bLFCrossTileBoundaryFlag ); pps.setLoopFilterAcrossSlicesEnabledFlag( m_bLFCrossSliceBoundaryFlag ); } else { pps.setLog2CtuSize( ceilLog2( sps.getCTUSize()) ); pps.setNumExpTileColumns(1); pps.setNumExpTileRows(1); pps.addTileColumnWidth( pps.getPicWidthInCtu( ) ); pps.addTileRowHeight( pps.getPicHeightInCtu( ) ); pps.initTiles(); pps.setRectSliceFlag( 1 ); pps.setNumSlicesInPic( 1 ); pps.initRectSlices( ); pps.setTileIdxDeltaPresentFlag( 0 ); pps.setSliceTileIdx( 0, 0 ); pps.initRectSliceMap( ); pps.setLoopFilterAcrossTilesEnabledFlag( true ); pps.setLoopFilterAcrossSlicesEnabledFlag( true ); } #else pps.setSingleTileInPicFlag((m_iNumColumnsMinus1 == 0 && m_iNumRowsMinus1 == 0)); #endif pps.setUseWP( m_useWeightedPred ); pps.setWPBiPred( m_useWeightedBiPred ); pps.setOutputFlagPresentFlag( false ); if ( getDeblockingFilterMetric() ) { pps.setDeblockingFilterOverrideEnabledFlag(true); pps.setPPSDeblockingFilterDisabledFlag(false); } else { pps.setDeblockingFilterOverrideEnabledFlag( !getLoopFilterOffsetInPPS() ); pps.setPPSDeblockingFilterDisabledFlag( getLoopFilterDisable() ); } if (! pps.getPPSDeblockingFilterDisabledFlag()) { pps.setDeblockingFilterBetaOffsetDiv2( getLoopFilterBetaOffset() ); pps.setDeblockingFilterTcOffsetDiv2( getLoopFilterTcOffset() ); } else { pps.setDeblockingFilterBetaOffsetDiv2(0); pps.setDeblockingFilterTcOffsetDiv2(0); } // deblockingFilterControlPresentFlag is true if any of the settings differ from the inferred values: const bool deblockingFilterControlPresentFlag = pps.getDeblockingFilterOverrideEnabledFlag() || pps.getPPSDeblockingFilterDisabledFlag() || pps.getDeblockingFilterBetaOffsetDiv2() != 0 || pps.getDeblockingFilterTcOffsetDiv2() != 0; pps.setDeblockingFilterControlPresentFlag(deblockingFilterControlPresentFlag); pps.setCabacInitPresentFlag(CABAC_INIT_PRESENT_FLAG); pps.setLoopFilterAcrossSlicesEnabledFlag( m_bLFCrossSliceBoundaryFlag ); int histogram[MAX_NUM_REF + 1]; for( int i = 0; i <= MAX_NUM_REF; i++ ) { histogram[i]=0; } for( int i = 0; i < getGOPSize(); i++) { CHECK(!(getRPLEntry(0, i).m_numRefPicsActive >= 0 && getRPLEntry(0, i).m_numRefPicsActive <= MAX_NUM_REF), "Unspecified error"); histogram[getRPLEntry(0, i).m_numRefPicsActive]++; } int maxHist=-1; int bestPos=0; for( int i = 0; i <= MAX_NUM_REF; i++ ) { if(histogram[i]>maxHist) { maxHist=histogram[i]; bestPos=i; } } CHECK(!(bestPos <= 15), "Unspecified error"); pps.setNumRefIdxL0DefaultActive(bestPos); pps.setNumRefIdxL1DefaultActive(bestPos); pps.setTransquantBypassEnabledFlag(getTransquantBypassEnabledFlag()); pps.setLog2MaxTransformSkipBlockSize(m_log2MaxTransformSkipBlockSize); #if !JVET_P1004_REMOVE_BRICKS xInitPPSforTiles(pps); #endif #if JVET_P1006_PICTURE_HEADER pps.setPictureHeaderExtensionPresentFlag(false); #else pps.setLoopFilterAcrossVirtualBoundariesDisabledFlag( m_loopFilterAcrossVirtualBoundariesDisabledFlag ); pps.setNumVerVirtualBoundaries ( m_numVerVirtualBoundaries ); pps.setNumHorVirtualBoundaries ( m_numHorVirtualBoundaries ); for( unsigned int i = 0; i < m_numVerVirtualBoundaries; i++ ) { pps.setVirtualBoundariesPosX ( m_virtualBoundariesPosX[i], i ); } for( unsigned int i = 0; i < m_numHorVirtualBoundaries; i++ ) { pps.setVirtualBoundariesPosY ( m_virtualBoundariesPosY[i], i ); } #endif pps.pcv = new PreCalcValues( sps, pps, true ); pps.setRpl1IdxPresentFlag(sps.getRPL1IdxPresentFlag()); } #if JVET_P1006_PICTURE_HEADER void EncLib::xInitPicHeader(PicHeader &picHeader, const SPS &sps, const PPS &pps) { int i; picHeader.initPicHeader(); // parameter sets picHeader.setSPSId( sps.getSPSId() ); picHeader.setPPSId( pps.getPPSId() ); // merge list sizes picHeader.setMaxNumMergeCand ( getMaxNumMergeCand() ); picHeader.setMaxNumAffineMergeCand( getMaxNumAffineMergeCand() ); picHeader.setMaxNumTriangleCand ( getMaxNumTriangleCand() ); picHeader.setMaxNumIBCMergeCand ( getMaxNumIBCMergeCand() ); // copy partitioning constraints from SPS picHeader.setSplitConsOverrideFlag(false); picHeader.setMinQTSizes( sps.getMinQTSizes() ); picHeader.setMaxMTTHierarchyDepths( sps.getMaxMTTHierarchyDepths() ); picHeader.setMaxBTSizes( sps.getMaxBTSizes() ); picHeader.setMaxTTSizes( sps.getMaxTTSizes() ); // quantization picHeader.setDepQuantEnabledFlag( getDepQuantEnabledFlag() ); picHeader.setSignDataHidingEnabledFlag( getSignDataHidingEnabledFlag() ); bool bUseDQP = (getCuQpDeltaSubdiv() > 0)? true : false; if( (getMaxDeltaQP() != 0 )|| getUseAdaptiveQP() ) { bUseDQP = true; } #if SHARP_LUMA_DELTA_QP if( getLumaLevelToDeltaQPMapping().isEnabled() ) { bUseDQP = true; } #endif #if ENABLE_QPA if( getUsePerceptQPA() && !bUseDQP ) { CHECK( m_cuQpDeltaSubdiv != 0, "max. delta-QP subdiv must be zero!" ); bUseDQP = (getBaseQP() < 38) && (getSourceWidth() > 512 || getSourceHeight() > 320); } #endif if( m_costMode==COST_SEQUENCE_LEVEL_LOSSLESS || m_costMode==COST_LOSSLESS_CODING ) { bUseDQP=false; } if( m_RCEnableRateControl ) { picHeader.setCuQpDeltaSubdivIntra( 0 ); picHeader.setCuQpDeltaSubdivInter( 0 ); } else if( bUseDQP ) { picHeader.setCuQpDeltaSubdivIntra( m_cuQpDeltaSubdiv ); picHeader.setCuQpDeltaSubdivInter( m_cuQpDeltaSubdiv ); } else { picHeader.setCuQpDeltaSubdivIntra( 0 ); picHeader.setCuQpDeltaSubdivInter( 0 ); } if( m_cuChromaQpOffsetSubdiv >= 0 ) { picHeader.setCuChromaQpOffsetSubdivIntra(m_cuChromaQpOffsetSubdiv); picHeader.setCuChromaQpOffsetSubdivInter(m_cuChromaQpOffsetSubdiv); } else { picHeader.setCuChromaQpOffsetSubdivIntra(0); picHeader.setCuChromaQpOffsetSubdivInter(0); } // sub-pictures picHeader.setSubPicIdSignallingPresentFlag(sps.getSubPicIdSignallingPresentFlag()); picHeader.setSubPicIdLen(sps.getSubPicIdLen()); for(i=0; i<sps.getNumSubPics(); i++) { picHeader.setSubPicId(i, sps.getSubPicId(i)); } // virtual boundaries picHeader.setLoopFilterAcrossVirtualBoundariesDisabledFlag(sps.getLoopFilterAcrossVirtualBoundariesDisabledFlag()); picHeader.setNumVerVirtualBoundaries(sps.getNumVerVirtualBoundaries()); picHeader.setNumHorVirtualBoundaries(sps.getNumHorVirtualBoundaries()); for(i=0; i<3; i++) { picHeader.setVirtualBoundariesPosX(sps.getVirtualBoundariesPosX(i), i); picHeader.setVirtualBoundariesPosY(sps.getVirtualBoundariesPosY(i), i); } // gradual decoder refresh flag picHeader.setGdrPicFlag(false); // BDOF / DMVR / PROF #if JVET_P0314_PROF_BDOF_DMVR_HLS picHeader.setDisBdofFlag(false); picHeader.setDisDmvrFlag(false); picHeader.setDisProfFlag(false); #else picHeader.setDisBdofDmvrFlag(false); #endif } #endif void EncLib::xInitAPS(APS &aps) { //Do nothing now } void EncLib::xInitRPL(SPS &sps, bool isFieldCoding) { ReferencePictureList* rpl; int numRPLCandidates = getRPLCandidateSize(0); sps.createRPLList0(numRPLCandidates); sps.createRPLList1(numRPLCandidates); RPLList* rplList = 0; for (int i = 0; i < 2; i++) { rplList = (i == 0) ? sps.getRPLList0() : sps.getRPLList1(); for (int j = 0; j < numRPLCandidates; j++) { const RPLEntry &ge = getRPLEntry(i, j); rpl = rplList->getReferencePictureList(j); rpl->setNumberOfShorttermPictures(ge.m_numRefPics); rpl->setNumberOfLongtermPictures(0); //Hardcoded as 0 for now. need to update this when implementing LTRP rpl->setNumberOfActivePictures(ge.m_numRefPicsActive); rpl->setLtrpInSliceHeaderFlag(ge.m_ltrp_in_slice_header_flag); for (int k = 0; k < ge.m_numRefPics; k++) { rpl->setRefPicIdentifier(k, ge.m_deltaRefPics[k], 0); } } } //Check if all delta POC of STRP in each RPL has the same sign //Check RPLL0 first const RPLList* rplList0 = sps.getRPLList0(); const RPLList* rplList1 = sps.getRPLList1(); uint32_t numberOfRPL = sps.getNumRPL0(); bool isAllEntriesinRPLHasSameSignFlag = true; bool isFirstEntry = true; bool lastSign = true; //true = positive ; false = negative for (uint32_t ii = 0; isAllEntriesinRPLHasSameSignFlag && ii < numberOfRPL; ii++) { const ReferencePictureList* rpl = rplList0->getReferencePictureList(ii); for (uint32_t jj = 0; isAllEntriesinRPLHasSameSignFlag && jj < rpl->getNumberOfActivePictures(); jj++) { if (!rpl->isRefPicLongterm(jj) && isFirstEntry) { lastSign = (rpl->getRefPicIdentifier(jj) >= 0) ? true : false; isFirstEntry = false; } else if (!rpl->isRefPicLongterm(jj) && (((rpl->getRefPicIdentifier(jj) - rpl->getRefPicIdentifier(jj - 1)) >= 0 && lastSign == false) || ((rpl->getRefPicIdentifier(jj) - rpl->getRefPicIdentifier(jj - 1)) < 0 && lastSign == true))) { isAllEntriesinRPLHasSameSignFlag = false; } } } //Check RPLL1. Skip it if it is already found out that this flag is not true for RPL0 or if RPL1 is the same as RPL0 numberOfRPL = sps.getNumRPL1(); isFirstEntry = true; lastSign = true; for (uint32_t ii = 0; isAllEntriesinRPLHasSameSignFlag && !sps.getRPL1CopyFromRPL0Flag() && ii < numberOfRPL; ii++) { isFirstEntry = true; const ReferencePictureList* rpl = rplList1->getReferencePictureList(ii); for (uint32_t jj = 0; isAllEntriesinRPLHasSameSignFlag && jj < rpl->getNumberOfActivePictures(); jj++) { if (!rpl->isRefPicLongterm(jj) && isFirstEntry) { lastSign = (rpl->getRefPicIdentifier(jj) >= 0) ? true : false; isFirstEntry = false; } else if (!rpl->isRefPicLongterm(jj) && (((rpl->getRefPicIdentifier(jj) - rpl->getRefPicIdentifier(jj - 1)) >= 0 && lastSign == false) || ((rpl->getRefPicIdentifier(jj) - rpl->getRefPicIdentifier(jj - 1)) < 0 && lastSign == true))) { isAllEntriesinRPLHasSameSignFlag = false; } } } sps.setAllActiveRplEntriesHasSameSignFlag(isAllEntriesinRPLHasSameSignFlag); } void EncLib::getActiveRefPicListNumForPOC(const SPS *sps, int POCCurr, int GOPid, uint32_t *activeL0, uint32_t *activeL1) { if (m_uiIntraPeriod < 0) //Only for RA { *activeL0 = *activeL1 = 0; return; } uint32_t rpl0Idx = GOPid; uint32_t rpl1Idx = GOPid; int fullListNum = m_iGOPSize; int partialListNum = getRPLCandidateSize(0) - m_iGOPSize; int extraNum = fullListNum; if (m_uiIntraPeriod < 0) { #if JVET_P0345_LD_GOP_8 if (POCCurr < (2 * m_iGOPSize + 2)) #else if (POCCurr < 10) #endif { rpl0Idx = POCCurr + m_iGOPSize - 1; rpl1Idx = POCCurr + m_iGOPSize - 1; } else { rpl0Idx = (POCCurr%m_iGOPSize == 0) ? m_iGOPSize - 1 : POCCurr%m_iGOPSize - 1; rpl1Idx = (POCCurr%m_iGOPSize == 0) ? m_iGOPSize - 1 : POCCurr%m_iGOPSize - 1; } extraNum = fullListNum + partialListNum; } for (; extraNum<fullListNum + partialListNum; extraNum++) { if (m_uiIntraPeriod > 0 && getDecodingRefreshType() > 0) { int POCIndex = POCCurr%m_uiIntraPeriod; if (POCIndex == 0) POCIndex = m_uiIntraPeriod; if (POCIndex == m_RPLList0[extraNum].m_POC) { rpl0Idx = extraNum; rpl1Idx = extraNum; extraNum++; } } } const ReferencePictureList *rpl0 = sps->getRPLList0()->getReferencePictureList(rpl0Idx); *activeL0 = rpl0->getNumberOfActivePictures(); const ReferencePictureList *rpl1 = sps->getRPLList1()->getReferencePictureList(rpl1Idx); *activeL1 = rpl1->getNumberOfActivePictures(); } void EncLib::selectReferencePictureList(Slice* slice, int POCCurr, int GOPid, int ltPoc) { bool isEncodeLtRef = (POCCurr == ltPoc); if (m_compositeRefEnabled && isEncodeLtRef) { POCCurr++; } slice->setRPL0idx(GOPid); slice->setRPL1idx(GOPid); int fullListNum = m_iGOPSize; int partialListNum = getRPLCandidateSize(0) - m_iGOPSize; int extraNum = fullListNum; if (m_uiIntraPeriod < 0) { #if JVET_P0345_LD_GOP_8 if (POCCurr < (2 * m_iGOPSize + 2)) #else if (POCCurr < 10) #endif { slice->setRPL0idx(POCCurr + m_iGOPSize - 1); slice->setRPL1idx(POCCurr + m_iGOPSize - 1); } else { slice->setRPL0idx((POCCurr%m_iGOPSize == 0) ? m_iGOPSize - 1 : POCCurr%m_iGOPSize - 1); slice->setRPL1idx((POCCurr%m_iGOPSize == 0) ? m_iGOPSize - 1 : POCCurr%m_iGOPSize - 1); } extraNum = fullListNum + partialListNum; } for (; extraNum < fullListNum + partialListNum; extraNum++) { if (m_uiIntraPeriod > 0 && getDecodingRefreshType() > 0) { int POCIndex = POCCurr%m_uiIntraPeriod; if (POCIndex == 0) POCIndex = m_uiIntraPeriod; if (POCIndex == m_RPLList0[extraNum].m_POC) { slice->setRPL0idx(extraNum); slice->setRPL1idx(extraNum); extraNum++; } } } const ReferencePictureList *rpl0 = (slice->getSPS()->getRPLList0()->getReferencePictureList(slice->getRPL0idx())); const ReferencePictureList *rpl1 = (slice->getSPS()->getRPLList1()->getReferencePictureList(slice->getRPL1idx())); slice->setRPL0(rpl0); slice->setRPL1(rpl1); } #if !JVET_P1004_REMOVE_BRICKS void EncLib::xInitPPSforTiles(PPS &pps) { if ( (m_iNumColumnsMinus1==0) && (m_iNumRowsMinus1==0) ) { // one, no bricks pps.setSingleTileInPicFlag(true); pps.setSingleBrickPerSliceFlag(true); pps.setRectSliceFlag(true); } else { pps.setSingleTileInPicFlag(false); pps.setSingleBrickPerSliceFlag( m_sliceMode==SINGLE_BRICK_PER_SLICE ); pps.setRectSliceFlag( m_sliceMode==SINGLE_BRICK_PER_SLICE ); if (m_rectSliceFlag) pps.setRectSliceFlag(m_rectSliceFlag); } pps.setUniformTileSpacingFlag( m_tileUniformSpacingFlag ); pps.setNumTileColumnsMinus1( m_iNumColumnsMinus1 ); pps.setNumTileRowsMinus1( m_iNumRowsMinus1 ); if( !m_tileUniformSpacingFlag ) { pps.setTileColumnWidth( m_tileColumnWidth ); pps.setTileRowHeight( m_tileRowHeight ); } else { pps.setTileColsWidthMinus1(m_uniformTileColsWidthMinus1); pps.setTileRowsHeightMinus1(m_uniformTileRowHeightMinus1); } pps.setLoopFilterAcrossBricksEnabledFlag( m_loopFilterAcrossBricksEnabledFlag ); //pps.setRectSliceFlag( m_rectSliceFlag ); pps.setNumSlicesInPicMinus1( m_numSlicesInPicMinus1 ); pps.setTopLeftBrickIdx(m_topLeftBrickIdx); pps.setBottomRightBrickIdx(m_bottomRightBrickIdx); if (m_numSlicesInPicMinus1 > 0) { std::vector<int> bottomrightdelta(m_numSlicesInPicMinus1 + 1); for (int i = 0; i < m_numSlicesInPicMinus1 + 1; i++) { bottomrightdelta[i] = (i == 0) ? m_bottomRightBrickIdx[i] : m_bottomRightBrickIdx[i] - m_bottomRightBrickIdx[i - 1]; } pps.setBottomRightBrickIdxDelta(bottomrightdelta); } pps.setLoopFilterAcrossBricksEnabledFlag( m_loopFilterAcrossBricksEnabledFlag ); pps.setLoopFilterAcrossSlicesEnabledFlag( m_loopFilterAcrossSlicesEnabledFlag ); pps.setSignalledSliceIdFlag( m_signalledSliceIdFlag ); pps.setSignalledSliceIdLengthMinus1( m_signalledSliceIdLengthMinus1 ); pps.setSignalledSliceIdFlag( m_signalledSliceIdFlag ); pps.setSignalledSliceIdLengthMinus1( m_signalledSliceIdLengthMinus1 ); pps.setSliceId( m_sliceId ); int numTiles= (m_iNumColumnsMinus1 + 1) * (m_iNumRowsMinus1 + 1); pps.setNumTilesInPic(numTiles); std::vector<int> tileHeight(numTiles); if (m_brickSplitMap.empty()) { pps.setBrickSplittingPresentFlag(false); } else { pps.setBrickSplittingPresentFlag(true); std::vector<bool> brickSplitFlag (numTiles, false); std::vector<bool> uniformBrickSpacingFlag (numTiles, false); std::vector<int> brickHeightMinus1 (numTiles, 0); std::vector<int> numBrickRowsMinus2(numTiles, 0); std::vector<std::vector<int>> brickRowHeightMinus1 (numTiles); for (auto &brickSplit: m_brickSplitMap) { int tileIdx = brickSplit.first; CHECK ( tileIdx >= numTiles, "Brick split specified for undefined tile"); brickSplitFlag[tileIdx] = true; uniformBrickSpacingFlag [tileIdx] = brickSplit.second.m_uniformSplit; if (uniformBrickSpacingFlag [tileIdx]) { brickHeightMinus1[tileIdx]=brickSplit.second.m_uniformHeight - 1; } else { numBrickRowsMinus2[tileIdx] = brickSplit.second.m_numSplits - 1; brickRowHeightMinus1[tileIdx].resize(brickSplit.second.m_numSplits); for (int i=0; i<brickSplit.second.m_numSplits; i++) { brickRowHeightMinus1[tileIdx][i]=brickSplit.second.m_brickHeight[i] - 1; } } } pps.setBrickSplitFlag(brickSplitFlag); pps.setUniformBrickSpacingFlag(uniformBrickSpacingFlag); pps.setBrickHeightMinus1(brickHeightMinus1); pps.setNumBrickRowsMinus2(numBrickRowsMinus2); pps.setBrickRowHeightMinus1(brickRowHeightMinus1); // check brick dimensions std::vector<uint32_t> tileRowHeight (m_iNumRowsMinus1+1); int picHeightInCtus = (getSourceHeight() + m_maxCUHeight - 1) / m_maxCUHeight; // calculate all tile row heights if( pps.getUniformTileSpacingFlag() ) { //set width and height for each (uniform) tile for(int row=0; row < m_iNumRowsMinus1 + 1; row++) { tileRowHeight[row] = (row+1)*picHeightInCtus/(m_iNumRowsMinus1+1) - (row*picHeightInCtus)/(m_iNumRowsMinus1 + 1); } } else { tileRowHeight[ m_iNumRowsMinus1 ] = picHeightInCtus; for( int j = 0; j < m_iNumRowsMinus1; j++ ) { tileRowHeight[ j ] = pps.getTileRowHeight( j ); tileRowHeight[ m_iNumRowsMinus1 ] = tileRowHeight[ m_iNumRowsMinus1 ] - pps.getTileRowHeight( j ); } } // check brick splits for each tile for (int tileIdx=0; tileIdx < numTiles; tileIdx++) { const int tileY = tileIdx / (m_iNumColumnsMinus1 + 1); tileHeight[tileIdx] = tileRowHeight[tileY]; if (tileHeight[tileIdx] <= 1) { CHECK(pps.getBrickSplitFlag(tileIdx) != 0, "The value of brick_split_flag[ i ] shall be 0 if tileHeight <= 1"); } if (pps.getBrickSplitFlag(tileIdx)) { if (tileHeight[tileIdx] <= 2) { CHECK(pps.getUniformBrickSpacingFlag(tileIdx) != 1, "The value of uniform_brick_spacing_flag[ i ] shall be 1 if tileHeight <= 2"); } if (pps.getUniformBrickSpacingFlag(tileIdx)) { CHECK((pps.getBrickHeightMinus1(tileIdx) + 1) >= tileHeight[tileIdx], "Brick height larger than or equal to tile height"); } else { int cumulativeHeight=0; for (int i = 0; i <= pps.getNumBrickRowsMinus2(tileIdx); i++) { cumulativeHeight += pps.getBrickRowHeightMinus1(tileIdx, i) + 1; } CHECK(cumulativeHeight >= tileHeight[tileIdx], "Cumulative brick height larger than or equal to tile height"); } } } } pps.setTileHeight(tileHeight); } void EncCfg::xCheckGSParameters() { int iWidthInCU = ( m_iSourceWidth%m_maxCUWidth ) ? m_iSourceWidth/m_maxCUWidth + 1 : m_iSourceWidth/m_maxCUWidth; int iHeightInCU = ( m_iSourceHeight%m_maxCUHeight ) ? m_iSourceHeight/m_maxCUHeight + 1 : m_iSourceHeight/m_maxCUHeight; uint32_t uiCummulativeColumnWidth = 0; uint32_t uiCummulativeRowHeight = 0; if (m_tileUniformSpacingFlag && m_uniformTileColsWidthMinus1 == -1) { EXIT("Uniform tiles specified with unspecified or invalid UniformTileColsWidthMinus1 value"); } if (m_tileUniformSpacingFlag && m_uniformTileRowHeightMinus1 == -1) { EXIT("Uniform tiles specified with unspecified or invalid UniformTileRowHeightMinus1 value"); } if (m_tileUniformSpacingFlag && m_uniformTileColsWidthMinus1 >= iWidthInCU) { EXIT("UniformTileColsWidthMinus1 too large"); } if (m_tileUniformSpacingFlag && m_uniformTileRowHeightMinus1 >= iHeightInCU) { EXIT("UniformTileRowHeightMinus1 too large"); } //check the column relative parameters if( m_iNumColumnsMinus1 >= (1<<(LOG2_MAX_NUM_COLUMNS_MINUS1+1)) ) { EXIT( "The number of columns is larger than the maximum allowed number of columns." ); } if( m_iNumColumnsMinus1 >= iWidthInCU ) { EXIT( "The current picture can not have so many columns." ); } if( m_iNumColumnsMinus1 && !m_tileUniformSpacingFlag ) { for(int i=0; i<m_iNumColumnsMinus1; i++) { uiCummulativeColumnWidth += m_tileColumnWidth[i]; } if( uiCummulativeColumnWidth >= iWidthInCU ) { EXIT( "The width of the column is too large." ); } } //check the row relative parameters if( m_iNumRowsMinus1 >= (1<<(LOG2_MAX_NUM_ROWS_MINUS1+1)) ) { EXIT( "The number of rows is larger than the maximum allowed number of rows." ); } if( m_iNumRowsMinus1 >= iHeightInCU ) { EXIT( "The current picture can not have so many rows." ); } if( m_iNumRowsMinus1 && !m_tileUniformSpacingFlag ) { for(int i=0; i<m_iNumRowsMinus1; i++) { uiCummulativeRowHeight += m_tileRowHeight[i]; } if( uiCummulativeRowHeight >= iHeightInCU ) { EXIT( "The height of the row is too large." ); } } } #endif void EncLib::setParamSetChanged(int spsId, int ppsId) { m_ppsMap.setChangedFlag(ppsId); m_spsMap.setChangedFlag(spsId); } bool EncLib::APSNeedsWriting(int apsId) { bool isChanged = m_apsMap.getChangedFlag(apsId); m_apsMap.clearChangedFlag(apsId); return isChanged; } bool EncLib::PPSNeedsWriting(int ppsId) { bool bChanged=m_ppsMap.getChangedFlag(ppsId); m_ppsMap.clearChangedFlag(ppsId); return bChanged; } bool EncLib::SPSNeedsWriting(int spsId) { bool bChanged=m_spsMap.getChangedFlag(spsId); m_spsMap.clearChangedFlag(spsId); return bChanged; } void EncLib::checkPltStats( Picture* pic ) { int totalArea = 0; int pltArea = 0; for (auto apu : pic->cs->pus) { for (int i = 0; i < MAX_NUM_TBLOCKS; ++i) { int puArea = apu->blocks[i].width * apu->blocks[i].height; if (apu->blocks[i].width > 0 && apu->blocks[i].height > 0) { totalArea += puArea; if (CU::isPLT(*apu->cu) || CU::isIBC(*apu->cu)) { pltArea += puArea; } break; } } } if (pltArea * PLT_FAST_RATIO < totalArea) { m_doPlt = false; } else { m_doPlt = true; } } #if X0038_LAMBDA_FROM_QP_CAPABILITY int EncCfg::getQPForPicture(const uint32_t gopIndex, const Slice *pSlice) const { const int lumaQpBDOffset = pSlice->getSPS()->getQpBDOffset(CHANNEL_TYPE_LUMA); int qp; if (getCostMode()==COST_LOSSLESS_CODING) { #if JVET_AHG14_LOSSLESS qp = LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP - ( ( pSlice->getSPS()->getBitDepth( CHANNEL_TYPE_LUMA ) - 8 ) * 6 ); #else qp=LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP; #endif } else { const SliceType sliceType=pSlice->getSliceType(); qp = getBaseQP(); // switch at specific qp and keep this qp offset static int appliedSwitchDQQ = 0; /* TODO: MT */ if( pSlice->getPOC() == getSwitchPOC() ) { appliedSwitchDQQ = getSwitchDQP(); } qp += appliedSwitchDQQ; #if QP_SWITCHING_FOR_PARALLEL const int* pdQPs = getdQPs(); if ( pdQPs ) { qp += pdQPs[pSlice->getPOC() / (m_compositeRefEnabled ? 2 : 1)]; } #endif if(sliceType==I_SLICE) { qp += getIntraQPOffset(); } else { #if SHARP_LUMA_DELTA_QP // Only adjust QP when not lossless if (!(( getMaxDeltaQP() == 0 ) && (!getLumaLevelToDeltaQPMapping().isEnabled()) && (qp == -lumaQpBDOffset ) && (pSlice->getPPS()->getTransquantBypassEnabledFlag()))) #else if (!(( getMaxDeltaQP() == 0 ) && (qp == -lumaQpBDOffset ) && (pSlice->getPPS()->getTransquantBypassEnabledFlag()))) #endif { const GOPEntry &gopEntry=getGOPEntry(gopIndex); // adjust QP according to the QP offset for the GOP entry. qp +=gopEntry.m_QPOffset; // adjust QP according to QPOffsetModel for the GOP entry. double dqpOffset=qp*gopEntry.m_QPOffsetModelScale+gopEntry.m_QPOffsetModelOffset+0.5; int qpOffset = (int)floor(Clip3<double>(0.0, 3.0, dqpOffset)); qp += qpOffset ; } } #if !QP_SWITCHING_FOR_PARALLEL // modify QP if a fractional QP was originally specified, cause dQPs to be 0 or 1. const int* pdQPs = getdQPs(); if ( pdQPs ) { qp += pdQPs[ pSlice->getPOC() ]; } #endif } qp = Clip3( -lumaQpBDOffset, MAX_QP, qp ); return qp; } #endif //! \}