HM编码器代码阅读(5)——参考帧的选择

https://blog.csdn.net/NB_vol_1/article/details/51135715


参考帧是怎么来的以及如何设置这个问题困扰了我很久,现在理出了一点头绪。
参考帧的选择主要涉及几个函数:
selectReferencePictureSet
createExplicitReferencePictureSetFromReference
applyReferencePictureSet
arrangeLongtermPicturesInRPS
setRefPicList
setRefPOCList
setList1IdxToList0Idx

主要过程:
1、首选调用selectReferencePictureSet来选择一个参考图像集,参考图像集(最多有有9个),全部放在SPS中,可以根据索引来取得
     (1)默认把当前帧在当前GOP中的相对poc设置为参考图像集的索引
     (2)如果当前帧的poc对I帧周期求余等于m_GOPList(注意这个列表存放的是帧对应的GOP信息,以及参考帧等信息)某个元素的gop
     那么就把这个元素的下标设置为参考图像集的索引!
2、每帧的第一个片中包含一个RPS的信息
3、根据步骤1选中的参考图像集,调用createExplicitReferencePictureSetFromReference 创建本地参考图像集,然后把参考的图像集设置为本地参考图像集
     (1)遍历参考集中所有的帧(参考集只存放这些参考帧的相对poc),在图像列表中找到其对应的帧,然后转往(2)
     (2)把相对poc存放到本地参考图像集的m_deltaPOC中
     (3)在本地参考图像集设置该帧(即参考帧)的被使用的标志(在m_used中)
     (4)如果相对poc小于0,那么统计为前向参考帧;如果相对poc大于0,那么统计为后向参考帧
     (5)把本地参考集设置为参考集
4、根据参考图像集调用applyReferencePictureSet 应用参考图像集,主要是设置里面的帧是否允许被参考,是否允许被当前帧所参考
     (1)对图像列表进行遍历,对于图像列表的每一帧pic,进行下面的操作
     (2)遍历参考集中的前向和后向参考帧(前向和后向参考帧的poc都是相对poc),如果pic在参考集中,那么设置pic的被参考标志
     (3)遍历参考集中其他参考帧(即长期参考帧),如果pic在参考集中,那么设置pic被参考的标志
     (4)保证pic所在的时域层比当前帧的时域层小
5、排列参考图像集中的帧,arrangeLongtermPicturesInRPS,主要是对长期参考帧进行排序,并设置相应的标志信息的过程
     (1)在参考图像集中先存放前向参考帧,然后存放后向参考帧,再放长期参考帧
     (2)MSB和LSB分别表示最高有效位和最低有效位,按照MSB从大到小排序长期参考帧
     (3)记录长期参考帧MSB出现的标志
     (4)记录长期参考帧被当前帧使用的情况
     (5)记录长期参考帧的各种信息(即上面出现的标志,使用情况等)
     (6)确保长期参考帧不会重复
6、调用 setRefPicList来设置参考图像列表(m_apcRefPicList),根据参考图像集设置list0和list1
     (1)m_aiNumRefIdx记录两个参考列表的元素个数
     (2)遍历参考集中的每一个前向参考帧,根据相对poc取得真实的帧的指针,然后放入临时的list0中
     (3)遍历每一个后向参考帧,把真实的帧的指针放入临时的list1中
     (4)遍历每一个长期参考帧,把真实的帧的指针放入临时的list中
     (5)按照前向、后向、长期的顺序,把这些参考帧都放进list0和list1中!(list0和list都放了前向和后向、长期参考帧;如果不是B帧,不需要list1)
7、调用setRefPOCList函数,设置m_aiRefPOCList
     (1)m_apcRefPicList中存放的是帧的指针,而m_aiRefPOCList中存放的是帧的poc
     (2)同样m_aiRefPOCList也是列表数组,m_aiRefPOCList[0]表示list0,m_aiRefPOCList[1]表示list1
8、调用setList1IdxToList0Idx,设置list0到list1的映射,根据poc相等来判断。


  
  
  1. // 为当前帧选择一个参考图像集
  2. // 额外的参考图像集有9个
  3. Void TEncTop::selectReferencePictureSet(TComSlice* slice, Int POCCurr, Int GOPid )
  4. {
  5. // GOPid是该帧在GOP中的相对poc
  6. // POCCurr是该帧的绝对poc
  7. slice->setRPSidx(GOPid); // 设置默认的参考集的索引
  8. // 对于额外的RPS
  9. for(Int extraNum=m_iGOPSize; extraNum<m_extraRPSs+m_iGOPSize; extraNum++)
  10. {
  11. // 如果I帧的周期大于0
  12. if(m_uiIntraPeriod > 0 && getDecodingRefreshType() > 0)
  13. {
  14. // 当前帧的poc(这个poc是绝对的poc)对IntraPeriod求余(求余之后就是IntraPeriod周期内的相对poc)
  15. Int POCIndex = POCCurr%m_uiIntraPeriod;
  16. if(POCIndex == 0)
  17. {
  18. POCIndex = m_uiIntraPeriod;
  19. }
  20. if(POCIndex == m_GOPList[extraNum].m_POC)
  21. {
  22. slice->setRPSidx(extraNum); // 如果IntraPeriod周期内的相对poc刚好等于额外参考集的poc,那么就把这个额外的参考集选为参考集
  23. }
  24. }
  25. else
  26. {
  27. if(POCCurr==m_GOPList[extraNum].m_POC)
  28. {
  29. slice->setRPSidx(extraNum);
  30. }
  31. }
  32. }
  33. if(POCCurr == 1 && slice->getPic()->isField())
  34. {
  35. slice->setRPSidx(m_iGOPSize+m_extraRPSs);
  36. }
  37. slice->setRPS(getSPS()->getRPSList()->getReferencePictureSet(slice->getRPSidx()));
  38. slice->getRPS()->setNumberOfPictures(slice->getRPS()->getNumberOfNegativePictures()+slice->getRPS()->getNumberOfPositivePictures());
  39. }

  
  
  1. // 明确的创建一个参考图像集(从参考图像中)
  2. #if ALLOW_RECOVERY_POINT_AS_RAP
  3. Void TComSlice::createExplicitReferencePictureSetFromReference( TComList<TComPic*>& rcListPic, TComReferencePictureSet *pReferencePictureSet, Bool isRAP, Int pocRandomAccess, Bool bUseRecoveryPoint)
  4. #else
  5. Void TComSlice::createExplicitReferencePictureSetFromReference( TComList<TComPic*>& rcListPic, TComReferencePictureSet *pReferencePictureSet, Bool isRAP)
  6. #endif
  7. {
  8. TComPic* rpcPic;
  9. Int i, j;
  10. // k就是参考图像的计数
  11. Int k = 0;
  12. Int nrOfNegativePictures = 0;
  13. Int nrOfPositivePictures = 0;
  14. // 当前帧(片)的参考图像及
  15. TComReferencePictureSet* pcRPS = this->getLocalRPS();
  16. // loop through all pictures in the Reference Picture Set
  17. // 遍历所有的参考图像(存放在参考图像集中的)
  18. for(i= 0;i<pReferencePictureSet->getNumberOfPictures();i++)
  19. {
  20. j = 0;
  21. // loop through all pictures in the reference picture buffer
  22. TComList<TComPic*>::iterator iterPic = rcListPic.begin();
  23. while ( iterPic != rcListPic.end())
  24. {
  25. j++;
  26. rpcPic = *(iterPic++);
  27. // 该条件成立表示找到了参考图像
  28. // 在图像列表中找到了当前片的参考图像
  29. if(rpcPic->getPicSym()->getSlice( 0)->getPOC() == this->getPOC() + pReferencePictureSet->getDeltaPOC(i)
  30. && rpcPic->getSlice( 0)->isReferenced())
  31. {
  32. // This picture exists as a reference picture
  33. // and should be added to the explicit Reference Picture Set
  34. // 设置第k个图像的相对poc
  35. pcRPS->setDeltaPOC(k, pReferencePictureSet->getDeltaPOC(i));
  36. // 设置该参考图像是否允许被使用
  37. pcRPS->setUsed(k, pReferencePictureSet->getUsed(i) && (!isRAP));
  38. #if ALLOW_RECOVERY_POINT_AS_RAP
  39. pcRPS->setUsed(k, pcRPS->getUsed(k) && !(bUseRecoveryPoint && this->getPOC() > pocRandomAccess && this->getPOC() + pReferencePictureSet->getDeltaPOC(i) < pocRandomAccess) );
  40. #endif
  41. // 如果相对poc小于0,表示是前向参考
  42. if(pcRPS->getDeltaPOC(k) < 0)
  43. {
  44. // 统计前向参考帧的数量
  45. nrOfNegativePictures++;
  46. }
  47. // 如果相对poc大于0,表示是后向参考
  48. else
  49. {
  50. // 统计后向参考帧的数量
  51. nrOfPositivePictures++;
  52. }
  53. k++;
  54. }
  55. }
  56. }
  57. #if EFFICIENT_FIELD_IRAP
  58. // 是否使用新的参考图像集
  59. Bool useNewRPS = false;
  60. // if current picture is complimentary field associated to IRAP, add the IRAP to its RPS.
  61. if(m_pcPic->isField())
  62. {
  63. TComList<TComPic*>::iterator iterPic = rcListPic.begin();
  64. while ( iterPic != rcListPic.end())
  65. {
  66. rpcPic = *(iterPic++);
  67. if(rpcPic->getPicSym()->getSlice( 0)->getPOC() == this->getAssociatedIRAPPOC() && this->getAssociatedIRAPPOC() == this->getPOC()+ 1)
  68. {
  69. pcRPS->setDeltaPOC(k, 1);
  70. pcRPS->setUsed(k, true);
  71. nrOfPositivePictures++;
  72. k ++;
  73. useNewRPS = true;
  74. }
  75. }
  76. }
  77. #endif // EFFICIENT_FIELD_IRAP
  78. // 设置前向参考帧的数量,后向参考帧的数量,以及参考帧的总数
  79. pcRPS->setNumberOfNegativePictures(nrOfNegativePictures);
  80. pcRPS->setNumberOfPositivePictures(nrOfPositivePictures);
  81. pcRPS->setNumberOfPictures(nrOfNegativePictures+nrOfPositivePictures);
  82. // This is a simplistic inter rps example. A smarter encoder will look for a better reference RPS to do the
  83. // inter RPS prediction with. Here we just use the reference used by pReferencePictureSet.
  84. // If pReferencePictureSet is not inter_RPS_predicted, then inter_RPS_prediction is for the current RPS also disabled.
  85. if (!pReferencePictureSet->getInterRPSPrediction() //如果是帧内预测
  86. # if EFFICIENT_FIELD_IRAP
  87. || useNewRPS
  88. #endif
  89. )
  90. {
  91. pcRPS->setInterRPSPrediction( false); //
  92. pcRPS->setNumRefIdc( 0);
  93. }
  94. // 帧间预测
  95. else
  96. {
  97. // 参考图像集的索引,以传进来的参考图像集为基础,得到当前参考图像集的相对索引
  98. Int rIdx = this->getRPSidx() - pReferencePictureSet->getDeltaRIdxMinus1() - 1;
  99. // 相对的参考图像集
  100. Int deltaRPS = pReferencePictureSet->getDeltaRPS();
  101. // 根据参考图像集的索引得到参考图像集(参考图像集可能有多个,存放在SPS的列表中),这个得到的图像集就是当前片的参考图像集
  102. TComReferencePictureSet* pcRefRPS = this->getSPS()->getRPSList()->getReferencePictureSet(rIdx);
  103. // 得到参考图像集中图像的数量
  104. Int iRefPics = pcRefRPS->getNumberOfPictures();
  105. Int iNewIdc= 0;
  106. // 对参考图像集的每一个图像
  107. for(i= 0; i<= iRefPics; i++)
  108. {
  109. // 得到相对的poc
  110. Int deltaPOC = ((i != iRefPics)? pcRefRPS->getDeltaPOC(i) : 0); // check if the reference abs POC is >= 0
  111. Int iRefIdc = 0;
  112. // 遍历本地的参考图像集的每一帧图像
  113. for (j= 0; j < pcRPS->getNumberOfPictures(); j++) // loop through the pictures in the new RPS
  114. {
  115. // 如果本参考图像集的某一帧和SPS的参考图像集中的某一帧匹配
  116. if ( (deltaPOC + deltaRPS) == pcRPS->getDeltaPOC(j))
  117. {
  118. // 如果该帧可以被参考
  119. if (pcRPS->getUsed(j))
  120. {
  121. iRefIdc = 1;
  122. }
  123. else
  124. {
  125. iRefIdc = 2;
  126. }
  127. }
  128. }
  129. // 设置本地参考图像集的这一帧的idc
  130. pcRPS->setRefIdc(i, iRefIdc);
  131. iNewIdc++;
  132. }
  133. // 帧间预测
  134. pcRPS->setInterRPSPrediction( true);
  135. // 参考帧的数量
  136. pcRPS->setNumRefIdc(iNewIdc);
  137. // 相对的参考图像集的
  138. pcRPS->setDeltaRPS(deltaRPS);
  139. pcRPS->setDeltaRIdxMinus1(pReferencePictureSet->getDeltaRIdxMinus1() + this->getSPS()->getRPSList()->getNumberOfReferencePictureSets() - this->getRPSidx());
  140. }
  141. // 设置参考图像集
  142. this->setRPS(pcRPS);
  143. this->setRPSidx( -1);
  144. }

  
  
  1. // 应用参考图像集
  2. Void TComSlice::applyReferencePictureSet( TComList<TComPic*>& rcListPic, TComReferencePictureSet *pReferencePictureSet)
  3. {
  4. TComPic* rpcPic;
  5. Int i, isReference;
  6. // 检测leading 帧的限制
  7. checkLeadingPictureRestrictions(rcListPic);
  8. // loop through all pictures in the reference picture buffer
  9. TComList<TComPic*>::iterator iterPic = rcListPic.begin();
  10. // 对图像列表的每一帧图像进行循环处理
  11. while ( iterPic != rcListPic.end())
  12. {
  13. rpcPic = *(iterPic++);
  14. // 如果不能被参考,那么跳过
  15. if(!rpcPic->getSlice( 0 )->isReferenced())
  16. {
  17. continue;
  18. }
  19. // 是否参考其他帧 的 标志
  20. isReference = 0;
  21. // loop through all pictures in the Reference Picture Set
  22. // to see if the picture should be kept as reference picture
  23. // 对于参考图像集的前向参考图像和后向参考图像
  24. for(i= 0;i<pReferencePictureSet->getNumberOfPositivePictures()+pReferencePictureSet->getNumberOfNegativePictures();i++)
  25. {
  26. // 如果图像列表中的某一帧不是长期参考的帧 并且 它是当前帧的参考帧
  27. if(!rpcPic->getIsLongTerm() &&
  28. rpcPic->getPicSym()->getSlice( 0)->getPOC() == this->getPOC() + pReferencePictureSet->getDeltaPOC(i))
  29. {
  30. // 把标志设置为1,表明是参考其他帧的
  31. isReference = 1;
  32. // 设置列表中的这一帧被其他人参考
  33. rpcPic->setUsedByCurr(pReferencePictureSet->getUsed(i));
  34. rpcPic->setIsLongTerm( 0);
  35. }
  36. }
  37. // 对于参考图像集的其他图像(注意i没有设置从0开始)(这些参考帧(属于长期参考帧)的poc都是绝对的poc)
  38. for(;i<pReferencePictureSet->getNumberOfPictures();i++)
  39. {
  40. if(pReferencePictureSet->getCheckLTMSBPresent(i)== true)
  41. {
  42. if(rpcPic->getIsLongTerm() && (rpcPic->getPicSym()->getSlice( 0)->getPOC()) == pReferencePictureSet->getPOC(i))
  43. {
  44. isReference = 1;
  45. rpcPic->setUsedByCurr(pReferencePictureSet->getUsed(i));
  46. }
  47. }
  48. else
  49. {
  50. Int pocCycle = 1<<rpcPic->getPicSym()->getSlice( 0)->getSPS()->getBitsForPOC();
  51. Int curPoc = rpcPic->getPicSym()->getSlice( 0)->getPOC() & (pocCycle -1);
  52. Int refPoc = pReferencePictureSet->getPOC(i) & (pocCycle -1);
  53. if(rpcPic->getIsLongTerm() && curPoc == refPoc)
  54. {
  55. isReference = 1;
  56. rpcPic->setUsedByCurr(pReferencePictureSet->getUsed(i));
  57. }
  58. }
  59. }
  60. // mark the picture as "unused for reference" if it is not in
  61. // the Reference Picture Set
  62. // 对参考图像集遍历完成之后,就可以知道这个帧是否被被其他帧参考
  63. if(rpcPic->getPicSym()->getSlice( 0)->getPOC() != this->getPOC() && isReference == 0)
  64. {
  65. rpcPic->getSlice( 0 )->setReferenced( false );
  66. rpcPic->setUsedByCurr( 0);
  67. rpcPic->setIsLongTerm( 0);
  68. }
  69. //check that pictures of higher temporal layers are not used
  70. // 这里保证了当前帧所在的时域层比参考帧的时域层大
  71. assert(rpcPic->getSlice( 0 )->isReferenced()== 0||rpcPic->getUsedByCurr()== 0||rpcPic->getTLayer()<= this->getTLayer());
  72. //check that pictures of higher or equal temporal layer are not in the RPS if the current picture is a TSA picture
  73. if( this->getNalUnitType() == NAL_UNIT_CODED_SLICE_TSA_R || this->getNalUnitType() == NAL_UNIT_CODED_SLICE_TSA_N)
  74. {
  75. assert(rpcPic->getSlice( 0 )->isReferenced()== 0||rpcPic->getTLayer()< this->getTLayer());
  76. }
  77. //check that pictures marked as temporal layer non-reference pictures are not used for reference
  78. if(rpcPic->getPicSym()->getSlice( 0)->getPOC() != this->getPOC() && rpcPic->getTLayer()== this->getTLayer())
  79. {
  80. assert(rpcPic->getSlice( 0 )->isReferenced()== 0||rpcPic->getUsedByCurr()== 0||rpcPic->getSlice( 0 )->getTemporalLayerNonReferenceFlag()== false);
  81. }
  82. }
  83. }

  
  
  1. // 对参考图像集中的长期参考图像进行排序
  2. Void TEncGOP::arrangeLongtermPicturesInRPS(TComSlice *pcSlice, TComList<TComPic*>& rcListPic)
  3. {
  4. TComReferencePictureSet *rps = pcSlice->getRPS();
  5. if(!rps->getNumberOfLongtermPictures())
  6. {
  7. return;
  8. }
  9. // Arrange long-term reference pictures in the correct order of LSB and MSB,
  10. // and assign values for pocLSBLT and MSB present flag
  11. // 长期参考图像的poc,LSB,索引
  12. Int longtermPicsPoc[MAX_NUM_REF_PICS], longtermPicsLSB[MAX_NUM_REF_PICS], indices[MAX_NUM_REF_PICS];
  13. // 长期参考图像的MSB
  14. Int longtermPicsMSB[MAX_NUM_REF_PICS];
  15. // msb出现的标志
  16. Bool mSBPresentFlag[MAX_NUM_REF_PICS];
  17. :: memset(longtermPicsPoc, 0, sizeof(longtermPicsPoc)); // Store POC values of LTRP
  18. :: memset(longtermPicsLSB, 0, sizeof(longtermPicsLSB)); // Store POC LSB values of LTRP
  19. :: memset(longtermPicsMSB, 0, sizeof(longtermPicsMSB)); // Store POC LSB values of LTRP
  20. :: memset(indices , 0, sizeof(indices)); // Indices to aid in tracking sorted LTRPs
  21. :: memset(mSBPresentFlag , 0, sizeof(mSBPresentFlag)); // Indicate if MSB needs to be present
  22. // Get the long-term reference pictures
  23. // 注意!!!
  24. // 各中参考图像在参考图像集中的位置:首先是前向参考帧,然后是后向参考帧,最后是长期参考帧
  25. // 下面这个变量存放了长期参考图像集的起始位置
  26. Int offset = rps->getNumberOfNegativePictures() + rps->getNumberOfPositivePictures();
  27. Int i, ctr = 0;
  28. Int maxPicOrderCntLSB = 1 << pcSlice->getSPS()->getBitsForPOC();
  29. // 从后面开始扫描,记录长期参考帧的信息
  30. for(i = rps->getNumberOfPictures() - 1; i >= offset; i--, ctr++)
  31. {
  32. longtermPicsPoc[ctr] = rps->getPOC(i); // LTRP POC
  33. longtermPicsLSB[ctr] = getLSB(longtermPicsPoc[ctr], maxPicOrderCntLSB); // LTRP POC LSB
  34. indices[ctr] = i;
  35. longtermPicsMSB[ctr] = longtermPicsPoc[ctr] - longtermPicsLSB[ctr];
  36. }
  37. Int numLongPics = rps->getNumberOfLongtermPictures();
  38. assert(ctr == numLongPics);
  39. // Arrange pictures in decreasing order of MSB;
  40. // 按照MSB从大到小排序长期参考帧
  41. for(i = 0; i < numLongPics; i++)
  42. {
  43. for(Int j = 0; j < numLongPics - 1; j++)
  44. {
  45. if(longtermPicsMSB[j] < longtermPicsMSB[j+ 1])
  46. {
  47. std::swap(longtermPicsPoc[j], longtermPicsPoc[j+ 1]);
  48. std::swap(longtermPicsLSB[j], longtermPicsLSB[j+ 1]);
  49. std::swap(longtermPicsMSB[j], longtermPicsMSB[j+ 1]);
  50. std::swap(indices[j] , indices[j+ 1] );
  51. }
  52. }
  53. }
  54. // 记录长期参考帧MSB出现的标志
  55. for(i = 0; i < numLongPics; i++)
  56. {
  57. // Check if MSB present flag should be enabled.
  58. // Check if the buffer contains any pictures that have the same LSB.
  59. TComList<TComPic*>::iterator iterPic = rcListPic.begin();
  60. TComPic* pcPic;
  61. while ( iterPic != rcListPic.end() )
  62. {
  63. pcPic = *iterPic;
  64. if( (getLSB(pcPic->getPOC(), maxPicOrderCntLSB) == longtermPicsLSB[i]) && // Same LSB
  65. (pcPic->getSlice( 0)->isReferenced()) && // Reference picture
  66. (pcPic->getPOC() != longtermPicsPoc[i]) ) // Not the LTRP itself
  67. {
  68. mSBPresentFlag[i] = true;
  69. break;
  70. }
  71. iterPic++;
  72. }
  73. }
  74. // tempArray for usedByCurr flag
  75. // 记录长期参考帧被使用的情况
  76. Bool tempArray[MAX_NUM_REF_PICS]; :: memset(tempArray, 0, sizeof(tempArray));
  77. for(i = 0; i < numLongPics; i++)
  78. {
  79. tempArray[i] = rps->getUsed(indices[i]);
  80. }
  81. // Now write the final values;
  82. ctr = 0;
  83. Int currMSB = 0, currLSB = 0;
  84. // currPicPoc = currMSB + currLSB
  85. currLSB = getLSB(pcSlice->getPOC(), maxPicOrderCntLSB);
  86. currMSB = pcSlice->getPOC() - currLSB;
  87. // 设置长期参考帧的各种信息
  88. for(i = rps->getNumberOfPictures() - 1; i >= offset; i--, ctr++)
  89. {
  90. rps->setPOC (i, longtermPicsPoc[ctr]);
  91. rps->setDeltaPOC (i, - pcSlice->getPOC() + longtermPicsPoc[ctr]);
  92. rps->setUsed (i, tempArray[ctr]);
  93. rps->setPocLSBLT (i, longtermPicsLSB[ctr]);
  94. rps->setDeltaPocMSBCycleLT (i, (currMSB - (longtermPicsPoc[ctr] - longtermPicsLSB[ctr])) / maxPicOrderCntLSB);
  95. rps->setDeltaPocMSBPresentFlag(i, mSBPresentFlag[ctr]);
  96. assert(rps->getDeltaPocMSBCycleLT(i) >= 0); // Non-negative value
  97. }
  98. // 确保长期参考帧不会重复
  99. for(i = rps->getNumberOfPictures() - 1, ctr = 1; i >= offset; i--, ctr++)
  100. {
  101. for(Int j = rps->getNumberOfPictures() - 1 - ctr; j >= offset; j--)
  102. {
  103. // Here at the encoder we know that we have set the full POC value for the LTRPs, hence we
  104. // don't have to check the MSB present flag values for this constraint.
  105. assert( rps->getPOC(i) != rps->getPOC(j) ); // If assert fails, LTRP entry repeated in RPS!!!
  106. }
  107. }
  108. }

  
  
  1. // 设置参考图像列表
  2. Void TComSlice::setRefPicList( TComList<TComPic*>& rcListPic, Bool checkNumPocTotalCurr )
  3. {
  4. if (!checkNumPocTotalCurr)
  5. {
  6. if (m_eSliceType == I_SLICE)
  7. {
  8. :: memset( m_apcRefPicList, 0, sizeof (m_apcRefPicList));
  9. :: memset( m_aiNumRefIdx, 0, sizeof ( m_aiNumRefIdx ));
  10. return;
  11. }
  12. m_aiNumRefIdx[ 0] = getNumRefIdx(REF_PIC_LIST_0);
  13. m_aiNumRefIdx[ 1] = getNumRefIdx(REF_PIC_LIST_1);
  14. }
  15. TComPic* pcRefPic= NULL;
  16. // 存放前向参考帧(最多16个)
  17. TComPic* RefPicSetStCurr0[ 16];
  18. // 存放后向参考帧(最多16个)
  19. TComPic* RefPicSetStCurr1[ 16];
  20. // 存放长期参考帧
  21. TComPic* RefPicSetLtCurr[ 16];
  22. UInt NumPocStCurr0 = 0;
  23. UInt NumPocStCurr1 = 0;
  24. UInt NumPocLtCurr = 0;
  25. Int i;
  26. // 遍历每一个前向参考帧
  27. for(i= 0; i < m_pcRPS->getNumberOfNegativePictures(); i++)
  28. {
  29. if(m_pcRPS->getUsed(i))
  30. {
  31. // 取得该帧
  32. pcRefPic = xGetRefPic(rcListPic, getPOC()+m_pcRPS->getDeltaPOC(i));
  33. pcRefPic->setIsLongTerm( 0);
  34. // 扩展图像边界
  35. pcRefPic->getPicYuvRec()->extendPicBorder();
  36. // 把这个帧存放起来
  37. RefPicSetStCurr0[NumPocStCurr0] = pcRefPic;
  38. NumPocStCurr0++;
  39. pcRefPic->setCheckLTMSBPresent( false);
  40. }
  41. }
  42. // 遍历每一个后向参考帧
  43. for(; i < m_pcRPS->getNumberOfNegativePictures()+m_pcRPS->getNumberOfPositivePictures(); i++)
  44. {
  45. if(m_pcRPS->getUsed(i))
  46. {
  47. pcRefPic = xGetRefPic(rcListPic, getPOC()+m_pcRPS->getDeltaPOC(i));
  48. pcRefPic->setIsLongTerm( 0);
  49. pcRefPic->getPicYuvRec()->extendPicBorder();
  50. RefPicSetStCurr1[NumPocStCurr1] = pcRefPic;
  51. NumPocStCurr1++;
  52. pcRefPic->setCheckLTMSBPresent( false);
  53. }
  54. }
  55. // 遍历每一个长期参考帧
  56. for(i = m_pcRPS->getNumberOfNegativePictures()+m_pcRPS->getNumberOfPositivePictures()+m_pcRPS->getNumberOfLongtermPictures() -1; i > m_pcRPS->getNumberOfNegativePictures()+m_pcRPS->getNumberOfPositivePictures() -1 ; i--)
  57. {
  58. if(m_pcRPS->getUsed(i))
  59. {
  60. pcRefPic = xGetLongTermRefPic(rcListPic, m_pcRPS->getPOC(i), m_pcRPS->getCheckLTMSBPresent(i));
  61. pcRefPic->setIsLongTerm( 1);
  62. pcRefPic->getPicYuvRec()->extendPicBorder();
  63. RefPicSetLtCurr[NumPocLtCurr] = pcRefPic;
  64. NumPocLtCurr++;
  65. }
  66. if(pcRefPic== NULL)
  67. {
  68. pcRefPic = xGetLongTermRefPic(rcListPic, m_pcRPS->getPOC(i), m_pcRPS->getCheckLTMSBPresent(i));
  69. }
  70. pcRefPic->setCheckLTMSBPresent(m_pcRPS->getCheckLTMSBPresent(i));
  71. }
  72. // ref_pic_list_init
  73. // 两个参考图像列表(list0和list1)
  74. TComPic* rpsCurrList0[MAX_NUM_REF+ 1];
  75. TComPic* rpsCurrList1[MAX_NUM_REF+ 1];
  76. Int numPocTotalCurr = NumPocStCurr0 + NumPocStCurr1 + NumPocLtCurr;
  77. if (checkNumPocTotalCurr)
  78. {
  79. // The variable NumPocTotalCurr is derived as specified in subclause 7.4.7.2. It is a requirement of bitstream conformance that the following applies to the value of NumPocTotalCurr:
  80. // - If the current picture is a BLA or CRA picture, the value of NumPocTotalCurr shall be equal to 0.
  81. // - Otherwise, when the current picture contains a P or B slice, the value of NumPocTotalCurr shall not be equal to 0.
  82. if (getRapPicFlag())
  83. {
  84. assert(numPocTotalCurr == 0);
  85. }
  86. if (m_eSliceType == I_SLICE)
  87. {
  88. :: memset( m_apcRefPicList, 0, sizeof (m_apcRefPicList));
  89. :: memset( m_aiNumRefIdx, 0, sizeof ( m_aiNumRefIdx ));
  90. return;
  91. }
  92. assert(numPocTotalCurr > 0);
  93. m_aiNumRefIdx[ 0] = getNumRefIdx(REF_PIC_LIST_0);
  94. m_aiNumRefIdx[ 1] = getNumRefIdx(REF_PIC_LIST_1);
  95. }
  96. // 按照 前向、后向,长期的顺序存放参考帧
  97. Int cIdx = 0;
  98. for ( i= 0; i<NumPocStCurr0; i++, cIdx++)
  99. {
  100. rpsCurrList0[cIdx] = RefPicSetStCurr0[i];
  101. }
  102. for ( i= 0; i<NumPocStCurr1; i++, cIdx++)
  103. {
  104. rpsCurrList0[cIdx] = RefPicSetStCurr1[i];
  105. }
  106. for ( i= 0; i<NumPocLtCurr; i++, cIdx++)
  107. {
  108. rpsCurrList0[cIdx] = RefPicSetLtCurr[i];
  109. }
  110. assert(cIdx == numPocTotalCurr);
  111. // 如果是B片(那么需要向后进行参考,即需要list1)
  112. if (m_eSliceType==B_SLICE)
  113. {
  114. cIdx = 0;
  115. for ( i= 0; i<NumPocStCurr1; i++, cIdx++)
  116. {
  117. rpsCurrList1[cIdx] = RefPicSetStCurr1[i];
  118. }
  119. for ( i= 0; i<NumPocStCurr0; i++, cIdx++)
  120. {
  121. rpsCurrList1[cIdx] = RefPicSetStCurr0[i];
  122. }
  123. for ( i= 0; i<NumPocLtCurr; i++, cIdx++)
  124. {
  125. rpsCurrList1[cIdx] = RefPicSetLtCurr[i];
  126. }
  127. assert(cIdx == numPocTotalCurr);
  128. }
  129. :: memset(m_bIsUsedAsLongTerm, 0, sizeof(m_bIsUsedAsLongTerm));
  130. // 然后把list0和list1(上面的是临时的)放到当前帧的参考列表中
  131. for (Int rIdx = 0; rIdx < m_aiNumRefIdx[ 0]; rIdx ++)
  132. {
  133. cIdx = m_RefPicListModification.getRefPicListModificationFlagL0() ? m_RefPicListModification.getRefPicSetIdxL0(rIdx) : rIdx % numPocTotalCurr;
  134. assert(cIdx >= 0 && cIdx < numPocTotalCurr);
  135. m_apcRefPicList[ 0][rIdx] = rpsCurrList0[ cIdx ];
  136. m_bIsUsedAsLongTerm[ 0][rIdx] = ( cIdx >= NumPocStCurr0 + NumPocStCurr1 );
  137. }
  138. if ( m_eSliceType != B_SLICE )
  139. {
  140. m_aiNumRefIdx[ 1] = 0;
  141. :: memset( m_apcRefPicList[ 1], 0, sizeof(m_apcRefPicList[ 1]));
  142. }
  143. else
  144. {
  145. for (Int rIdx = 0; rIdx < m_aiNumRefIdx[ 1]; rIdx ++)
  146. {
  147. cIdx = m_RefPicListModification.getRefPicListModificationFlagL1() ? m_RefPicListModification.getRefPicSetIdxL1(rIdx) : rIdx % numPocTotalCurr;
  148. assert(cIdx >= 0 && cIdx < numPocTotalCurr);
  149. m_apcRefPicList[ 1][rIdx] = rpsCurrList1[ cIdx ];
  150. m_bIsUsedAsLongTerm[ 1][rIdx] = ( cIdx >= NumPocStCurr0 + NumPocStCurr1 );
  151. }
  152. }
  153. }

  
  
  1. Void TComSlice::setRefPOCList()
  2. {
  3. for (Int iDir = 0; iDir < 2; iDir++)
  4. {
  5. for (Int iNumRefIdx = 0; iNumRefIdx < m_aiNumRefIdx[iDir]; iNumRefIdx++)
  6. {
  7. m_aiRefPOCList[iDir][iNumRefIdx] = m_apcRefPicList[iDir][iNumRefIdx]->getPOC();
  8. }
  9. }
  10. }

  
  
  1. Void TComSlice::setList1IdxToList0Idx()
  2. {
  3. Int idxL0, idxL1;
  4. for ( idxL1 = 0; idxL1 < getNumRefIdx( REF_PIC_LIST_1 ); idxL1++ )
  5. {
  6. m_list1IdxToList0Idx[idxL1] = -1;
  7. for ( idxL0 = 0; idxL0 < getNumRefIdx( REF_PIC_LIST_0 ); idxL0++ )
  8. {
  9. if ( m_apcRefPicList[REF_PIC_LIST_0][idxL0]->getPOC() == m_apcRefPicList[REF_PIC_LIST_1][idxL1]->getPOC() )
  10. {
  11. m_list1IdxToList0Idx[idxL1] = idxL0;
  12. break;
  13. }
  14. }
  15. }
  16. }








  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值