compressGOP
晋骏喆
2023-12-01
// ====================================================================================================================
// Public member functions
// ====================================================================================================================
Void TEncGOP::compressGOP( Int iPOCLast, Int iNumPicRcvd, TComList<TComPic*>& rcListPic, TComList<TComPicYuv*>& rcListPicYuvRecOut, std::list<AccessUnit>& accessUnitsInGOP, bool isField, bool isTff)
{
TComPic* pcPic;
TComPicYuv* pcPicYuvRecOut;
TComSlice* pcSlice;
TComOutputBitstream *pcBitstreamRedirect;
pcBitstreamRedirect = new TComOutputBitstream;
AccessUnit::iterator itLocationToPushSliceHeaderNALU; // used to store location where NALU containing slice header is to be inserted >用于存储包含silce头的邋邋NALU的插入位置
UInt uiOneBitstreamPerSliceLength = 0;
TEncSbac* pcSbacCoders = NULL;
TComOutputBitstream* pcSubstreamsOut = NULL;
xInitGOP( iPOCLast, iNumPicRcvd, rcListPic, rcListPicYuvRecOut, isField );
m_iNumPicCoded = 0;
SEIPictureTiming pictureTimingSEI;
Bool writeSOP = m_pcCfg->getSOPDescriptionSEIEnabled();
// Initialize Scalable Nesting SEI with single layer values
SEIScalableNesting scalableNestingSEI;
scalableNestingSEI.m_bitStreamSubsetFlag = 1; // If the nested SEI messages are picture buffereing SEI mesages, picure timing SEI messages or sub-picture timing SEI messages, bitstream_subset_flag shall be equal to 1
scalableNestingSEI.m_nestingOpFlag = 0;
scalableNestingSEI.m_nestingNumOpsMinus1 = 0; //nesting_num_ops_minus1
scalableNestingSEI.m_allLayersFlag = 0;
scalableNestingSEI.m_nestingNoOpMaxTemporalIdPlus1 = 6 + 1; //nesting_no_op_max_temporal_id_plus1
scalableNestingSEI.m_nestingNumLayersMinus1 = 1 - 1; //nesting_num_layers_minus1
scalableNestingSEI.m_nestingLayerId[0] = 0;
scalableNestingSEI.m_callerOwnsSEIs = true;
Int picSptDpbOutputDuDelay = 0;
UInt *accumBitsDU = NULL;
UInt *accumNalsDU = NULL;
SEIDecodingUnitInfo decodingUnitInfoSEI;
for ( Int iGOPid=0; iGOPid < m_iGopSize; iGOPid++ )
{
UInt uiColDir = 1;
//-- For time output for each slice
long iBeforeTime = clock();
//select uiColDir
Int iCloseLeft=1, iCloseRight=-1;
for(Int i = 0; i<m_pcCfg->getGOPEntry(iGOPid).m_numRefPics; i++)
{
Int iRef = m_pcCfg->getGOPEntry(iGOPid).m_referencePics[i];
if(iRef>0&&(iRef<iCloseRight||iCloseRight==-1))
{
iCloseRight=iRef;
}
else if(iRef<0&&(iRef>iCloseLeft||iCloseLeft==1))
{
iCloseLeft=iRef;
}
}
if(iCloseRight>-1)
{
iCloseRight=iCloseRight+m_pcCfg->getGOPEntry(iGOPid).m_POC-1;
}
if(iCloseLeft<1)
{
iCloseLeft=iCloseLeft+m_pcCfg->getGOPEntry(iGOPid).m_POC-1;
while(iCloseLeft<0)
{
iCloseLeft+=m_iGopSize;
}
}
Int iLeftQP=0, iRightQP=0;
for(Int i=0; i<m_iGopSize; i++)
{
if(m_pcCfg->getGOPEntry(i).m_POC==(iCloseLeft%m_iGopSize)+1)
{
iLeftQP= m_pcCfg->getGOPEntry(i).m_QPOffset;
}
if (m_pcCfg->getGOPEntry(i).m_POC==(iCloseRight%m_iGopSize)+1)
{
iRightQP=m_pcCfg->getGOPEntry(i).m_QPOffset;
}
}
if(iCloseRight>-1&&iRightQP<iLeftQP)
{
uiColDir=0;
}
/// Initial to start encoding
Int iTimeOffset;
Int pocCurr;
if(iPOCLast == 0) //case first frame or first top field
{
pocCurr=0;
iTimeOffset = 1;
}
else if(iPOCLast == 1 && isField) //case first bottom field, just like the first frame, the poc computation is not right anymore, we set the right value
{
pocCurr = 1;
iTimeOffset = 1;
}
else
{
pocCurr = iPOCLast - iNumPicRcvd + m_pcCfg->getGOPEntry(iGOPid).m_POC - isField;
iTimeOffset = m_pcCfg->getGOPEntry(iGOPid).m_POC;
}
if(pocCurr>=m_pcCfg->getFramesToBeEncoded())
{
continue;
}
if( getNalUnitType(pocCurr, m_iLastIDR, isField) == NAL_UNIT_CODED_SLICE_IDR_W_RADL || getNalUnitType(pocCurr, m_iLastIDR, isField) == NAL_UNIT_CODED_SLICE_IDR_N_LP )
{
m_iLastIDR = pocCurr;
}
// start a new access unit: create an entry in the list of output access units
accessUnitsInGOP.push_back(AccessUnit());
AccessUnit& accessUnit = accessUnitsInGOP.back();
xGetBuffer( rcListPic, rcListPicYuvRecOut, iNumPicRcvd, iTimeOffset, pcPic, pcPicYuvRecOut, pocCurr, isField);
// Slice data initialization
pcPic->clearSliceBuffer();
assert(pcPic->getNumAllocatedSlice() == 1);
m_pcSliceEncoder->setSliceIdx(0);
pcPic->setCurrSliceIdx(0);
m_pcSliceEncoder->initEncSlice ( pcPic, iPOCLast, pocCurr, iNumPicRcvd, iGOPid, pcSlice, m_pcEncTop->getSPS(), m_pcEncTop->getPPS(), isField );
//Set Frame/Field coding
pcSlice->getPic()->setField(isField);
pcSlice->setLastIDR(m_iLastIDR);
pcSlice->setSliceIdx(0);
//set default slice level flag to the same as SPS level flag
pcSlice->setLFCrossSliceBoundaryFlag( pcSlice->getPPS()->getLoopFilterAcrossSlicesEnabledFlag() );
pcSlice->setScalingList ( m_pcEncTop->getScalingList() );
if(m_pcEncTop->getUseScalingListId() == SCALING_LIST_OFF)
{
m_pcEncTop->getTrQuant()->setFlatScalingList();
m_pcEncTop->getTrQuant()->setUseScalingList(false);
m_pcEncTop->getSPS()->setScalingListPresentFlag(false);
m_pcEncTop->getPPS()->setScalingListPresentFlag(false);
}
else if(m_pcEncTop->getUseScalingListId() == SCALING_LIST_DEFAULT)
{
pcSlice->setDefaultScalingList ();
m_pcEncTop->getSPS()->setScalingListPresentFlag(false);
m_pcEncTop->getPPS()->setScalingListPresentFlag(false);
m_pcEncTop->getTrQuant()->setScalingList(pcSlice->getScalingList());
m_pcEncTop->getTrQuant()->setUseScalingList(true);
}
else if(m_pcEncTop->getUseScalingListId() == SCALING_LIST_FILE_READ)
{
if(pcSlice->getScalingList()->xParseScalingList(m_pcCfg->getScalingListFile()))
{
pcSlice->setDefaultScalingList ();
}
pcSlice->getScalingList()->checkDcOfMatrix();
m_pcEncTop->getSPS()->setScalingListPresentFlag(pcSlice->checkDefaultScalingList());
m_pcEncTop->getPPS()->setScalingListPresentFlag(false);
m_pcEncTop->getTrQuant()->setScalingList(pcSlice->getScalingList());
m_pcEncTop->getTrQuant()->setUseScalingList(true);
}
else
{
printf("error : ScalingList == %d no support\n",m_pcEncTop->getUseScalingListId());
assert(0);
}
if(pcSlice->getSliceType()==B_SLICE&&m_pcCfg->getGOPEntry(iGOPid).m_sliceType=='P')
{
pcSlice->setSliceType(P_SLICE);
}
if(pcSlice->getSliceType()==B_SLICE&&m_pcCfg->getGOPEntry(iGOPid).m_sliceType=='I')
{
pcSlice->setSliceType(I_SLICE);
}
// Set the nal unit type
pcSlice->setNalUnitType(getNalUnitType(pocCurr, m_iLastIDR, isField));
if(pcSlice->getTemporalLayerNonReferenceFlag())
{
if (pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_TRAIL_R &&
!(m_iGopSize == 1 && pcSlice->getSliceType() == I_SLICE))
// Add this condition to avoid POC issues with encoder_intra_main.cfg configuration (see #1127 in bug tracker)
{
pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_TRAIL_N);
}
if(pcSlice->getNalUnitType()==NAL_UNIT_CODED_SLICE_RADL_R)
{
pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_RADL_N);
}
if(pcSlice->getNalUnitType()==NAL_UNIT_CODED_SLICE_RASL_R)
{
pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_RASL_N);
}
}
// Do decoding refresh marking if any
pcSlice->decodingRefreshMarking(m_pocCRA, m_bRefreshPending, rcListPic);
m_pcEncTop->selectReferencePictureSet(pcSlice, pocCurr, iGOPid);
pcSlice->getRPS()->setNumberOfLongtermPictures(0);
#if FIX1172
if ( pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_LP
|| pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_RADL
|| pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_N_LP
|| pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_W_RADL
|| pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_N_LP
|| pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA ) // IRAP picture
{
m_associatedIRAPType = pcSlice->getNalUnitType();
m_associatedIRAPPOC = pocCurr;
}
pcSlice->setAssociatedIRAPType(m_associatedIRAPType);
pcSlice->setAssociatedIRAPPOC(m_associatedIRAPPOC);
#endif
if ((pcSlice->checkThatAllRefPicsAreAvailable(rcListPic, pcSlice->getRPS(), false) != 0) || (pcSlice->isIRAP()))
{
pcSlice->createExplicitReferencePictureSetFromReference(rcListPic, pcSlice->getRPS(), pcSlice->isIRAP());
}
pcSlice->applyReferencePictureSet(rcListPic, pcSlice->getRPS());
if(pcSlice->getTLayer() > 0
&& !( pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RADL_N // Check if not a leading picture
|| pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RADL_R
|| pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RASL_N
|| pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RASL_R )
)
{
if(pcSlice->isTemporalLayerSwitchingPoint(rcListPic) || pcSlice->getSPS()->getTemporalIdNestingFlag())
{
if(pcSlice->getTemporalLayerNonReferenceFlag())
{
pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_TSA_N);
}
else
{
pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_TSA_R);
}
}
else if(pcSlice->isStepwiseTemporalLayerSwitchingPointCandidate(rcListPic))
{
Bool isSTSA=true;
for(Int ii=iGOPid+1;(ii<m_pcCfg->getGOPSize() && isSTSA==true);ii++)
{
Int lTid= m_pcCfg->getGOPEntry(ii).m_temporalId;
if(lTid==pcSlice->getTLayer())
{
TComReferencePictureSet* nRPS = pcSlice->getSPS()->getRPSList()->getReferencePictureSet(ii);
for(Int jj=0;jj<nRPS->getNumberOfPictures();jj++)
{
if(nRPS->getUsed(jj))
{
Int tPoc=m_pcCfg->getGOPEntry(ii).m_POC+nRPS->getDeltaPOC(jj);
Int kk=0;
for(kk=0;kk<m_pcCfg->getGOPSize();kk++)
{
if(m_pcCfg->getGOPEntry(kk).m_POC==tPoc)
break;
}
Int tTid=m_pcCfg->getGOPEntry(kk).m_temporalId;
if(tTid >= pcSlice->getTLayer())
{
isSTSA=false;
break;
}
}
}
}
}
if(isSTSA==true)
{
if(pcSlice->getTemporalLayerNonReferenceFlag())
{
pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_STSA_N);
}
else
{
pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_STSA_R);
}
}
}
}
arrangeLongtermPicturesInRPS(pcSlice, rcListPic);
TComRefPicListModification* refPicListModification = pcSlice->getRefPicListModification();
refPicListModification->setRefPicListModificationFlagL0(0);
refPicListModification->setRefPicListModificationFlagL1(0);
pcSlice->setNumRefIdx(REF_PIC_LIST_0,min(m_pcCfg->getGOPEntry(iGOPid).m_numRefPicsActive,pcSlice->getRPS()->getNumberOfPictures()));
pcSlice->setNumRefIdx(REF_PIC_LIST_1,min(m_pcCfg->getGOPEntry(iGOPid).m_numRefPicsActive,pcSlice->getRPS()->getNumberOfPictures()));
#if ADAPTIVE_QP_SELECTION
pcSlice->setTrQuant( m_pcEncTop->getTrQuant() );
#endif
// Set reference list
pcSlice->setRefPicList ( rcListPic );
// Slice info. refinement
if ( (pcSlice->getSliceType() == B_SLICE) && (pcSlice->getNumRefIdx(REF_PIC_LIST_1) == 0) )
{
pcSlice->setSliceType ( P_SLICE );
}
if (pcSlice->getSliceType() == B_SLICE)
{
pcSlice->setColFromL0Flag(1-uiColDir);
Bool bLowDelay = true;
Int iCurrPOC = pcSlice->getPOC();
Int iRefIdx = 0;
for (iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_0) && bLowDelay; iRefIdx++)
{
if ( pcSlice->getRefPic(REF_PIC_LIST_0, iRefIdx)->getPOC() > iCurrPOC )
{
bLowDelay = false;
}
}
for (iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_1) && bLowDelay; iRefIdx++)
{
if ( pcSlice->getRefPic(REF_PIC_LIST_1, iRefIdx)->getPOC() > iCurrPOC )
{
bLowDelay = false;
}
}
pcSlice->setCheckLDC(bLowDelay);
}
else
{
pcSlice->setCheckLDC(true);
}
uiColDir = 1-uiColDir;
//-------------------------------------------------------------
pcSlice->setRefPOCList();
pcSlice->setList1IdxToList0Idx();
if (m_pcEncTop->getTMVPModeId() == 2)
{
if (iGOPid == 0) // first picture in SOP (i.e. forward B)
{
pcSlice->setEnableTMVPFlag(0);
}
else
{
// Note: pcSlice->getColFromL0Flag() is assumed to be always 0 and getcolRefIdx() is always 0.
pcSlice->setEnableTMVPFlag(1);
}
pcSlice->getSPS()->setTMVPFlagsPresent(1);
}
else if (m_pcEncTop->getTMVPModeId() == 1)
{
pcSlice->getSPS()->setTMVPFlagsPresent(1);
pcSlice->setEnableTMVPFlag(1);
}
else
{
pcSlice->getSPS()->setTMVPFlagsPresent(0);
pcSlice->setEnableTMVPFlag(0);
}
/// Compress a slice
// Slice compression 条压缩
if (m_pcCfg->getUseASR())
{
m_pcSliceEncoder->setSearchRange(pcSlice);
}
Bool bGPBcheck=false;
if ( pcSlice->getSliceType() == B_SLICE)
{
if ( pcSlice->getNumRefIdx(RefPicList( 0 ) ) == pcSlice->getNumRefIdx(RefPicList( 1 ) ) )
{
bGPBcheck=true;
Int i;
for ( i=0; i < pcSlice->getNumRefIdx(RefPicList( 1 ) ); i++ )
{
if ( pcSlice->getRefPOC(RefPicList(1), i) != pcSlice->getRefPOC(RefPicList(0), i) )
{
bGPBcheck=false;
break;
}
}
}
}
if(bGPBcheck)
{
pcSlice->setMvdL1ZeroFlag(true);
}
else
{
pcSlice->setMvdL1ZeroFlag(false);
}
pcPic->getSlice(pcSlice->getSliceIdx())->setMvdL1ZeroFlag(pcSlice->getMvdL1ZeroFlag());
Double lambda = 0.0;
Int actualHeadBits = 0;
Int actualTotalBits = 0;
Int estimatedBits = 0;
Int tmpBitsBeforeWriting = 0;
if ( m_pcCfg->getUseRateCtrl() )
{
Int frameLevel = m_pcRateCtrl->getRCSeq()->getGOPID2Level( iGOPid );
if ( pcPic->getSlice(0)->getSliceType() == I_SLICE )
{
frameLevel = 0;
}
m_pcRateCtrl->initRCPic( frameLevel );
estimatedBits = m_pcRateCtrl->getRCPic()->getTargetBits();
Int sliceQP = m_pcCfg->getInitialQP();
if ( ( pcSlice->getPOC() == 0 && m_pcCfg->getInitialQP() > 0 ) || ( frameLevel == 0 && m_pcCfg->getForceIntraQP() ) ) // QP is specified
{
Int NumberBFrames = ( m_pcCfg->getGOPSize() - 1 );
Double dLambda_scale = 1.0 - Clip3( 0.0, 0.5, 0.05*(Double)NumberBFrames );
Double dQPFactor = 0.57*dLambda_scale;
Int SHIFT_QP = 12;
Int bitdepth_luma_qp_scale = 0;
Double qp_temp = (Double) sliceQP + bitdepth_luma_qp_scale - SHIFT_QP;
lambda = dQPFactor*pow( 2.0, qp_temp/3.0 );
}
else if ( frameLevel == 0 ) // intra case, but use the model
{
m_pcSliceEncoder->calCostSliceI(pcPic);
if ( m_pcCfg->getIntraPeriod() != 1 ) // do not refine allocated bits for all intra case
{
Int bits = m_pcRateCtrl->getRCSeq()->getLeftAverageBits();
bits = m_pcRateCtrl->getRCPic()->getRefineBitsForIntra( bits );
if ( bits < 200 )
{
bits = 200;
}
m_pcRateCtrl->getRCPic()->setTargetBits( bits );
}
list<TEncRCPic*> listPreviousPicture = m_pcRateCtrl->getPicList();
m_pcRateCtrl->getRCPic()->getLCUInitTargetBit