Newer
Older

Karsten Suehring
committed
/* 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.
*

Karsten Suehring
committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
* 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
#include "CommonLib/ProfileLevelTier.h"

Karsten Suehring
committed
//! \ingroup EncoderLib
//! \{
// ====================================================================================================================
// Constructor / destructor / create / destroy
// ====================================================================================================================
EncLib::EncLib( EncLibCommon* encLibCommon )
: m_cListPic( encLibCommon->getPictureBuffer() )
#if JVET_AK0065_TALF
, m_cEncALF( encLibCommon->getApsIdStart(), encLibCommon->getApsIdStart2() )
#else
, m_cEncALF( encLibCommon->getApsIdStart() )
, m_spsMap( encLibCommon->getSpsMap() )
, m_ppsMap( encLibCommon->getPpsMap() )
, m_apsMap( encLibCommon->getApsMap() )
, m_AUWriterIf( nullptr )

Karsten Suehring
committed
#if JVET_J0090_MEMORY_BANDWITH_MEASURE
, m_cacheModel()
#endif
, m_scalinglistAPS( nullptr )
, m_doPlt( true )
, m_vps( encLibCommon->getVPS() )

Karsten Suehring
committed
{
m_iPOCLast = -1;
m_iNumPicRcvd = 0;
m_uiNumAllPicCoded = 0;
m_iMaxRefPicNum = 0;
#if ENABLE_SIMD_OPT_BUFFER && defined(TARGET_SIMD_X86)

Karsten Suehring
committed
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_AK0065_TALF
memset(m_apss2, 0, sizeof(m_apss2));
#endif

Karsten Suehring
committed
}
EncLib::~EncLib()
{
}

Karsten Suehring
committed
{
m_iPOCLast = m_compositeRefEnabled ? -2 : -1;

Karsten Suehring
committed
// create processing unit classes
m_cGOPEncoder. create( );
#if JVET_AJ0237_INTERNAL_12BIT
m_cGOPEncoder.m_cBilateralFilter.setInternalBitDepth(m_bitDepth[COMPONENT_Y]);
#endif

Karsten Suehring
committed
#if ENABLE_SPLIT_PARALLELISM
m_numCuEncStacks = m_numSplitThreads == 1 ? 1 : NUM_RESERVERD_SPLIT_JOBS;
#else
m_numCuEncStacks = 1;
#endif
m_cCuEncoder = new EncCu [m_numCuEncStacks];
m_cInterSearch = new InterSearch [m_numCuEncStacks];
m_cIntraSearch = new IntraSearch [m_numCuEncStacks];
#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER
m_bilateralFilter = new BilateralFilter [m_numCuEncStacks];
#endif

Karsten Suehring
committed
m_cTrQuant = new TrQuant [m_numCuEncStacks];
m_CABACEncoder = new CABACEncoder [m_numCuEncStacks];
m_cRdCost = new RdCost [m_numCuEncStacks];

Karsten Suehring
committed
for( int jId = 0; jId < m_numCuEncStacks; jId++ )
{
m_cCuEncoder[jId]. create( this );
#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER

Karsten Suehring
committed
}
#else
m_cCuEncoder. create( this );
#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER
#if JVET_AJ0237_INTERNAL_12BIT
m_bilateralFilter.setInternalBitDepth(m_bitDepth[COMPONENT_Y]);
#endif

Karsten Suehring
committed
#endif
#if JVET_J0090_MEMORY_BANDWITH_MEASURE
m_cInterSearch.cacheAssign( &m_cacheModel );
#endif
m_cLoopFilter.create(floorLog2(m_maxCUWidth) - MIN_CU_LOG2);

Karsten Suehring
committed
m_cLoopFilter.initEncPicYuvBuffer(m_chromaFormatIDC, Size(getSourceWidth(), getSourceHeight()), getMaxCUWidth());
m_cReshaper = new EncReshape[m_numCuEncStacks];
#endif
if (m_lmcsEnabled)
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]);

Karsten Suehring
committed
if ( m_RCEnableRateControl )
{
#if JVET_AA0146_WRAP_AROUND_FIX
m_cRateCtrl.init(m_framesToBeEncoded, m_RCTargetBitrate, (int)((double)m_iFrameRate / m_temporalSubsampleRatio + 0.5), m_iGOPSize, m_sourceWidth, m_sourceHeight,
m_maxCUWidth, m_maxCUHeight, getBitDepth(CHANNEL_TYPE_LUMA), m_RCKeepHierarchicalBit, m_RCUseLCUSeparateModel, m_GOPList);
#else
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);

Karsten Suehring
committed
}
#if JVET_AA0146_WRAP_AROUND_FIX
m_cEncALF.create(this, m_sourceWidth, m_sourceHeight, m_chromaFormatIDC, m_maxCUWidth, m_maxCUHeight, floorLog2(m_maxCUWidth) - m_log2MinCUSize, m_bitDepth, m_inputBitDepth);
#else
m_cEncALF.create(this, m_iSourceWidth, m_iSourceHeight, m_chromaFormatIDC, m_maxCUWidth, m_maxCUHeight, floorLog2(m_maxCUWidth) - m_log2MinCUSize, m_bitDepth, m_inputBitDepth);
#if JVET_X0071_CHROMA_BILATERAL_FILTER
if (m_bUseSAO || m_BIF || m_CCSAO || m_chromaBIF)
#endif
#else
#if JVET_X0071_CHROMA_BILATERAL_FILTER
if (m_bUseSAO || m_BIF || m_chromaBIF)
#if JVET_X0071_CHROMA_BILATERAL_FILTER
if (m_bUseSAO || m_CCSAO || m_chromaBIF)
#endif
#else
#if JVET_X0071_CHROMA_BILATERAL_FILTER
if (m_bUseSAO || m_chromaBIF)
#if JVET_AA0146_WRAP_AROUND_FIX
const uint32_t widthInCtus = (m_sourceWidth + m_maxCUWidth - 1) / m_maxCUWidth;
const uint32_t heightInCtus = (m_sourceHeight + m_maxCUHeight - 1) / m_maxCUHeight;
const uint32_t numCtuInFrame = widthInCtus * heightInCtus;
m_cEncSAO.create(m_sourceWidth, m_sourceHeight, m_chromaFormatIDC, m_maxCUWidth, m_maxCUHeight, floorLog2(m_maxCUWidth) - m_log2MinCUSize, (uint32_t)std::max(0, m_bitDepth[CHANNEL_TYPE_LUMA] - MAX_SAO_TRUNCATED_BITDEPTH), (uint32_t)std::max(0, m_bitDepth[CHANNEL_TYPE_CHROMA] - MAX_SAO_TRUNCATED_BITDEPTH));
#else
const uint32_t widthInCtus = (m_iSourceWidth + m_maxCUWidth - 1) / m_maxCUWidth;
const uint32_t heightInCtus = (m_iSourceHeight + m_maxCUHeight - 1) / m_maxCUHeight;
const uint32_t numCtuInFrame = widthInCtus * heightInCtus;
m_cEncSAO.create(m_iSourceWidth, m_iSourceHeight, m_chromaFormatIDC, m_maxCUWidth, m_maxCUHeight, floorLog2(m_maxCUWidth) - m_log2MinCUSize, (uint32_t)std::max(0, m_bitDepth[CHANNEL_TYPE_LUMA] - MAX_SAO_TRUNCATED_BITDEPTH), (uint32_t)std::max(0, m_bitDepth[CHANNEL_TYPE_CHROMA] - MAX_SAO_TRUNCATED_BITDEPTH));
#if JVET_AJ0237_INTERNAL_12BIT
m_cEncSAO.m_bilateralFilter.setInternalBitDepth(m_bitDepth[COMPONENT_Y]);
#endif

Karsten Suehring
committed
}
void EncLib::destroy ()
{
// destroy processing unit classes
m_cGOPEncoder. destroy();
m_cSliceEncoder. destroy();

Karsten Suehring
committed
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. destroy();
m_cLoopFilter. destroy();
m_cRateCtrl. destroy();
for (int jId = 0; jId < m_numCuEncStacks; jId++)
{
m_cReshaper[jId]. destroy();
}
#else

Karsten Suehring
committed
for( int jId = 0; jId < m_numCuEncStacks; jId++ )
{
m_cInterSearch[jId]. destroy();
m_cIntraSearch[jId]. destroy();
#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER

Karsten Suehring
committed
}
#else
m_cInterSearch. destroy();
m_cIntraSearch. destroy();
#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER

Karsten Suehring
committed
#endif

Karsten Suehring
committed
delete[] m_cCuEncoder;
delete[] m_cInterSearch;
delete[] m_cIntraSearch;
#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER

Karsten Suehring
committed
delete[] m_cTrQuant;
delete[] m_CABACEncoder;
delete[] m_cRdCost;

Karsten Suehring
committed
#endif
return;
}
void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf )
{
m_AUWriterIf = auWriterIf;
Vadim Seregin
committed
SPS &sps0 = *(m_spsMap.allocatePS( m_vps->getGeneralLayerIdx( m_layerId ) )); // NOTE: implementations that use more than 1 SPS need to be aware of activation issues.
PPS &pps0 = *( m_ppsMap.allocatePS( m_vps->getGeneralLayerIdx( m_layerId ) ) );
APS &aps0 = *( m_apsMap.allocatePS( SCALING_LIST_APS ) );
aps0.setAPSId( 0 );
aps0.setAPSType( SCALING_LIST_APS );

Karsten Suehring
committed
if (getAvoidIntraInDepLayer() && getNumRefLayers(m_vps->getGeneralLayerIdx( getLayerId())) > 0)
{
setIDRRefParamListPresent(true);
}

Karsten Suehring
committed
// initialize SPS
xInitSPS( sps0 );
xInitVPS( sps0 );

Karsten Suehring
committed

Karsten Suehring
committed
#if ENABLE_SPLIT_PARALLELISM
if( omp_get_dynamic() )
{
omp_set_dynamic( false );
}
omp_set_nested( true );
#endif
if (getUseCompositeRef() || getDependentRAPIndicationSEIEnabled())
{
sps0.setLongTermRefsPresent(true);
}

Karsten Suehring
committed
#if U0132_TARGET_BITS_SATURATION
if (m_RCCpbSaturationEnabled)
{
m_cRateCtrl.initHrdParam(sps0.getGeneralHrdParameters(), sps0.getOlsHrdParameters(), m_iFrameRate, m_RCInitialCpbFullness);

Karsten Suehring
committed
}
#endif

Karsten Suehring
committed
for( int jId = 0; jId < m_numCuEncStacks; jId++ )
{
m_cRdCost[jId].setCostMode ( m_costMode );
}
#else
m_cRdCost.setCostMode ( m_costMode );
#endif
// initialize PPS
#if JVET_AA0146_WRAP_AROUND_FIX
pps0.setPicWidthInLumaSamples( m_sourceWidth );
pps0.setPicHeightInLumaSamples( m_sourceHeight );
#else
pps0.setPicWidthInLumaSamples( m_iSourceWidth );
pps0.setPicHeightInLumaSamples( m_iSourceHeight );
#if JVET_R0068_ASPECT6_ENC_RESTRICTION
if (pps0.getPicWidthInLumaSamples() == sps0.getMaxPicWidthInLumaSamples() && pps0.getPicHeightInLumaSamples() == sps0.getMaxPicHeightInLumaSamples())
{
pps0.setConformanceWindow( sps0.getConformanceWindow() );
pps0.setConformanceWindowFlag( false );
}
else
{
pps0.setConformanceWindow( m_conformanceWindow );
pps0.setConformanceWindowFlag( m_conformanceWindow.getWindowEnabledFlag() );
}
#else
pps0.setConformanceWindow( m_conformanceWindow );

Karsten Suehring
committed
xInitPPS(pps0, sps0);
#if JVET_AA0093_DIVERSITY_CRITERION_FOR_ARMC
if (sps0.getUseAML())
{
sps0.setNumLambda(m_numQPOffset);
int maxBits = 0;
for (int idx = 0; idx < m_numQPOffset; idx++)
{
sps0.setQPOffsets(idx, m_qpOffsetList[idx]);
const uint32_t lambda = (uint32_t)LAMBDA_DEC_SIDE[min(max(26 + pps0.getPicInitQPMinus26() + m_qpOffsetList[idx] - 4 * ((int)m_isRA), 0), MAX_QP)];
sps0.setLambdaVal(idx, lambda);
for (int shift = 0; shift < 16; shift++)
if (lambda >> shift == 0)
{
if (shift > maxBits)
{
maxBits = shift;
}
break;
}
}
sps0.setMaxbitsLambdaVal(maxBits);
}
#endif

Karsten Suehring
committed
if (m_resChangeInClvsEnabled)
PPS &pps = *( m_ppsMap.allocatePS( ENC_PPS_ID_RPR ) );
Window& inputScalingWindow = pps0.getScalingWindow();
int scaledWidth = int( ( pps0.getPicWidthInLumaSamples() - SPS::getWinUnitX( sps0.getChromaFormatIdc() ) * ( inputScalingWindow.getWindowLeftOffset() + inputScalingWindow.getWindowRightOffset() ) ) / m_scalingRatioHor );
int minSizeUnit = std::max(8, 1 << sps0.getLog2MinCodingBlockSize());
int temp = scaledWidth / minSizeUnit;
int width = ( scaledWidth - ( temp * minSizeUnit) > 0 ? temp + 1 : temp ) * minSizeUnit;
int scaledHeight = int( ( pps0.getPicHeightInLumaSamples() - SPS::getWinUnitY( sps0.getChromaFormatIdc() ) * ( inputScalingWindow.getWindowTopOffset() + inputScalingWindow.getWindowBottomOffset() ) ) / m_scalingRatioVer );
temp = scaledHeight / minSizeUnit;
int height = ( scaledHeight - ( temp * minSizeUnit) > 0 ? temp + 1 : temp ) * minSizeUnit;
pps.setPicWidthInLumaSamples( width );
pps.setPicHeightInLumaSamples( height );
#if JVET_AC0096
pps.setSliceChromaQpFlag(true);
#endif
Window conformanceWindow;
conformanceWindow.setWindow( 0, ( width - scaledWidth ) / SPS::getWinUnitX( sps0.getChromaFormatIdc() ), 0, ( height - scaledHeight ) / SPS::getWinUnitY( sps0.getChromaFormatIdc() ) );
#if JVET_R0068_ASPECT6_ENC_RESTRICTION
if (pps.getPicWidthInLumaSamples() == sps0.getMaxPicWidthInLumaSamples() && pps.getPicHeightInLumaSamples() == sps0.getMaxPicHeightInLumaSamples())
{
pps.setConformanceWindow( sps0.getConformanceWindow() );
pps.setConformanceWindowFlag( false );
}
else
{
pps.setConformanceWindow( conformanceWindow );
pps.setConformanceWindowFlag( pps.getConformanceWindow().getWindowEnabledFlag() );
}
#else
pps.setConformanceWindow( conformanceWindow );
Window scalingWindow;
scalingWindow.setWindow( 0, ( width - scaledWidth ) / SPS::getWinUnitX( sps0.getChromaFormatIdc() ), 0, ( height - scaledHeight ) / SPS::getWinUnitY( sps0.getChromaFormatIdc() ) );
pps.setScalingWindow( scalingWindow );
Peter Chuang
committed
//register the width/height of the current pic into reference SPS
if (!sps0.getPPSValidFlag(pps.getPPSId()))
{
sps0.setPPSValidFlag(pps.getPPSId(), true);
sps0.setScalingWindowSizeInPPS(pps.getPPSId(), scaledWidth, scaledHeight);
}
int curSeqMaxPicWidthY = sps0.getMaxPicWidthInLumaSamples(); // pic_width_max_in_luma_samples
int curSeqMaxPicHeightY = sps0.getMaxPicHeightInLumaSamples(); // pic_height_max_in_luma_samples
int curPicWidthY = width; // pic_width_in_luma_samples
int curPicHeightY = height; // pic_height_in_luma_samples
Peter Chuang
committed
int max8MinCbSizeY = std::max((int)8, (1 << sps0.getLog2MinCodingBlockSize())); // Max(8, MinCbSizeY)
Peter Chuang
committed
//Warning message of potential scaling window size violation
Peter Chuang
committed
for (int i = 0; i < 64; i++)
{
if (sps0.getPPSValidFlag(i))
{
if ((scaledWidth * curSeqMaxPicWidthY) < sps0.getScalingWindowSizeInPPS(i).width * (curPicWidthY - max8MinCbSizeY))
printf("Potential violation: (curScaledWIdth * curSeqMaxPicWidthY) should be greater than or equal to refScaledWidth * (curPicWidthY - max(8, MinCbSizeY)\n");
if ((scaledHeight * curSeqMaxPicHeightY) < sps0.getScalingWindowSizeInPPS(i).height * (curPicHeightY - max8MinCbSizeY))
printf("Potential violation: (curScaledHeight * curSeqMaxPicHeightY) should be greater than or equal to refScaledHeight * (curPicHeightY - max(8, MinCbSizeY)\n");
}
}
// disable picture partitioning for scaled RPR pictures (slice/tile config only provided for the original resolution)
m_noPicPartitionFlag = true;
xInitPPS( pps, sps0 ); // will allocate memory for and initialize pps.pcv inside
if( pps.getWrapAroundEnabledFlag() )
{
int minCbSizeY = (1 << sps0.getLog2MinCodingBlockSize());
pps.setPicWidthMinusWrapAroundOffset ((pps.getPicWidthInLumaSamples()/minCbSizeY) - (m_wrapAroundOffset * pps.getPicWidthInLumaSamples() / pps0.getPicWidthInLumaSamples() / minCbSizeY) );
pps.setWrapAroundOffset (minCbSizeY * (pps.getPicWidthInLumaSamples() / minCbSizeY - pps.getPicWidthMinusWrapAroundOffset()));
pps.setPicWidthMinusWrapAroundOffset (0);
#if JVET_AG0116
if (m_resChangeInClvsEnabled && (m_rprFunctionalityTestingEnabledFlag || m_gopBasedRPREnabledFlag))
#else
if (m_resChangeInClvsEnabled && m_rprFunctionalityTestingEnabledFlag)
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
{
// allocate PPS that can be used
double scalingRatioHor = m_scalingRatioHor2;
double scalingRatioVer = m_scalingRatioVer2;
PPS& pps = *(m_ppsMap.allocatePS(ENC_PPS_ID_RPR2));
Window& inputScalingWindow = pps0.getScalingWindow();
int scaledWidth = int((pps0.getPicWidthInLumaSamples() - SPS::getWinUnitX(sps0.getChromaFormatIdc()) * (inputScalingWindow.getWindowLeftOffset() + inputScalingWindow.getWindowRightOffset())) / scalingRatioHor);
int minSizeUnit = std::max(8, 1 << sps0.getLog2MinCodingBlockSize());
int temp = scaledWidth / minSizeUnit;
int width = (scaledWidth - (temp * minSizeUnit) > 0 ? temp + 1 : temp) * minSizeUnit;
int scaledHeight = int((pps0.getPicHeightInLumaSamples() - SPS::getWinUnitY(sps0.getChromaFormatIdc()) * (inputScalingWindow.getWindowTopOffset() + inputScalingWindow.getWindowBottomOffset())) / scalingRatioVer);
temp = scaledHeight / minSizeUnit;
int height = (scaledHeight - (temp * minSizeUnit) > 0 ? temp + 1 : temp) * minSizeUnit;
pps.setPicWidthInLumaSamples(width);
pps.setPicHeightInLumaSamples(height);
pps.setSliceChromaQpFlag(true);
Window conformanceWindow;
conformanceWindow.setWindow(0, (width - scaledWidth) / SPS::getWinUnitX(sps0.getChromaFormatIdc()), 0, (height - scaledHeight) / SPS::getWinUnitY(sps0.getChromaFormatIdc()));
#if JVET_R0068_ASPECT6_ENC_RESTRICTION
if (pps.getPicWidthInLumaSamples() == sps0.getMaxPicWidthInLumaSamples() && pps.getPicHeightInLumaSamples() == sps0.getMaxPicHeightInLumaSamples())
{
pps.setConformanceWindow(sps0.getConformanceWindow());
pps.setConformanceWindowFlag(false);
}
else
{
pps.setConformanceWindow(conformanceWindow);
pps.setConformanceWindowFlag(pps.getConformanceWindow().getWindowEnabledFlag());
}
#else
pps.setConformanceWindow(conformanceWindow);
#endif
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
Window scalingWindow;
scalingWindow.setWindow(0, (width - scaledWidth) / SPS::getWinUnitX(sps0.getChromaFormatIdc()), 0, (height - scaledHeight) / SPS::getWinUnitY(sps0.getChromaFormatIdc()));
pps.setScalingWindow(scalingWindow);
//register the width/height of the current pic into reference SPS
if (!sps0.getPPSValidFlag(pps.getPPSId()))
{
sps0.setPPSValidFlag(pps.getPPSId(), true);
sps0.setScalingWindowSizeInPPS(pps.getPPSId(), scaledWidth, scaledHeight);
}
int curSeqMaxPicWidthY = sps0.getMaxPicWidthInLumaSamples(); // pic_width_max_in_luma_samples
int curSeqMaxPicHeightY = sps0.getMaxPicHeightInLumaSamples(); // pic_height_max_in_luma_samples
int curPicWidthY = width; // pic_width_in_luma_samples
int curPicHeightY = height; // pic_height_in_luma_samples
int max8MinCbSizeY = std::max((int)8, (1 << sps0.getLog2MinCodingBlockSize())); // Max(8, MinCbSizeY)
//Warning message of potential scaling window size violation
for (int i = 0; i < 64; i++)
{
if (sps0.getPPSValidFlag(i))
{
if ((scaledWidth * curSeqMaxPicWidthY) < sps0.getScalingWindowSizeInPPS(i).width * (curPicWidthY - max8MinCbSizeY))
{
printf("Potential violation: (curScaledWIdth * curSeqMaxPicWidthY) should be greater than or equal to refScaledWidth * (curPicWidthY - max(8, MinCbSizeY)\n");
}
if ((scaledHeight * curSeqMaxPicHeightY) < sps0.getScalingWindowSizeInPPS(i).height * (curPicHeightY - max8MinCbSizeY))
{
printf("Potential violation: (curScaledHeight * curSeqMaxPicHeightY) should be greater than or equal to refScaledHeight * (curPicHeightY - max(8, MinCbSizeY)\n");
}
}
}
// disable picture partitioning for scaled RPR pictures (slice/tile config only provided for the original resolution)
m_noPicPartitionFlag = true;
xInitPPS(pps, sps0); // will allocate memory for and initialize pps.pcv inside
if (pps.getWrapAroundEnabledFlag())
{
int minCbSizeY = (1 << sps0.getLog2MinCodingBlockSize());
pps.setPicWidthMinusWrapAroundOffset((pps.getPicWidthInLumaSamples() / minCbSizeY) - (m_wrapAroundOffset * pps.getPicWidthInLumaSamples() / pps0.getPicWidthInLumaSamples() / minCbSizeY));
pps.setWrapAroundOffset(minCbSizeY * (pps.getPicWidthInLumaSamples() / minCbSizeY - pps.getPicWidthMinusWrapAroundOffset()));
}
else
{
pps.setPicWidthMinusWrapAroundOffset(0);
pps.setWrapAroundOffset(0);
}
}
#if JVET_AG0116
if (m_resChangeInClvsEnabled && (m_rprFunctionalityTestingEnabledFlag || m_gopBasedRPREnabledFlag))
#else
if (m_resChangeInClvsEnabled && m_rprFunctionalityTestingEnabledFlag)
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
{
// allocate PPS that can be used
double scalingRatioHor = m_scalingRatioHor3;
double scalingRatioVer = m_scalingRatioVer3;
PPS& pps = *(m_ppsMap.allocatePS(ENC_PPS_ID_RPR3));
Window& inputScalingWindow = pps0.getScalingWindow();
int scaledWidth = int((pps0.getPicWidthInLumaSamples() - SPS::getWinUnitX(sps0.getChromaFormatIdc()) * (inputScalingWindow.getWindowLeftOffset() + inputScalingWindow.getWindowRightOffset())) / scalingRatioHor);
int minSizeUnit = std::max(8, 1 << sps0.getLog2MinCodingBlockSize());
int temp = scaledWidth / minSizeUnit;
int width = (scaledWidth - (temp * minSizeUnit) > 0 ? temp + 1 : temp) * minSizeUnit;
int scaledHeight = int((pps0.getPicHeightInLumaSamples() - SPS::getWinUnitY(sps0.getChromaFormatIdc()) * (inputScalingWindow.getWindowTopOffset() + inputScalingWindow.getWindowBottomOffset())) / scalingRatioVer);
temp = scaledHeight / minSizeUnit;
int height = (scaledHeight - (temp * minSizeUnit) > 0 ? temp + 1 : temp) * minSizeUnit;
pps.setPicWidthInLumaSamples(width);
pps.setPicHeightInLumaSamples(height);
pps.setSliceChromaQpFlag(true);
Window conformanceWindow;
conformanceWindow.setWindow(0, (width - scaledWidth) / SPS::getWinUnitX(sps0.getChromaFormatIdc()), 0, (height - scaledHeight) / SPS::getWinUnitY(sps0.getChromaFormatIdc()));
#if JVET_R0068_ASPECT6_ENC_RESTRICTION
if (pps.getPicWidthInLumaSamples() == sps0.getMaxPicWidthInLumaSamples() && pps.getPicHeightInLumaSamples() == sps0.getMaxPicHeightInLumaSamples())
{
pps.setConformanceWindow(sps0.getConformanceWindow());
pps.setConformanceWindowFlag(false);
}
else
{
pps.setConformanceWindow(conformanceWindow);
pps.setConformanceWindowFlag(pps.getConformanceWindow().getWindowEnabledFlag());
}
#else
pps.setConformanceWindow(conformanceWindow);
#endif
Window scalingWindow;
scalingWindow.setWindow(0, (width - scaledWidth) / SPS::getWinUnitX(sps0.getChromaFormatIdc()), 0, (height - scaledHeight) / SPS::getWinUnitY(sps0.getChromaFormatIdc()));
pps.setScalingWindow(scalingWindow);
//register the width/height of the current pic into reference SPS
if (!sps0.getPPSValidFlag(pps.getPPSId()))
{
sps0.setPPSValidFlag(pps.getPPSId(), true);
sps0.setScalingWindowSizeInPPS(pps.getPPSId(), scaledWidth, scaledHeight);
}
int curSeqMaxPicWidthY = sps0.getMaxPicWidthInLumaSamples(); // pic_width_max_in_luma_samples
int curSeqMaxPicHeightY = sps0.getMaxPicHeightInLumaSamples(); // pic_height_max_in_luma_samples
int curPicWidthY = width; // pic_width_in_luma_samples
int curPicHeightY = height; // pic_height_in_luma_samples
int max8MinCbSizeY = std::max((int)8, (1 << sps0.getLog2MinCodingBlockSize())); // Max(8, MinCbSizeY)
//Warning message of potential scaling window size violation
for (int i = 0; i < 64; i++)
{
if (sps0.getPPSValidFlag(i))
{
if ((scaledWidth * curSeqMaxPicWidthY) < sps0.getScalingWindowSizeInPPS(i).width * (curPicWidthY - max8MinCbSizeY))
{
printf("Potential violation: (curScaledWIdth * curSeqMaxPicWidthY) should be greater than or equal to refScaledWidth * (curPicWidthY - max(8, MinCbSizeY)\n");
}
if ((scaledHeight * curSeqMaxPicHeightY) < sps0.getScalingWindowSizeInPPS(i).height * (curPicHeightY - max8MinCbSizeY))
{
printf("Potential violation: (curScaledHeight * curSeqMaxPicHeightY) should be greater than or equal to refScaledHeight * (curPicHeightY - max(8, MinCbSizeY)\n");
}
}
}
// disable picture partitioning for scaled RPR pictures (slice/tile config only provided for the original resolution)
m_noPicPartitionFlag = true;
xInitPPS(pps, sps0); // will allocate memory for and initialize pps.pcv inside
if (pps.getWrapAroundEnabledFlag())
{
int minCbSizeY = (1 << sps0.getLog2MinCodingBlockSize());
pps.setPicWidthMinusWrapAroundOffset((pps.getPicWidthInLumaSamples() / minCbSizeY) - (m_wrapAroundOffset * pps.getPicWidthInLumaSamples() / pps0.getPicWidthInLumaSamples() / minCbSizeY));
pps.setWrapAroundOffset(minCbSizeY * (pps.getPicWidthInLumaSamples() / minCbSizeY - pps.getPicWidthMinusWrapAroundOffset()));
}
else
{
pps.setPicWidthMinusWrapAroundOffset(0);
pps.setWrapAroundOffset(0);
}
}
#endif

Karsten Suehring
committed
#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);
}

Karsten Suehring
committed
// initialize processing unit classes
m_cGOPEncoder. init( this );
m_cSliceEncoder.init( this, sps0 );

Karsten Suehring
committed
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 );

Karsten Suehring
committed
}
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,

Karsten Suehring
committed
m_useRDOQ,
m_useRDOQTS,
#if T0196_SELECTIVE_RDOQ
m_useSelectiveRDOQ,
#endif

Karsten Suehring
committed
);
// initialize encoder search class
CABACWriter* cabacEstimator = m_CABACEncoder[jId].getCABACEstimator( &sps0 );
m_cIntraSearch[jId].init( this,
#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER

Karsten Suehring
committed
&m_cTrQuant[jId],
&m_cRdCost[jId],
cabacEstimator,
getCtxCache( jId ), m_maxCUWidth, m_maxCUHeight, floorLog2(m_maxCUWidth) - m_log2MinCUSize
, sps0.getBitDepth(CHANNEL_TYPE_LUMA)

Karsten Suehring
committed
m_cInterSearch[jId].init( this,
#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER

Karsten Suehring
committed
&m_cTrQuant[jId],
m_iSearchRange,
m_bipredSearchRange,
m_motionEstimationSearchMethod,
m_maxCUWidth, m_maxCUHeight, floorLog2(m_maxCUWidth) - m_log2MinCUSize, &m_cRdCost[jId], cabacEstimator, getCtxCache( jId )

Karsten Suehring
committed
// 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

Karsten Suehring
committed
// initialize transform & quantization class
m_cTrQuant.init( nullptr,

Karsten Suehring
committed
m_useRDOQ,
m_useRDOQTS,
#if T0196_SELECTIVE_RDOQ
m_useSelectiveRDOQ,
#endif

Karsten Suehring
committed
);
// initialize encoder search class
CABACWriter* cabacEstimator = m_CABACEncoder.getCABACEstimator(&sps0);
m_cIntraSearch.init( this,
#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER

Karsten Suehring
committed
&m_cTrQuant,
&m_cRdCost,
cabacEstimator,
getCtxCache(), m_maxCUWidth, m_maxCUHeight, floorLog2(m_maxCUWidth) - m_log2MinCUSize
, sps0.getBitDepth(CHANNEL_TYPE_LUMA)

Karsten Suehring
committed
m_cInterSearch.init( this,
#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER

Karsten Suehring
committed
&m_cTrQuant,
m_iSearchRange,
m_bipredSearchRange,
m_motionEstimationSearchMethod,
m_maxCUWidth, m_maxCUHeight, floorLog2(m_maxCUWidth) - m_log2MinCUSize, &m_cRdCost, cabacEstimator, getCtxCache()
#if JVET_Z0153_IBC_EXT_REF
, pps0.getPicWidthInLumaSamples()
#if JVET_AJ0172_IBC_ITMP_ALIGN_REF_AREA
, pps0.getPicHeightInLumaSamples()
#endif

Karsten Suehring
committed
// 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
#if JVET_AE0159_FIBC || JVET_AE0059_INTER_CCCM || JVET_AE0078_IBC_LIC_EXTENSION || JVET_AF0073_INTER_CCP_MERGE
m_cInterSearch.setIntraPrediction(&m_cIntraSearch);
Wei Chen
committed
#endif
#if JVET_AH0200_INTRA_TMP_BV_REORDER
m_cIntraSearch.setInterPrediction(&m_cInterSearch);
Pekka Astola
committed
#endif

Karsten Suehring
committed
m_iMaxRefPicNum = 0;
#if ER_CHROMA_QP_WCG_PPS
if( m_wcgChromaQpControl.isEnabled() )
{
xInitScalingLists( sps0, *m_apsMap.getPS( 1 ) );
xInitScalingLists( sps0, aps0 );

Karsten Suehring
committed
}
else
#endif
{
xInitScalingLists( sps0, aps0 );

Karsten Suehring
committed
}
if (m_resChangeInClvsEnabled)
xInitScalingLists( sps0, *m_apsMap.getPS( ENC_PPS_ID_RPR ) );
if (getUseCompositeRef())
{
Picture *picBg = new Picture;
picBg->create(
Fabrice Le Léannec
committed
sps0.getRprEnabledFlag(),
sps0.getGDREnabledFlag(),
sps0.getWrapAroundEnabledFlag(), sps0.getChromaFormatIdc(),
Size(pps0.getPicWidthInLumaSamples(), pps0.getPicHeightInLumaSamples()), sps0.getMaxCUWidth(),
sps0.getMaxCUWidth() + EXT_PICTURE_SIZE, false, m_layerId, getGopBasedTemporalFilterEnabled());
picBg->getRecoBuf().fill(0);
#if JVET_AK0065_TALF
picBg->finalInit( m_vps, sps0, pps0, &m_picHeader, m_apss, m_apss2, m_lmcsAPS, m_scalinglistAPS );
#else
picBg->finalInit( m_vps, sps0, pps0, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS );
picBg->allocateNewSlice();
picBg->createSpliceIdx(pps0.pcv->sizeInCtus);
m_cGOPEncoder.setPicBg(picBg);
Picture *picOrig = new Picture;
picOrig->create(
Fabrice Le Léannec
committed
sps0.getRprEnabledFlag(),
sps0.getGDREnabledFlag(),
sps0.getWrapAroundEnabledFlag(), sps0.getChromaFormatIdc(),
Size(pps0.getPicWidthInLumaSamples(), pps0.getPicHeightInLumaSamples()), sps0.getMaxCUWidth(),
sps0.getMaxCUWidth() + EXT_PICTURE_SIZE, false, m_layerId, getGopBasedTemporalFilterEnabled());
picOrig->getOrigBuf().fill(0);
m_cGOPEncoder.setPicOrig(picOrig);
}

Karsten Suehring
committed
}
void EncLib::xInitScalingLists( SPS &sps, APS &aps )

Karsten Suehring
committed
{
// 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)

Karsten Suehring
committed
};
Quant* quant = getTrQuant()->getQuant();
if(getUseScalingListId() == SCALING_LIST_OFF)
{
quant->setFlatScalingList(maxLog2TrDynamicRange, sps.getBitDepths());
quant->setUseScalingList(false);

Karsten Suehring
committed
for( int jId = 1; jId < m_numCuEncStacks; jId++ )
{
getTrQuant( jId )->getQuant()->setFlatScalingList( maxLog2TrDynamicRange, sps.getBitDepths() );
getTrQuant( jId )->getQuant()->setUseScalingList( false );
}
#endif

Karsten Suehring
committed
}
else if(getUseScalingListId() == SCALING_LIST_DEFAULT)
{
aps.getScalingList().setDefaultScalingList ();
quant->setScalingList( &( aps.getScalingList() ), maxLog2TrDynamicRange, sps.getBitDepths() );

Karsten Suehring
committed
quant->setUseScalingList(true);

Karsten Suehring
committed
for( int jId = 1; jId < m_numCuEncStacks; jId++ )
{
getTrQuant( jId )->getQuant()->setUseScalingList( true );
}
sps.setDisableScalingMatrixForLfnstBlks(getDisableScalingMatrixForLfnstBlks());

Karsten Suehring
committed
#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 );
}
aps.getScalingList().setChromaScalingListPresentFlag((sps.getChromaFormatIdc()!=CHROMA_400));
quant->setScalingList( &( aps.getScalingList() ), maxLog2TrDynamicRange, sps.getBitDepths() );

Karsten Suehring
committed
quant->setUseScalingList(true);

Karsten Suehring
committed
for( int jId = 1; jId < m_numCuEncStacks; jId++ )
{
getTrQuant( jId )->getQuant()->setUseScalingList( true );
}
Adarsh Krishnan Ramasubramonian
committed
#endif
sps.setDisableScalingMatrixForLfnstBlks(getDisableScalingMatrixForLfnstBlks());

Karsten Suehring
committed
}
else
{
THROW("error : ScalingList == " << getUseScalingListId() << " not supported\n");
}
if( getUseScalingListId() == SCALING_LIST_FILE_READ )

Karsten Suehring
committed
{
// Prepare delta's:
Chen-Yen Lai
committed
for (uint32_t scalingListId = 0; scalingListId < 28; scalingListId++)
{
Hongbin Zhang
committed
if (aps.getScalingList().getChromaScalingListPresentFlag()||aps.getScalingList().isLumaScalingList(scalingListId))
Chen-Yen Lai
committed
aps.getScalingList().checkPredMode(scalingListId);
Chen-Yen Lai
committed
}

Karsten Suehring
committed
}
}
void EncLib::xInitPPSforLT(PPS& pps)
{
pps.setOutputFlagPresentFlag(true);
pps.setDeblockingFilterControlPresentFlag(true);
pps.setPPSDeblockingFilterDisabledFlag(true);
}

Karsten Suehring
committed
// ====================================================================================================================
// 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;
}

Karsten Suehring
committed
}
bool EncLib::encodePrep(bool flush, PelStorage* pcPicYuvOrg, const InputColourSpaceConversion snrCSC, std::list<PelUnitBuf*>& rcListPicYuvRecOut, int& iNumEncoded
#if JVET_AG0116
, PelStorage** ppcPicYuvRPR
#endif
)
{
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_AK0065_TALF
picCurr->finalInit(m_vps, *sps, *pps, &m_picHeader, m_apss, m_apss2, m_lmcsAPS, m_scalinglistAPS);
#else
picCurr->finalInit( m_vps, *sps, *pps, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS );
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,
#if MSSIM_UNIFORM_METRICS_LOG
m_printMSSSIM,
#endif
true, 0);
#if JVET_O0756_CALCULATE_HDRMETRICS
m_metricTime = m_cGOPEncoder.getMetricTime();
#endif
m_cGOPEncoder.setEncodedLTRef( true );
if( m_RCEnableRateControl )