Skip to content

Commit

Permalink
New decoder refresh type optimized for closed GOP DASH streaming: idr…
Browse files Browse the repository at this point in the history
…_no_radl
  • Loading branch information
adamjw24 committed Jun 27, 2024
1 parent 9969b5f commit b94f415
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 24 deletions.
1 change: 1 addition & 0 deletions include/vvenc/vvencCfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ typedef enum
VVENC_DRT_RECOVERY_POINT_SEI = 3,
VVENC_DRT_IDR2 = 4, //deprecated
VVENC_DRT_CRA_CRE = 5, //constrained RASL encoding
VVENC_DRT_IDR_NO_RADL = 6,
}vvencDecodingRefreshType;

typedef enum
Expand Down
20 changes: 15 additions & 5 deletions source/Lib/CommonLib/Slice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -952,7 +952,7 @@ void Slice::applyReferencePictureListBasedMarking(const PicList& rcListPic, cons
}

// int Slice::checkThatAllRefPicsAreAvailable( const PicList& rcListPic, const ReferencePictureList *pRPL, int rplIdx ) const
bool Slice::isRplPicMissing( const PicList& rcListPic, const RefPicList refList, int& missingPoc ) const
bool Slice::isRplPicMissing( const PicList& rcListPic, const RefPicList refList, int& missingPoc, int ip ) const
{
if( isIDRorBLA() ) return false; // assume that all pic in the DPB will be flushed anyway so no need to check.

Expand Down Expand Up @@ -1034,7 +1034,7 @@ bool Slice::isRplPicMissing( const PicList& rcListPic, const RefPicList refList,

for( auto& pic : rcListPic )
{
if( ! pic->isLongTerm && pic->getPOC() == poc + pRPL->refPicIdentifier[ii] && pic->isReferenced )
if( ! pic->isLongTerm && pic->getPOC() == poc + pRPL->refPicIdentifier[ii] && pic->isReferenced && !refPicIsFutureIDRnoLP( pic->getPOC(), ip ) )
{
isAvailable = true;
break;
Expand All @@ -1050,7 +1050,7 @@ bool Slice::isRplPicMissing( const PicList& rcListPic, const RefPicList refList,
return false;
}

void Slice::createExplicitReferencePictureSetFromReference(const PicList& rcListPic, const ReferencePictureList* pRPL0, const ReferencePictureList* pRPL1)
void Slice::createExplicitReferencePictureSetFromReference(const PicList& rcListPic, const ReferencePictureList* pRPL0, const ReferencePictureList* pRPL1, int ip)
{
Picture* picCand;;
int pocCycle = 0;
Expand Down Expand Up @@ -1080,7 +1080,7 @@ void Slice::createExplicitReferencePictureSetFromReference(const PicList& rcList
picCand = *(iterPic++);
if( pic->layerId == picCand->layerId && picCand->isReferenced)
{
if (!rplSrc0.isLongtermRefPic[ii] && picCand->poc == poc + rplSrc0.refPicIdentifier[ii] && !isPocRestrictedByDRAP(picCand->poc, picCand->precedingDRAP))
if (!rplSrc0.isLongtermRefPic[ii] && picCand->poc == poc + rplSrc0.refPicIdentifier[ii] && !isPocRestrictedByDRAP(picCand->poc, picCand->precedingDRAP) && !refPicIsFutureIDRnoLP(picCand->poc, ip))
{
isAvailable = true;
break;
Expand Down Expand Up @@ -1144,7 +1144,7 @@ void Slice::createExplicitReferencePictureSetFromReference(const PicList& rcList
picCand = *(iterPic++);
if( pic->layerId == picCand->layerId && picCand->isReferenced )
{
if (!rplSrc1.isLongtermRefPic[ii] && picCand->poc == poc + rplSrc1.refPicIdentifier[ii] && !isPocRestrictedByDRAP(picCand->poc, picCand->precedingDRAP))
if (!rplSrc1.isLongtermRefPic[ii] && picCand->poc == poc + rplSrc1.refPicIdentifier[ii] && !isPocRestrictedByDRAP(picCand->poc, picCand->precedingDRAP) && !refPicIsFutureIDRnoLP(picCand->poc, ip))
{
isAvailable = true;
break;
Expand Down Expand Up @@ -1330,6 +1330,16 @@ bool Slice::isPocRestrictedByDRAP( int poc, bool precedingDRAPInDecodingOrder )
return ( isDRAP && poc != associatedIRAP ) || ( latestDRAPPOC != MAX_INT && poc > latestDRAPPOC && (precedingDRAPInDecodingOrder || poc < latestDRAPPOC) );
}

bool Slice::refPicIsFutureIDRnoLP( int candPoc, int ipc ) const
{
//check if we are not trying to reference a future IDR picture
if( ipc != 0 && associatedIRAP + ipc == candPoc )
{
return true;
}
return false;
}

void Slice::setAlfApsIds( const std::vector<int>& ApsIDs)
{
lumaApsId.resize(numAps);
Expand Down
6 changes: 4 additions & 2 deletions source/Lib/CommonLib/Slice.h
Original file line number Diff line number Diff line change
Expand Up @@ -1298,8 +1298,8 @@ class Slice
void checkLeadingPictureRestrictions( const PicList& rcListPic ) const;
void applyReferencePictureListBasedMarking( const PicList& rcListPic, const ReferencePictureList* pRPL0, const ReferencePictureList* pRPL1, const int layerId, const PPS& pps, const bool usingLongTerm = true ) const;
bool isStepwiseTemporalLayerSwitchingPointCandidate( const PicList& rcListPic ) const;
bool isRplPicMissing( const PicList& rcListPic, const RefPicList refList, int& missingPoc ) const;
void createExplicitReferencePictureSetFromReference( const PicList& rcListPic, const ReferencePictureList* pRPL0, const ReferencePictureList* pRPL1 );
bool isRplPicMissing( const PicList& rcListPic, const RefPicList refList, int& missingPoc, int ip ) const;
void createExplicitReferencePictureSetFromReference( const PicList& rcListPic, const ReferencePictureList* pRPL0, const ReferencePictureList* pRPL1, int ip );
void getWpScaling( RefPicList e, int iRefIdx, WPScalingParam *&wp) const;

void resetWpScaling();
Expand All @@ -1313,6 +1313,8 @@ class Slice
unsigned getMinPictureDistance() const ;

bool isPocRestrictedByDRAP( int poc, bool precedingDRAPInDecodingOrder ) const;
bool refPicIsFutureIDRnoLP( int candPoc, int ipc ) const;

void setAlfApsIds( const std::vector<int>& ApsIDs);
private:
Picture* xGetLongTermRefPic(const PicList& rcListPic, int poc, bool pocHasMsb);
Expand Down
23 changes: 14 additions & 9 deletions source/Lib/EncoderLib/EncGOP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1325,6 +1325,10 @@ vvencNalUnitType EncGOP::xGetNalUnitType( const GOPEntry* _gopEntry ) const
return VVENC_NAL_UNIT_CODED_SLICE_CRA;
}
}
else if( m_pcEncCfg->m_DecodingRefreshType == VVENC_DRT_IDR_NO_RADL )
{
return VVENC_NAL_UNIT_CODED_SLICE_IDR_N_LP;
}
else
{
return VVENC_NAL_UNIT_CODED_SLICE_IDR_W_RADL;
Expand All @@ -1341,7 +1345,7 @@ vvencNalUnitType EncGOP::xGetNalUnitType( const GOPEntry* _gopEntry ) const
return VVENC_NAL_UNIT_CODED_SLICE_RASL;
}

if( m_lastIDR > 0 && gopEntry.m_POC < m_lastIDR )
if( m_lastIDR > 0 && gopEntry.m_POC < m_lastIDR && m_pcEncCfg->m_DecodingRefreshType != VVENC_DRT_IDR_NO_RADL )
{
return VVENC_NAL_UNIT_CODED_SLICE_RADL;
}
Expand Down Expand Up @@ -1631,8 +1635,8 @@ void EncGOP::xGetProcessingLists( std::list<Picture*>& procList, std::list<Pictu
}
else
{
// just pass the input list to processing list
procList.splice( procList.end(), m_gopEncListInput );
// just pass the input list to processing list
procList.splice( procList.end(), m_gopEncListInput );
m_gopEncListInput.clear();
}
}
Expand Down Expand Up @@ -1726,8 +1730,8 @@ void EncGOP::xInitGopQpCascade( Picture& keyPic, PicList::const_iterator picList
for (auto picItr = picListBegin; picItr != picList.end(); ++picItr)
{
auto pic = (*picItr);
if (pic->gopEntry->m_gopNum == gopNum )
{
if( pic->gopEntry->m_gopNum == gopNum )
{
if( pic->m_picShared->m_picMotEstError > 0 )
{
CHECK( pic->isInitDone, "try to modify GOP qp of picture, which has already been initialized" );
Expand Down Expand Up @@ -1833,12 +1837,12 @@ void EncGOP::xInitGopQpCascade( Picture& keyPic, PicList::const_iterator picList

// enable QP adjustment after coded Intra in the first GOP or on a scene cut
// NOTE: on some scene cuts, in case of low motion activity, targetBits equals to zero (QPA)
if (m_rcap.accumGopCounter == 0 && m_rcap.accumTargetBits > 0 && !nextKeyPicAfterIDR )
if (m_rcap.accumGopCounter == 0 && m_rcap.accumTargetBits > 0 && !nextKeyPicAfterIDR)
{
for (auto picItr = picListBegin; picItr != picList.end(); ++picItr)
{
auto pic = (*picItr);
// just on the next picture in decoding order after start of GOP
// just on the next picture in decoding order after start of GOP
if (pic->gopEntry->m_gopNum == gopNum && !pic->gopEntry->m_isStartOfGop)
{
pic->isSceneCutCheckAdjQP = true;
Expand Down Expand Up @@ -1929,9 +1933,10 @@ void EncGOP::xInitFirstSlice( Picture& pic, const PicList& picList, bool isEncod
// reference list
xSelectReferencePictureList( slice );
int missingPoc;
if ( slice->isRplPicMissing( picList, REF_PIC_LIST_0, missingPoc ) || slice->isRplPicMissing( picList, REF_PIC_LIST_1, missingPoc ) )
int ipc = ( m_pcEncCfg->m_DecodingRefreshType == VVENC_DRT_IDR_NO_RADL ) ? m_pcEncCfg->m_IntraPeriod : 0;
if ( slice->isRplPicMissing( picList, REF_PIC_LIST_0, missingPoc, ipc ) || slice->isRplPicMissing( picList, REF_PIC_LIST_1, missingPoc, ipc ) )
{
slice->createExplicitReferencePictureSetFromReference( picList, slice->rpl[0], slice->rpl[1] );
slice->createExplicitReferencePictureSetFromReference( picList, slice->rpl[0], slice->rpl[1], ipc );
}
slice->applyReferencePictureListBasedMarking( picList, slice->rpl[0], slice->rpl[1], 0, *slice->pps, m_pcEncCfg->m_numThreads == 0 );

Expand Down
30 changes: 29 additions & 1 deletion source/Lib/EncoderLib/GOPCfg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ void GOPCfg::initGopList( int refreshType, bool poc0idr, int intraPeriod, int go
m_numTillIntra = poc0idr ? 0 : (int)m_gopList->size() - 1;
m_minIntraDist = minIntraDist;
m_lastIntraPOC = -1;
m_adjustNoLPcodingOrder = m_refreshType == VVENC_DRT_IDR_NO_RADL && m_fixIntraPeriod <= m_maxGopSize;
}

void GOPCfg::getNextGopEntry( GOPEntry& gopEntry )
Expand Down Expand Up @@ -170,11 +171,15 @@ void GOPCfg::getNextGopEntry( GOPEntry& gopEntry )
const int pocInGop = m_nextPoc - m_pocOffset;
const int gopId = m_pocToGopIdx[ pocInGop % (int)m_pocToGopIdx.size() ];
const bool isLeading0 = m_poc0idr && m_nextPoc == 0 ? true : false; // for poc0idr, we have a leading poc 0

gopEntry = (*m_gopList)[ gopId ];
gopEntry.m_POC = m_nextPoc;
gopEntry.m_codingNum = isLeading0 ? 0 : m_cnOffset + gopId;
gopEntry.m_gopNum = m_gopNum;
if( m_nextPoc != 0 && m_adjustNoLPcodingOrder )
{
xAdjustNoLPcodingOrder( gopEntry, gopId );
}
gopEntry.m_isValid = true;

// mark start of intra
Expand All @@ -198,6 +203,7 @@ void GOPCfg::getNextGopEntry( GOPEntry& gopEntry )
m_gopList = &m_defaultGopLists[ 0 ];
m_nextListIdx = std::min( 1, (int)m_defaultGopLists.size() - 1 );
m_numTillIntra = m_fixIntraPeriod;
m_adjustNoLPcodingOrder = m_refreshType == VVENC_DRT_IDR_NO_RADL && m_fixIntraPeriod <= m_maxGopSize;
}
else
{
Expand All @@ -212,6 +218,8 @@ void GOPCfg::getNextGopEntry( GOPEntry& gopEntry )
CHECK( remainSize != (int)m_remainGopList.size() || prevGopSize != m_defGopSize, "remaining size does not match size of pre-calculated gop list" );
m_gopList = &m_remainGopList;
}
//if we have a full gop, we don't need to change the coding order...
m_adjustNoLPcodingOrder = m_refreshType == VVENC_DRT_IDR_NO_RADL && m_numTillIntra <= m_maxGopSize;
}
xCreatePocToGopIdx( *m_gopList, !m_poc0idr, m_pocToGopIdx );
m_numTillGop = (int)m_gopList->size();
Expand Down Expand Up @@ -1122,6 +1130,26 @@ int GOPCfg::xGetMaxNumReorder( const GOPEntry& gopEntry, const GOPEntryList& gop
return numReorder;
}

void GOPCfg::xAdjustNoLPcodingOrder( GOPEntry& gopEntry, const int orgGopId ) const
{
if( orgGopId == 0 )
{
//postpone the intra frame and put it in a new gop
gopEntry.m_codingNum += (int)m_pocToGopIdx.size() - 1;
gopEntry.m_gopNum += 1;
}
else
{
gopEntry.m_codingNum -= 1;
if( orgGopId == 1 && m_fixIntraPeriod > m_maxGopSize )
{
gopEntry.m_isStartOfGop = true;
}
}

return;
}

} // namespace vvenc

//! \}
Expand Down
4 changes: 3 additions & 1 deletion source/Lib/EncoderLib/GOPCfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class GOPCfg
int m_defaultNumActive[ 2 ];
int m_minIntraDist;
int m_lastIntraPOC;
bool m_adjustNoLPcodingOrder;

public:
GOPCfg( MsgLog& _m )
Expand All @@ -119,6 +120,7 @@ class GOPCfg
, m_defaultNumActive{ 0, 0 }
, m_minIntraDist ( -1 )
, m_lastIntraPOC ( -1 )
, m_adjustNoLPcodingOrder( false )
{
};

Expand Down Expand Up @@ -164,7 +166,7 @@ class GOPCfg
int xGetMaxTid ( const GOPEntryList& gopList ) const;
int xGetMaxRefPics ( const GOPEntry& gopEntry ) const;
int xGetMaxNumReorder ( const GOPEntry& gopEntry, const GOPEntryList& gopList ) const;

void xAdjustNoLPcodingOrder( GOPEntry& gopEntry, const int orgGopId ) const;
};

} // namespace vvenc
Expand Down
2 changes: 2 additions & 0 deletions source/Lib/apputils/VVEncAppCfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,12 +230,14 @@ const std::vector<SVPair<vvencDecodingRefreshType>> DecodingRefreshTypeToEnumMap
{ "rpsei", VVENC_DRT_RECOVERY_POINT_SEI },
{ "idr2", VVENC_DRT_IDR2 }, //deprecated
{ "cra_cre", VVENC_DRT_CRA_CRE },
{ "idr_no_radl", VVENC_DRT_IDR_NO_RADL },
{ "0", VVENC_DRT_NONE },
{ "1", VVENC_DRT_CRA },
{ "2", VVENC_DRT_IDR },
{ "3", VVENC_DRT_RECOVERY_POINT_SEI },
{ "4", VVENC_DRT_IDR2 }, //deprecated
{ "5", VVENC_DRT_CRA_CRE },
{ "6", VVENC_DRT_IDR_NO_RADL },
};

const std::vector<SVPair<BitDepthAndColorSpace>> BitColorSpaceToIntMap =
Expand Down
8 changes: 5 additions & 3 deletions source/Lib/vvenc/vvencCfg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ static inline std::string vvenc_getDecodingRefreshTypeStr( int type, bool poc0i
case 3: cType = "RecPointSEI"; break;
case 4: cType = "IDR2 (deprecated)"; break; //deprecated
case 5: cType = "CRA_CRE (CRA with constrained encoding for RASL pictures)"; break;
case 6: cType = "IDR_NO_RADL"; break;
default: cType = "unknown"; break;
}
if( poc0idr ) cType += " with POC 0 IDR";
Expand Down Expand Up @@ -1277,11 +1278,11 @@ VVENC_DECL bool vvenc_init_config_parameter( vvenc_config *c )

if( c->m_rprEnabledFlag == -1 )
{
c->m_rprEnabledFlag = c->m_DecodingRefreshType == VVENC_DRT_CRA_CRE ? 2 : 0;
c->m_rprEnabledFlag = ( c->m_DecodingRefreshType == VVENC_DRT_CRA_CRE || c->m_DecodingRefreshType == VVENC_DRT_IDR_NO_RADL ) ? 2 : 0;
}

vvenc_confirmParameter( c, c->m_rprEnabledFlag < -1 || c->m_rprEnabledFlag > 2, "RPR must be either -1, 0, 1 or 2" );
vvenc_confirmParameter( c, c->m_rprEnabledFlag == 2 && c->m_DecodingRefreshType != VVENC_DRT_CRA_CRE, "for using RPR=2 constrained rasl encoding, DecodingRefreshType has to be set to VVENC_DRT_CRA_CRE" );
vvenc_confirmParameter( c, c->m_rprEnabledFlag == 2 && !( c->m_DecodingRefreshType == VVENC_DRT_CRA_CRE || c->m_DecodingRefreshType == VVENC_DRT_IDR_NO_RADL ), "for using RPR=2 constrained rasl encoding, DecodingRefreshType has to be set to VVENC_DRT_CRA_CRE or VVENC_DRT_IDR_NO_RADL" );

if( c->m_rprEnabledFlag == 2 )
{
Expand Down Expand Up @@ -1907,7 +1908,8 @@ static bool checkCfgParameter( vvenc_config *c )
vvenc_confirmParameter( c, c->m_log2SaoOffsetScale[0] > (c->m_internalBitDepth[0 ]<10?0:(c->m_internalBitDepth[0 ]-10)), "SaoLumaOffsetBitShift must be in the range of 0 to InternalBitDepth-10, inclusive");
vvenc_confirmParameter( c, c->m_log2SaoOffsetScale[1] > (c->m_internalBitDepth[1]<10?0:(c->m_internalBitDepth[1]-10)), "SaoChromaOffsetBitShift must be in the range of 0 to InternalBitDepthC-10, inclusive");

vvenc_confirmParameter( c, c->m_DecodingRefreshType < 0 || c->m_DecodingRefreshType > 5, "Decoding refresh type must be comprised between 0 and 5 included" );
vvenc_confirmParameter( c, c->m_DecodingRefreshType < 0 || c->m_DecodingRefreshType > 6, "Decoding refresh type must be comprised between 0 and 6 included" );
vvenc_confirmParameter( c, c->m_DecodingRefreshType == 6 && !c->m_poc0idr, "Decoding refresh type VVENC_DRT_IDR_NO_RADL without POC0IDR not supported" );
vvenc_confirmParameter( c, c->m_picReordering && (c->m_DecodingRefreshType == VVENC_DRT_NONE || c->m_DecodingRefreshType == VVENC_DRT_RECOVERY_POINT_SEI), "Decoding refresh type Recovery Point SEI for non low delay not supported" );
vvenc_confirmParameter( c, ! c->m_picReordering && c->m_DecodingRefreshType != VVENC_DRT_NONE, "Only decoding refresh type none for low delay supported" );

Expand Down
6 changes: 3 additions & 3 deletions test/vvenclibtest/vvenclibtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,10 @@ int testLibParameterRanges()
fillEncoderParameters( vvencParams, false );

testParamList( "DecodingRefreshType", vvencParams.m_DecodingRefreshType, vvencParams, { 1, 2, 4, 5 } );
testParamList( "DecodingRefreshType", vvencParams.m_DecodingRefreshType, vvencParams, { -1,0,3,6 }, true );
testParamList( "DecodingRefreshType", vvencParams.m_DecodingRefreshType, vvencParams, { -1,0,3,6,7 }, true );
vvencParams.m_poc0idr = true;
testParamList( "DecodingRefreshType", vvencParams.m_DecodingRefreshType, vvencParams, { 1, 2, 5 } );
testParamList( "DecodingRefreshType", vvencParams.m_DecodingRefreshType, vvencParams, { -1,0,3,4,6 }, true );
testParamList( "DecodingRefreshType", vvencParams.m_DecodingRefreshType, vvencParams, { 1, 2, 5, 6 } );
testParamList( "DecodingRefreshType", vvencParams.m_DecodingRefreshType, vvencParams, { -1,0,3,4,7 }, true );
vvencParams.m_poc0idr = false;

testParamList( "Level", vvencParams.m_level, vvencParams, { 32,35,48,51,64,67,80,83,86,96,99,102 } );
Expand Down

0 comments on commit b94f415

Please sign in to comment.