// Function will arrange the long-term pictures in the decreasing order of poc_lsb_lt, // and among the pictures with the same lsb, it arranges them in increasing delta_poc_msb_cycle_lt value void DPB::arrangeLongtermPicturesInRPS(TComSlice *slice) { TComReferencePictureSet *rps = slice->getRPS(); if (!rps->getNumberOfLongtermPictures()) { return; } // Arrange long-term reference pictures in the correct order of LSB and MSB, // and assign values for pocLSBLT and MSB present flag int longtermPicsPoc[MAX_NUM_REF_PICS], longtermPicsLSB[MAX_NUM_REF_PICS], indices[MAX_NUM_REF_PICS]; int longtermPicsMSB[MAX_NUM_REF_PICS]; bool mSBPresentFlag[MAX_NUM_REF_PICS]; ::memset(longtermPicsPoc, 0, sizeof(longtermPicsPoc)); // Store POC values of LTRP ::memset(longtermPicsLSB, 0, sizeof(longtermPicsLSB)); // Store POC LSB values of LTRP ::memset(longtermPicsMSB, 0, sizeof(longtermPicsMSB)); // Store POC LSB values of LTRP ::memset(indices, 0, sizeof(indices)); // Indices to aid in tracking sorted LTRPs ::memset(mSBPresentFlag, 0, sizeof(mSBPresentFlag)); // Indicate if MSB needs to be present // Get the long-term reference pictures int offset = rps->getNumberOfNegativePictures() + rps->getNumberOfPositivePictures(); int i, ctr = 0; int maxPicOrderCntLSB = 1 << slice->getSPS()->getBitsForPOC(); for (i = rps->getNumberOfPictures() - 1; i >= offset; i--, ctr++) { longtermPicsPoc[ctr] = rps->getPOC(i); // LTRP POC longtermPicsLSB[ctr] = getLSB(longtermPicsPoc[ctr], maxPicOrderCntLSB); // LTRP POC LSB indices[ctr] = i; longtermPicsMSB[ctr] = longtermPicsPoc[ctr] - longtermPicsLSB[ctr]; } int numLongPics = rps->getNumberOfLongtermPictures(); assert(ctr == numLongPics); // Arrange pictures in decreasing order of MSB; for (i = 0; i < numLongPics; i++) { for (int j = 0; j < numLongPics - 1; j++) { if (longtermPicsMSB[j] < longtermPicsMSB[j + 1]) { std::swap(longtermPicsPoc[j], longtermPicsPoc[j + 1]); std::swap(longtermPicsLSB[j], longtermPicsLSB[j + 1]); std::swap(longtermPicsMSB[j], longtermPicsMSB[j + 1]); std::swap(indices[j], indices[j + 1]); } } } for (i = 0; i < numLongPics; i++) { // Check if MSB present flag should be enabled. // Check if the buffer contains any pictures that have the same LSB. TComPic* iterPic = m_picList.first(); while (iterPic) { if ((getLSB(iterPic->getPOC(), maxPicOrderCntLSB) == longtermPicsLSB[i]) && // Same LSB (iterPic->getSlice()->isReferenced()) && // Reference picture (iterPic->getPOC() != longtermPicsPoc[i])) // Not the LTRP itself { mSBPresentFlag[i] = true; break; } iterPic = iterPic->m_next; } } // tempArray for usedByCurr flag bool tempArray[MAX_NUM_REF_PICS]; ::memset(tempArray, 0, sizeof(tempArray)); for (i = 0; i < numLongPics; i++) { tempArray[i] = rps->getUsed(indices[i]) ? true : false; } // Now write the final values; ctr = 0; int currMSB = 0, currLSB = 0; // currPicPoc = currMSB + currLSB currLSB = getLSB(slice->getPOC(), maxPicOrderCntLSB); currMSB = slice->getPOC() - currLSB; for (i = rps->getNumberOfPictures() - 1; i >= offset; i--, ctr++) { rps->setPOC(i, longtermPicsPoc[ctr]); rps->setDeltaPOC(i, -slice->getPOC() + longtermPicsPoc[ctr]); rps->setUsed(i, tempArray[ctr]); rps->setPocLSBLT(i, longtermPicsLSB[ctr]); rps->setDeltaPocMSBCycleLT(i, (currMSB - (longtermPicsPoc[ctr] - longtermPicsLSB[ctr])) / maxPicOrderCntLSB); rps->setDeltaPocMSBPresentFlag(i, mSBPresentFlag[ctr]); assert(rps->getDeltaPocMSBCycleLT(i) >= 0); // Non-negative value } for (i = rps->getNumberOfPictures() - 1, ctr = 1; i >= offset; i--, ctr++) { for (int j = rps->getNumberOfPictures() - 1 - ctr; j >= offset; j--) { // Here at the encoder we know that we have set the full POC value for the LTRPs, hence we // don't have to check the MSB present flag values for this constraint. assert(rps->getPOC(i) != rps->getPOC(j)); // If assert fails, LTRP entry repeated in RPS!!! } } }
//Function for initializing m_RPSList, a list of TComReferencePictureSet, based on the GOPEntry objects read from the config file. Void TEncTop::xInitRPS(Bool isFieldCoding) { TComReferencePictureSet* rps; m_cSPS.createRPSList(getGOPSize() + m_extraRPSs + 1); TComRPSList* rpsList = m_cSPS.getRPSList(); for( Int i = 0; i < getGOPSize()+m_extraRPSs; i++) { GOPEntry ge = getGOPEntry(i); rps = rpsList->getReferencePictureSet(i); rps->setNumberOfPictures(ge.m_numRefPics); rps->setNumRefIdc(ge.m_numRefIdc); Int numNeg = 0; Int numPos = 0; for( Int j = 0; j < ge.m_numRefPics; j++) { rps->setDeltaPOC(j,ge.m_referencePics[j]); rps->setUsed(j,ge.m_usedByCurrPic[j]); if(ge.m_referencePics[j]>0) { numPos++; } else { numNeg++; } } rps->setNumberOfNegativePictures(numNeg); rps->setNumberOfPositivePictures(numPos); // handle inter RPS intialization from the config file. rps->setInterRPSPrediction(ge.m_interRPSPrediction > 0); // not very clean, converting anything > 0 to true. rps->setDeltaRIdxMinus1(0); // index to the Reference RPS is always the previous one. TComReferencePictureSet* RPSRef = i>0 ? rpsList->getReferencePictureSet(i-1): NULL; // get the reference RPS if (ge.m_interRPSPrediction == 2) // Automatic generation of the inter RPS idc based on the RIdx provided. { assert (RPSRef!=NULL); Int deltaRPS = getGOPEntry(i-1).m_POC - ge.m_POC; // the ref POC - current POC Int numRefDeltaPOC = RPSRef->getNumberOfPictures(); rps->setDeltaRPS(deltaRPS); // set delta RPS rps->setNumRefIdc(numRefDeltaPOC+1); // set the numRefIdc to the number of pictures in the reference RPS + 1. Int count=0; for (Int j = 0; j <= numRefDeltaPOC; j++ ) // cycle through pics in reference RPS. { Int RefDeltaPOC = (j<numRefDeltaPOC)? RPSRef->getDeltaPOC(j): 0; // if it is the last decoded picture, set RefDeltaPOC = 0 rps->setRefIdc(j, 0); for (Int k = 0; k < rps->getNumberOfPictures(); k++ ) // cycle through pics in current RPS. { if (rps->getDeltaPOC(k) == ( RefDeltaPOC + deltaRPS)) // if the current RPS has a same picture as the reference RPS. { rps->setRefIdc(j, (rps->getUsed(k)?1:2)); count++; break; } } } if (count != rps->getNumberOfPictures()) { printf("Warning: Unable fully predict all delta POCs using the reference RPS index given in the config file. Setting Inter RPS to false for this RPS.\n"); rps->setInterRPSPrediction(0); } } else if (ge.m_interRPSPrediction == 1) // inter RPS idc based on the RefIdc values provided in config file. { assert (RPSRef!=NULL); rps->setDeltaRPS(ge.m_deltaRPS); rps->setNumRefIdc(ge.m_numRefIdc); for (Int j = 0; j < ge.m_numRefIdc; j++ ) { rps->setRefIdc(j, ge.m_refIdc[j]); } #if WRITE_BACK // the following code overwrite the deltaPOC and Used by current values read from the config file with the ones // computed from the RefIdc. A warning is printed if they are not identical. numNeg = 0; numPos = 0; TComReferencePictureSet RPSTemp; // temporary variable for (Int j = 0; j < ge.m_numRefIdc; j++ ) { if (ge.m_refIdc[j]) { Int deltaPOC = ge.m_deltaRPS + ((j < RPSRef->getNumberOfPictures())? RPSRef->getDeltaPOC(j) : 0); RPSTemp.setDeltaPOC((numNeg+numPos),deltaPOC); RPSTemp.setUsed((numNeg+numPos),ge.m_refIdc[j]==1?1:0); if (deltaPOC<0) { numNeg++; } else { numPos++; } } } if (numNeg != rps->getNumberOfNegativePictures()) { printf("Warning: number of negative pictures in RPS is different between intra and inter RPS specified in the config file.\n"); rps->setNumberOfNegativePictures(numNeg); rps->setNumberOfPictures(numNeg+numPos); } if (numPos != rps->getNumberOfPositivePictures()) { printf("Warning: number of positive pictures in RPS is different between intra and inter RPS specified in the config file.\n"); rps->setNumberOfPositivePictures(numPos); rps->setNumberOfPictures(numNeg+numPos); } RPSTemp.setNumberOfPictures(numNeg+numPos); RPSTemp.setNumberOfNegativePictures(numNeg); RPSTemp.sortDeltaPOC(); // sort the created delta POC before comparing // check if Delta POC and Used are the same // print warning if they are not. for (Int j = 0; j < ge.m_numRefIdc; j++ ) { if (RPSTemp.getDeltaPOC(j) != rps->getDeltaPOC(j)) { printf("Warning: delta POC is different between intra RPS and inter RPS specified in the config file.\n"); rps->setDeltaPOC(j,RPSTemp.getDeltaPOC(j)); } if (RPSTemp.getUsed(j) != rps->getUsed(j)) { printf("Warning: Used by Current in RPS is different between intra and inter RPS specified in the config file.\n"); rps->setUsed(j,RPSTemp.getUsed(j)); } } #endif } } //In case of field coding, we need to set special parameters for the first bottom field of the sequence, since it is not specified in the cfg file. //The position = GOPSize + extraRPSs which is (a priori) unused is reserved for this field in the RPS. if (isFieldCoding) { rps = rpsList->getReferencePictureSet(getGOPSize()+m_extraRPSs); rps->setNumberOfPictures(1); rps->setNumberOfNegativePictures(1); rps->setNumberOfPositivePictures(0); rps->setNumberOfLongtermPictures(0); rps->setDeltaPOC(0,-1); rps->setPOC(0,0); rps->setUsed(0,true); rps->setInterRPSPrediction(false); rps->setDeltaRIdxMinus1(0); rps->setDeltaRPS(0); rps->setNumRefIdc(0); } }