【HEVC】2、HM-16.7编码一个CU(帧内部分) 1.帧内预测相邻参考像素获取
HEVC帧内预测的35中预测模式是在PU基础上定义的,实际帧内预测的过程则以TU为单位。PU以四叉树划分TU,一个PU内所有TU共享同一种预测模式。帧内预测分3个步骤:
(1) 判断当前TU相邻像素点是否可用并做相应的处理
(2) 对参考像素进行滤波
(3) 根据滤波后的参考像素计算当前TU的预测像素值。
HM-16.7中fillReferenceSamples()主要实现第一个步骤,真正进行帧内预测之前,使用重建后的Yuv图像对当前PU的相邻样点进行赋值,为接下来进行的角度预测提供参考样点值,对应于draft 8.4.4.2.2的内容。主要过程是:
(1)如果所有相邻点均不可用,则参考样点值均被赋值为DC值;
iDCValue = 1 << (bitDepth - 1),对于8bit像素,该值为128。
(2)如果所有相邻点均可用,则参考样点值都会被赋值为重建Yuv图像中与其位置相同的样点值;
(3)如果不满足上述两个条件,则按照从左下往左上,从左上往右上的扫描顺序进行遍历,如果第一个点不可用,则使用下一个可用点对应的重建Yuv样点值对其进行赋值;对于除第一个点外的其它邻点,如果该点不可用,则使用它的前一个样点值进行赋值(前一个步骤保证了前一个样点值一定是存在的),直到遍历完毕。
1 Void fillReferenceSamples( const Int bitDepth, 2 #if O0043_BEST_EFFORT_DECODING 3 const Int bitDepthDelta, 4 #endif 5 const Pel* piRoiOrigin, 6 Pel* piIntraTemp, 7 const Bool* bNeighborFlags, 8 const Int iNumIntraNeighbor, 9 const Int unitWidth, 10 const Int unitHeight, 11 const Int iAboveUnits, 12 const Int iLeftUnits, 13 const UInt uiWidth, 14 const UInt uiHeight, 15 const Int iPicStride ) 16 { 17 const Pel* piRoiTemp;//piRoiOrgin指向重建Yuv图像对应于当前PU所在位置的首地址,piRoiTemp用于指向所感兴趣的重建Yuv的位置 18 Int i, j; 19 Int iDCValue = 1 << (bitDepth - 1);//参考像素不可用时的填充值,8bit时候为128. 20 const Int iTotalUnits = iAboveUnits + iLeftUnits + 1; //+1 for top-left //以4个像素点为单位标记,其中左上角单独标记 21 22 if (iNumIntraNeighbor == 0) // all samples are not available 23 { 24 // Fill border with DC value 25 for (i=0; i<uiWidth; i++) //!< AboveLeft + Above + AboveRight 26 { 27 piIntraTemp[i] = iDCValue; 28 } 29 for (i=1; i<uiHeight; i++)//!< Left + BelowLeft 30 { 31 piIntraTemp[i*uiWidth] = iDCValue; 32 } 33 } 34 else if (iNumIntraNeighbor == iTotalUnits)// all samples are available 35 { 36 // Fill top-left border and top and top right with rec. samples 37 piRoiTemp = piRoiOrigin - iPicStride - 1; //!< AboveLeft 38 39 for (i=0; i<uiWidth; i++) 40 { 41 #if O0043_BEST_EFFORT_DECODING 42 piIntraTemp[i] = piRoiTemp[i] << bitDepthDelta; 43 #else 44 piIntraTemp[i] = piRoiTemp[i]; 45 #endif 46 } 47 48 // Fill left and below left border with rec. samples 49 piRoiTemp = piRoiOrigin - 1; 50 51 for (i=1; i<uiHeight; i++) 52 { 53 #if O0043_BEST_EFFORT_DECODING 54 piIntraTemp[i*uiWidth] = (*(piRoiTemp)) << bitDepthDelta; 55 #else 56 piIntraTemp[i*uiWidth] = *(piRoiTemp);//!< 每个参考样点赋值为对应位置重建Yuv样点值 57 #endif 58 piRoiTemp += iPicStride;//!< 指向重建Yuv下一行 59 } 60 } 61 else // reference samples are partially available 62 { 63 // all above units have "unitWidth" samples each, all left/below-left units have "unitHeight" samples each 64 //!< neighboring samples的总数 65 const Int iTotalSamples = (iLeftUnits * unitHeight) + ((iAboveUnits + 1) * unitWidth); 66 Pel piIntraLine[5 * MAX_CU_SIZE]; 67 Pel *piIntraLineTemp;//!<临时存储用于填充neighboring samples的样点值 68 const Bool *pbNeighborFlags;//保存以四个像素点为单位的可用性 69 70 // Initialize 71 for (i=0; i<iTotalSamples; i++) 72 { 73 piIntraLine[i] = iDCValue; 74 } 75 76 // Fill top-left sample 77 piRoiTemp = piRoiOrigin - iPicStride - 1;//!< 指向重建Yuv左上角 78 piIntraLineTemp = piIntraLine + (iLeftUnits * unitHeight);//!< piAdiLine的扫描顺序为左下到左上,再从左到右上 79 pbNeighborFlags = bNeighborFlags + iLeftUnits;//!< 标记neighbor可用性的数组同样移动至左上角 80 if (*pbNeighborFlags)//!< 如果左上角可用,则左上角4个像素点均赋值为重建Yuv左上角的样点值 81 { 82 #if O0043_BEST_EFFORT_DECODING 83 Pel topLeftVal=piRoiTemp[0] << bitDepthDelta; 84 #else 85 Pel topLeftVal=piRoiTemp[0]; 86 #endif 87 for (i=0; i<unitWidth; i++) 88 { 89 piIntraLineTemp[i] = topLeftVal; 90 } 91 } 92 93 // Fill left & below-left samples (downwards) 94 piRoiTemp += iPicStride;//!< piRoiTemp指向重建Yuv的左边界 95 piIntraLineTemp--;//移动指针至左边界 96 pbNeighborFlags--;//移动指针至左边界 97 98 for (j=0; j<iLeftUnits; j++)//从左向左下扫描 99 { 100 if (*pbNeighborFlags)//如果可用 101 { 102 for (i=0; i<unitHeight; i++)//!< 每个4x4块里的4个样点分别被赋值为对应位置的重建Yuv的样点值 103 { 104 #if O0043_BEST_EFFORT_DECODING 105 piIntraLineTemp[-i] = piRoiTemp[i*iPicStride] << bitDepthDelta; 106 #else 107 piIntraLineTemp[-i] = piRoiTemp[i*iPicStride]; 108 #endif 109 } 110 } 111 piRoiTemp += unitHeight*iPicStride;//!< 指针挪到下一个行(以4x4块为单位,即实际上下移了4行) 112 piIntraLineTemp -= unitHeight;//!< 指针下移 113 pbNeighborFlags--;//!< 指针下移 114 } 115 116 // Fill above & above-right samples (left-to-right) (each unit has "unitWidth" samples) 117 piRoiTemp = piRoiOrigin - iPicStride;//!< piRoiTemp 指向重建Yuv的上边界 118 // offset line buffer by iNumUints2*unitHeight (for left/below-left) + unitWidth (for above-left) 119 piIntraLineTemp = piIntraLine + (iLeftUnits * unitHeight) + unitWidth; 120 pbNeighborFlags = bNeighborFlags + iLeftUnits + 1; 121 for (j=0; j<iAboveUnits; j++) //!< 从左扫描至右上 122 { 123 if (*pbNeighborFlags)//如果可用 124 { 125 for (i=0; i<unitWidth; i++)//!< 每个4x4块里的4个样点分别被赋值为对应位置的重建Yuv的样点值 126 { 127 #if O0043_BEST_EFFORT_DECODING 128 piIntraLineTemp[i] = piRoiTemp[i] << bitDepthDelta; 129 #else 130 piIntraLineTemp[i] = piRoiTemp[i]; 131 #endif 132 } 133 } 134 piRoiTemp += unitWidth;//!< 指针右移,实际是右移了4 135 piIntraLineTemp += unitWidth;//!< 指针右移,实际是右移了4 136 pbNeighborFlags++;//!< 指针右移,以4个像素点为单位标记可用性 137 } 138 139 // Pad reference samples when necessary 140 Int iCurrJnit = 0; 141 Pel *piIntraLineCur = piIntraLine;//!< 指向左下角(纵坐标最大的那个位置,即扫描起点) 142 const UInt piIntraLineTopRowOffset = iLeftUnits * (unitHeight - unitWidth); 143 144 if (!bNeighborFlags[0]) 145 { 146 // very bottom unit of bottom-left; at least one unit will be valid. 147 { 148 Int iNext = 1; 149 while (iNext < iTotalUnits && !bNeighborFlags[iNext]) 150 { 151 iNext++; 152 } 153 Pel *piIntraLineNext = piIntraLine + ((iNext < iLeftUnits) ? (iNext * unitHeight) : (piIntraLineTopRowOffset + (iNext * unitWidth))); 154 const Pel refSample = *piIntraLineNext; 155 // Pad unavailable samples with new value 156 Int iNextOrTop = std::min<Int>(iNext, iLeftUnits); 157 // fill left column 158 while (iCurrJnit < iNextOrTop) //!< 遍历所有neighboring samples 159 { 160 for (i=0; i<unitHeight; i++) 161 { 162 piIntraLineCur[i] = refSample; 163 } 164 piIntraLineCur += unitHeight; 165 iCurrJnit++; 166 } 167 // fill top row 168 while (iCurrJnit < iNext) 169 { 170 for (i=0; i<unitWidth; i++) 171 { 172 piIntraLineCur[i] = refSample; 173 } 174 piIntraLineCur += unitWidth; 175 iCurrJnit++; 176 } 177 } 178 } 179 180 // pad all other reference samples. 181 while (iCurrJnit < iTotalUnits) 182 { 183 if (!bNeighborFlags[iCurrJnit]) // samples not available 184 { 185 { 186 const Int numSamplesInCurrUnit = (iCurrJnit >= iLeftUnits) ? unitWidth : unitHeight; 187 const Pel refSample = *(piIntraLineCur-1); 188 for (i=0; i<numSamplesInCurrUnit; i++) 189 { 190 piIntraLineCur[i] = refSample; 191 } 192 piIntraLineCur += numSamplesInCurrUnit; 193 iCurrJnit++; 194 } 195 } 196 else 197 { 198 piIntraLineCur += (iCurrJnit >= iLeftUnits) ? unitWidth : unitHeight; 199 iCurrJnit++; 200 } 201 } 202 203 // Copy processed samples 204 205 piIntraLineTemp = piIntraLine + uiHeight + unitWidth - 2; 206 // top left, top and top right samples 207 for (i=0; i<uiWidth; i++) 208 { 209 piIntraTemp[i] = piIntraLineTemp[i]; 210 } 211 212 piIntraLineTemp = piIntraLine + uiHeight - 1; 213 for (i=1; i<uiHeight; i++) 214 { 215 piIntraTemp[i*uiWidth] = piIntraLineTemp[-i]; 216 } 217 } 218 }
本文来自博客园,作者:追随技术,转载请注明原文链接:https://www.cnblogs.com/545235abc/p/5190689.html
分类:
HEVC/H265
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 快收藏!一个技巧从此不再搞混缓存穿透和缓存击穿
· Blazor Hybrid适配到HarmonyOS系统
· 支付宝 IoT 设备入门宝典(下)设备经营篇
· 万字调研——AI生成内容检测
· 解决跨域问题的这6种方案,真香!