Commit b262c86e authored by Frank Bossen's avatar Frank Bossen

Merge branch 'aps' into 'master'

JVET-M0132: improved APS implementation

See merge request !379
parents f2b029f1 8420ed0d
Pipeline #1088 passed with stage
......@@ -909,6 +909,9 @@ void EncApp::rateStatsAccum(const AccessUnit& au, const std::vector<uint32_t>& a
#endif
case NAL_UNIT_SPS:
case NAL_UNIT_PPS:
#if JVET_M0132_APS
case NAL_UNIT_APS:
#endif
m_essentialBytes += *it_stats;
break;
default:
......@@ -925,7 +928,11 @@ void EncApp::printRateSummary()
msg( DETAILS,"Bytes written to file: %u (%.3f kbps)\n", m_totalBytes, 0.008 * m_totalBytes / time );
if (m_summaryVerboseness > 0)
{
#if JVET_M0132_APS
msg(DETAILS, "Bytes for SPS/PPS/APS/Slice (Incl. Annex B): %u (%.3f kbps)\n", m_essentialBytes, 0.008 * m_essentialBytes / time);
#else
msg( DETAILS,"Bytes for SPS/PPS/Slice (Incl. Annex B): %u (%.3f kbps)\n", m_essentialBytes, 0.008 * m_essentialBytes / time );
#endif
}
}
......
......@@ -221,6 +221,9 @@ const char * NALU_TYPE[] =
#endif
"SPS_NUT",
"PPS_NUT",
#if JVET_M0132
"APS_NUT",
#endif
"AUD_NUT",
"EOS_NUT",
"EOB_NUT",
......
......@@ -174,7 +174,7 @@ void AdaptiveLoopFilter::reconstructCoeff( AlfSliceParam& alfSliceParam, Channel
for( int classIdx = 0; classIdx < numClasses; classIdx++ )
{
int filterIdx = alfSliceParam.filterCoeffDeltaIdx[classIdx];
memcpy( m_coeffFinal + classIdx * MAX_NUM_ALF_LUMA_COEFF, coeff + filterIdx * MAX_NUM_ALF_LUMA_COEFF, sizeof( int16_t ) * numCoeff );
memcpy( m_coeffFinal + classIdx * MAX_NUM_ALF_LUMA_COEFF, coeff + filterIdx * MAX_NUM_ALF_LUMA_COEFF, sizeof( short ) * numCoeff );
}
if( bRedo && alfSliceParam.alfLumaCoeffDeltaPredictionFlag )
......
......@@ -802,6 +802,9 @@ void CodingStructure::initSubStructure( CodingStructure& subStruct, const Channe
subStruct.vps = vps;
#endif
subStruct.pps = pps;
#if JVET_M0132_APS
subStruct.aps = aps;
#endif
subStruct.slice = slice;
subStruct.baseQP = baseQP;
subStruct.prevQP[_chType]
......
......@@ -101,6 +101,9 @@ public:
bool isLossless;
const SPS *sps;
const PPS *pps;
#if JVET_M0132_APS
APS * aps;
#endif
#if HEVC_VPS
const VPS *vps;
#endif
......
......@@ -192,6 +192,9 @@ static const int C2FLAG_NUMBER = 1; ///< maxi
static const int MAX_NUM_VPS = 16;
static const int MAX_NUM_SPS = 16;
static const int MAX_NUM_PPS = 64;
#if JVET_M0132_APS
static const int MAX_NUM_APS = 32; //Currently APS ID has 5 bits
#endif
static const int MLS_GRP_NUM = 1024; ///< Max number of coefficient groups, max(16, 256)
......
......@@ -881,7 +881,11 @@ const CPelUnitBuf Picture::getRecoBuf(const UnitArea &unit) const { return g
PelUnitBuf Picture::getRecoBuf() { return M_BUFS(scheduler.getSplitPicId(), PIC_RECONSTRUCTION); }
const CPelUnitBuf Picture::getRecoBuf() const { return M_BUFS(scheduler.getSplitPicId(), PIC_RECONSTRUCTION); }
#if JVET_M0132_APS
void Picture::finalInit(const SPS& sps, const PPS& pps, APS& aps)
#else
void Picture::finalInit( const SPS& sps, const PPS& pps )
#endif
{
for( auto &sei : SEIs )
{
......@@ -917,6 +921,9 @@ void Picture::finalInit( const SPS& sps, const PPS& pps )
cs->picture = this;
cs->slice = nullptr; // the slices for this picture have not been set at this point. update cs->slice after swapSliceObject()
cs->pps = &pps;
#if JVET_M0132_APS
cs->aps = &aps;
#endif
#if HEVC_VPS
cs->vps = nullptr;
#endif
......@@ -939,6 +946,9 @@ void Picture::allocateNewSlice()
slices.push_back(new Slice);
Slice& slice = *slices.back();
#if JVET_M0132_APS
slice.setAPS(cs->aps);
#endif
slice.setPPS( cs->pps);
slice.setSPS( cs->sps);
if(slices.size()>=2)
......@@ -952,11 +962,17 @@ Slice *Picture::swapSliceObject(Slice * p, uint32_t i)
{
p->setSPS(cs->sps);
p->setPPS(cs->pps);
#if JVET_M0132_APS
p->setAPS(cs->aps);
#endif
Slice * pTmp = slices[i];
slices[i] = p;
pTmp->setSPS(0);
pTmp->setPPS(0);
#if JVET_M0132_APS
pTmp->setAPS(0);
#endif
return pTmp;
}
......
......@@ -233,7 +233,11 @@ struct Picture : public UnitArea
const CPelUnitBuf getBuf(const UnitArea &unit, const PictureType &type) const;
void extendPicBorder();
#if JVET_M0132_APS
void finalInit(const SPS& sps, const PPS& pps, APS& aps);
#else
void finalInit( const SPS& sps, const PPS& pps );
#endif
int getPOC() const { return poc; }
void setBorderExtension( bool bFlag) { m_bIsBorderExtended = bFlag;}
......
......@@ -86,6 +86,9 @@ const char* nalUnitTypeToString(NalUnitType type)
#endif
case NAL_UNIT_SPS: return "SPS";
case NAL_UNIT_PPS: return "PPS";
#if JVET_M0132_APS
case NAL_UNIT_APS: return "APS";
#endif
case NAL_UNIT_ACCESS_UNIT_DELIMITER: return "AUD";
case NAL_UNIT_EOS: return "EOS";
case NAL_UNIT_EOB: return "EOB";
......
......@@ -138,6 +138,10 @@ Slice::Slice()
, m_uiMaxBTSizeIChroma ( 0 )
, m_uiMaxTTSizeIChroma ( 0 )
, m_uiMaxBTSize ( 0 )
#if JVET_M0132_APS
, m_apsId ( -1 )
, m_aps (NULL)
#endif
{
for(uint32_t i=0; i<NUM_REF_PIC_LIST_01; i++)
{
......@@ -1940,6 +1944,16 @@ PPS::~PPS()
delete pcv;
}
#if JVET_M0132_APS
APS::APS()
: m_APSId(0)
{
}
APS::~APS()
{
}
#endif
ReferencePictureSet::ReferencePictureSet()
: m_numberOfPictures (0)
, m_numberOfNegativePictures (0)
......@@ -2418,6 +2432,9 @@ ParameterSetManager::ParameterSetManager()
: m_spsMap(MAX_NUM_SPS)
#endif
, m_ppsMap(MAX_NUM_PPS)
#if JVET_M0132_APS
, m_apsMap(MAX_NUM_APS)
#endif
#if HEVC_VPS
, m_activeVPSId(-1)
#endif
......@@ -2528,6 +2545,28 @@ bool ParameterSetManager::activatePPS(int ppsId, bool isIRAP)
return false;
}
#if JVET_M0132_APS
bool ParameterSetManager::activateAPS(int apsId)
{
APS *aps = m_apsMap.getPS(apsId);
if (aps)
{
m_apsMap.setActive(apsId);
return true;
}
else
{
msg(WARNING, "Warning: tried to activate non-existing APS.");
}
return false;
}
template <>
void ParameterSetMap<APS>::setID(APS* parameterSet, const int psId)
{
parameterSet->setAPSId(psId);
}
#endif
template <>
void ParameterSetMap<PPS>::setID(PPS* parameterSet, const int psId)
{
......@@ -2653,6 +2692,13 @@ void xTracePPSHeader()
DTRACE( g_trace_ctx, D_HEADER, "=========== Picture Parameter Set ===========\n" );
}
#if JVET_M0132_APS
void xTraceAPSHeader()
{
DTRACE(g_trace_ctx, D_HEADER, "=========== Adaptation Parameter Set ===========\n");
}
#endif
void xTraceSliceHeader()
{
DTRACE( g_trace_ctx, D_HEADER, "=========== Slice ===========\n" );
......
......@@ -1581,6 +1581,24 @@ public:
PPSRExt& getPpsRangeExtension() { return m_ppsRangeExtension; }
};
#if JVET_M0132_APS
class APS
{
private:
int m_APSId; // adaptation_parameter_set_id
AlfSliceParam m_alfAPSParam;
public:
APS();
virtual ~APS();
int getAPSId() const { return m_APSId; }
void setAPSId(int i) { m_APSId = i; }
void setAlfAPSParam(AlfSliceParam& alfAPSParam) { m_alfAPSParam = alfAPSParam; }
const AlfSliceParam& getAlfAPSParam() const { return m_alfAPSParam; }
};
#endif
struct WPScalingParam
{
// Explicit weighted prediction parameters parsed in slice header,
......@@ -1737,7 +1755,15 @@ private:
uint32_t m_uiMaxTTSizeIChroma;
uint32_t m_uiMaxBTSize;
#if JVET_M0132_APS
int m_apsId;
APS* m_aps;
#endif
#if !JVET_M0132_APS
AlfSliceParam m_alfSliceParam;
#else
bool m_tileGroupAlfEnabledFlag;
#endif
#if JVET_M0427_INLOOP_RESHAPER
SliceReshapeInfo m_sliceReshapeInfo;
#endif
......@@ -1758,6 +1784,12 @@ public:
void setPPSId( int PPSId ) { m_iPPSId = PPSId; }
int getPPSId() const { return m_iPPSId; }
#if JVET_M0132_APS
void setAPS(APS* aps) { m_aps = aps; m_apsId = (aps) ? aps->getAPSId() : -1; }
APS* getAPS() { return m_aps; }
void setAPSId(int apsId) { m_apsId = apsId; }
int getAPSId() const { return m_apsId; }
#endif
void setPicOutputFlag( bool b ) { m_PicOutputFlag = b; }
bool getPicOutputFlag() const { return m_PicOutputFlag; }
void setSaoEnabledFlag(ChannelType chType, bool s) {m_saoEnabledFlag[chType] =s; }
......@@ -2017,8 +2049,13 @@ public:
void resetProcessingTime() { m_dProcessingTime = m_iProcessingStartTime = 0; }
double getProcessingTime() const { return m_dProcessingTime; }
#if !JVET_M0132_APS
void setAlfSliceParam( AlfSliceParam& alfSliceParam ) { m_alfSliceParam = alfSliceParam; }
AlfSliceParam& getAlfSliceParam() { return m_alfSliceParam; }
#else
bool getTileGroupAlfEnabledFlag() const { return m_tileGroupAlfEnabledFlag; }
void setTileGroupAlfEnabledFlag(bool b) { m_tileGroupAlfEnabledFlag = b; }
#endif
#if JVET_M0427_INLOOP_RESHAPER
const SliceReshapeInfo& getReshapeInfo() const { return m_sliceReshapeInfo; }
......@@ -2215,6 +2252,14 @@ public:
//! \returns true, if activation is successful
bool activatePPS(int ppsId, bool isIRAP);
#if JVET_M0132_APS
void storeAPS(APS *aps, const std::vector<uint8_t> &naluData) { m_apsMap.storePS(aps->getAPSId(), aps, &naluData); };
APS* getAPS(int apsId) { return m_apsMap.getPS(apsId); };
bool getAPSChangedFlag(int apsId) const { return m_apsMap.getChangedFlag(apsId); }
void clearAPSChangedFlag(int apsId) { m_apsMap.clearChangedFlag(apsId); }
APS* getFirstAPS() { return m_apsMap.getFirstPS(); };
bool activateAPS(int apsId);
#endif
#if HEVC_VPS
const VPS* getActiveVPS()const { return m_vpsMap.getPS(m_activeVPSId); };
#endif
......@@ -2226,6 +2271,9 @@ protected:
#endif
ParameterSetMap<SPS> m_spsMap;
ParameterSetMap<PPS> m_ppsMap;
#if JVET_M0132_APS
ParameterSetMap<APS> m_apsMap;
#endif
#if HEVC_VPS
int m_activeVPSId; // -1 for nothing active
......@@ -2320,6 +2368,9 @@ void xTraceVPSHeader();
#endif
void xTraceSPSHeader();
void xTracePPSHeader();
#if JVET_M0132_APS
void xTraceAPSHeader();
#endif
void xTraceSliceHeader();
void xTraceAccessUnitDelimiter();
#endif
......
......@@ -278,6 +278,8 @@ typedef std::pair<int, int> TrCost;
#endif
#endif
#define JVET_M0132_APS 1 // APS
#define KEEP_PRED_AND_RESI_SIGNALS 0
......@@ -978,6 +980,9 @@ enum NalUnitType
#endif
NAL_UNIT_SPS, // 33
NAL_UNIT_PPS, // 34
#if JVET_M0132_APS
NAL_UNIT_APS, //NAL unit type number needs to be reaaranged.
#endif
NAL_UNIT_ACCESS_UNIT_DELIMITER, // 35
NAL_UNIT_EOS, // 36
NAL_UNIT_EOB, // 37
......@@ -1641,6 +1646,11 @@ struct AlfSliceParam
bool alfLumaCoeffDeltaPredictionFlag; // alf_luma_coeff_delta_prediction_flag
std::vector<AlfFilterShape>* filterShapes;
AlfSliceParam()
{
reset();
}
void reset()
{
std::memset( enabledFlag, false, sizeof( enabledFlag ) );
......
......@@ -143,10 +143,16 @@ bool CABACReader::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i
sao( cs, ctuRsAddr );
#if !JVET_M0132_APS
AlfSliceParam& alfSliceParam = cs.slice->getAlfSliceParam();
if( cs.sps->getALFEnabledFlag() && ( alfSliceParam.enabledFlag[COMPONENT_Y] || alfSliceParam.enabledFlag[COMPONENT_Cb] || alfSliceParam.enabledFlag[COMPONENT_Cr] ) )
if (cs.sps->getALFEnabledFlag() && (alfSliceParam.enabledFlag[COMPONENT_Y] || alfSliceParam.enabledFlag[COMPONENT_Cb] || alfSliceParam.enabledFlag[COMPONENT_Cr]))
{
#else
if (cs.sps->getALFEnabledFlag() && (cs.slice->getTileGroupAlfEnabledFlag()))
{
CHECK(cs.aps == nullptr, "APS not initialized");
const AlfSliceParam& alfSliceParam = cs.aps->getAlfAPSParam();
#endif
const PreCalcValues& pcv = *cs.pcv;
int frame_width_in_ctus = pcv.widthInCtus;
......
......@@ -220,7 +220,13 @@ bool tryDecodePicture( Picture* pcEncPic, const int expectedPoc, const std::stri
for( int i = 0; i < pic->slices.size(); i++ )
{
#if JVET_M0132_APS
pcEncPic->slices[i]->setAPSId(pic->slices[i]->getAPSId());
pcEncPic->slices[i]->setAPS( pic->slices[i]->getAPS());
pcEncPic->slices[i]->setTileGroupAlfEnabledFlag( pic->slices[i]->getTileGroupAlfEnabledFlag());
#else
pcEncPic->slices[i]->getAlfSliceParam() = pic->slices[i]->getAlfSliceParam();
#endif
}
}
......@@ -581,7 +587,20 @@ void DecLib::executeLoopFilters()
if( cs.sps->getALFEnabledFlag() )
{
#if JVET_M0132_APS
if (cs.slice->getTileGroupAlfEnabledFlag())
{
// ALF decodes the differentially coded coefficients and stores them in the parameters structure.
// Code could be restructured to do directly after parsing. So far we just pass a fresh non-const
// copy in case the APS gets used more than once.
AlfSliceParam alfParamCopy = cs.aps->getAlfAPSParam();
m_cALF.ALFProcess(cs, alfParamCopy);
}
#else
m_cALF.ALFProcess( cs, cs.slice->getAlfSliceParam() );
#endif
}
}
......@@ -738,6 +757,13 @@ void DecLib::xActivateParameterSets()
{
if (m_bFirstSliceInPicture)
{
#if JVET_M0132_APS
APS *aps = m_parameterSetManager.getAPS(m_apcSlicePilot->getAPSId()); // this is a temporary APS object. Do not store this value
if (m_apcSlicePilot->getAPSId() != -1)
{
CHECK(aps == 0, "No APS present");
}
#endif
const PPS *pps = m_parameterSetManager.getPPS(m_apcSlicePilot->getPPSId()); // this is a temporary PPS object. Do not store this value
CHECK(pps == 0, "No PPS present");
......@@ -756,6 +782,17 @@ void DecLib::xActivateParameterSets()
THROW("Parameter set activation failed!");
}
#if JVET_M0132_APS
if (aps)
{
m_parameterSetManager.clearAPSChangedFlag(aps->getAPSId());
if (false == m_parameterSetManager.activateAPS(m_apcSlicePilot->getAPSId()))
{
THROW("APS activation failed!");
}
}
#endif
xParsePrefixSEImessages();
#if RExt__HIGH_BIT_DEPTH_SUPPORT==0
......@@ -770,7 +807,11 @@ void DecLib::xActivateParameterSets()
m_apcSlicePilot->applyReferencePictureSet(m_cListPic, m_apcSlicePilot->getRPS());
#if JVET_M0132_APS
m_pcPic->finalInit(*sps, *pps, *aps);
#else
m_pcPic->finalInit( *sps, *pps );
#endif
m_pcPic->createTempBuffers( m_pcPic->cs->pps->pcv->maxCUWidth );
m_pcPic->cs->createCoeffs();
......@@ -784,6 +825,9 @@ void DecLib::xActivateParameterSets()
Slice *pSlice = m_pcPic->slices[m_uiSliceSegmentIdx];
// Update the PPS and SPS pointers with the ones of the picture.
#if JVET_M0132_APS
aps= pSlice->getAPS();
#endif
pps=pSlice->getPPS();
sps=pSlice->getSPS();
......@@ -791,6 +835,9 @@ void DecLib::xActivateParameterSets()
m_pcPic->cs->slice = pSlice;
m_pcPic->cs->sps = sps;
m_pcPic->cs->pps = pps;
#if JVET_M0132_APS
m_pcPic->cs->aps = aps;
#endif
#if HEVC_VPS
m_pcPic->cs->vps = pSlice->getVPS();
#endif
......@@ -866,11 +913,16 @@ void DecLib::xActivateParameterSets()
const SPS *sps = pSlice->getSPS();
const PPS *pps = pSlice->getPPS();
#if JVET_M0132_APS
APS *aps = pSlice->getAPS();
#endif
// fix Parameter Sets, now that we have the real slice
m_pcPic->cs->slice = pSlice;
m_pcPic->cs->sps = sps;
m_pcPic->cs->pps = pps;
#if JVET_M0132_APS
m_pcPic->cs->aps = aps;
#endif
#if HEVC_VPS
m_pcPic->cs->vps = pSlice->getVPS();
#endif
......@@ -885,6 +937,12 @@ void DecLib::xActivateParameterSets()
{
EXIT("Error - a new PPS has been decoded while processing a picture");
}
#if JVET_M0132_APS
if (aps && m_parameterSetManager.getAPSChangedFlag(aps->getAPSId()))
{
EXIT("Error - a new APS has been decoded while processing a picture");
}
#endif
xParsePrefixSEImessages();
......@@ -1049,6 +1107,13 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl
int iMaxPOClsb = 1 << sps->getBitsForPOC();
m_apcSlicePilot->setPOC( m_apcSlicePilot->getPOC() & (iMaxPOClsb - 1) );
xUpdatePreviousTid0POC(m_apcSlicePilot);
#if JVET_M0132_APS
if (m_apcSlicePilot->getAPSId() != -1)
{
APS *aps = m_parameterSetManager.getAPS(m_apcSlicePilot->getAPSId());
CHECK(aps == 0, "No APS present");
}
#endif
}
// Skip pictures due to random access
......@@ -1403,6 +1468,15 @@ void DecLib::xDecodePPS( InputNALUnit& nalu )
m_parameterSetManager.storePPS( pps, nalu.getBitstream().getFifo() );
}
#if JVET_M0132_APS
void DecLib::xDecodeAPS(InputNALUnit& nalu)
{
APS* aps = new APS();
m_HLSReader.setBitstream(&nalu.getBitstream());
m_HLSReader.parseAPS(aps);
m_parameterSetManager.storeAPS(aps, nalu.getBitstream().getFifo());
}
#endif
bool DecLib::decode(InputNALUnit& nalu, int& iSkipFrame, int& iPOCLastDisplay)
{
bool ret;
......@@ -1428,6 +1502,11 @@ bool DecLib::decode(InputNALUnit& nalu, int& iSkipFrame, int& iPOCLastDisplay)
case NAL_UNIT_PPS:
xDecodePPS( nalu );
return false;
#if JVET_M0132_APS
case NAL_UNIT_APS:
xDecodeAPS(nalu);
return false;
#endif
case NAL_UNIT_PREFIX_SEI:
// Buffer up prefix SEI messages until SPS of associated VCL is known.
......
......@@ -184,6 +184,9 @@ protected:
#endif
void xDecodeSPS( InputNALUnit& nalu );
void xDecodePPS( InputNALUnit& nalu );
#if JVET_M0132_APS
void xDecodeAPS(InputNALUnit& nalu);
#endif
void xUpdatePreviousTid0POC( Slice *pSlice ) { if ((pSlice->getTLayer()==0) && (pSlice->isReferenceNalu() && (pSlice->getNalUnitType()!=NAL_UNIT_CODED_SLICE_RASL_R)&& (pSlice->getNalUnitType()!=NAL_UNIT_CODED_SLICE_RADL_R))) { m_prevTid0POC=pSlice->getPOC(); } }
void xParsePrefixSEImessages();
void xParsePrefixSEIsForUnknownVCLNal();
......
......@@ -91,6 +91,9 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream )
cs.slice = slice;
cs.sps = sps;
cs.pps = slice->getPPS();
#if JVET_M0132_APS
cs.aps = slice->getAPS();
#endif
#if HEVC_VPS
cs.vps = slice->getVPS();
#endif
......
......@@ -624,6 +624,52 @@ void HLSyntaxReader::parsePPS( PPS* pcPPS )
xReadRbspTrailingBits();
}
#if JVET_M0132_APS
void HLSyntaxReader::parseAPS(APS* aps)
{
#if ENABLE_TRACING
xTraceAPSHeader();
#endif
uint32_t code;
READ_CODE(5, code, "adaptation_parameter_set_id");
aps->setAPSId(code);
AlfSliceParam param = aps->getAlfAPSParam();
param.enabledFlag[COMPONENT_Y] = true;
int alfChromaIdc = truncatedUnaryEqProb(3); //alf_chroma_idc
param.enabledFlag[COMPONENT_Cb] = alfChromaIdc >> 1;
param.enabledFlag[COMPONENT_Cr] = alfChromaIdc & 1;
xReadTruncBinCode(code, MAX_NUM_ALF_CLASSES); //number_of_filters_minus1
param.numLumaFilters = code + 1;
if (param.numLumaFilters > 1)
{
for (int i = 0; i < MAX_NUM_ALF_CLASSES; i++)
{
xReadTruncBinCode(code, param.numLumaFilters);
param.filterCoeffDeltaIdx[i] = code;
}
}
else
{
memset(param.filterCoeffDeltaIdx, 0, sizeof(param.filterCoeffDeltaIdx));
}