/src/vvenc/source/Lib/CommonLib/IntraPrediction.cpp
Line | Count | Source |
1 | | /* ----------------------------------------------------------------------------- |
2 | | The copyright in this software is being made available under the Clear BSD |
3 | | License, included below. No patent rights, trademark rights and/or |
4 | | other Intellectual Property Rights other than the copyrights concerning |
5 | | the Software are granted under this license. |
6 | | |
7 | | The Clear BSD License |
8 | | |
9 | | Copyright (c) 2019-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVenC Authors. |
10 | | All rights reserved. |
11 | | |
12 | | Redistribution and use in source and binary forms, with or without modification, |
13 | | are permitted (subject to the limitations in the disclaimer below) provided that |
14 | | the following conditions are met: |
15 | | |
16 | | * Redistributions of source code must retain the above copyright notice, |
17 | | this list of conditions and the following disclaimer. |
18 | | |
19 | | * Redistributions in binary form must reproduce the above copyright |
20 | | notice, this list of conditions and the following disclaimer in the |
21 | | documentation and/or other materials provided with the distribution. |
22 | | |
23 | | * Neither the name of the copyright holder nor the names of its |
24 | | contributors may be used to endorse or promote products derived from this |
25 | | software without specific prior written permission. |
26 | | |
27 | | NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY |
28 | | THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
29 | | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
30 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
31 | | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
32 | | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
33 | | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
34 | | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
35 | | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
36 | | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
37 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
38 | | POSSIBILITY OF SUCH DAMAGE. |
39 | | |
40 | | |
41 | | ------------------------------------------------------------------------------------------- */ |
42 | | |
43 | | |
44 | | /** \file Prediction.cpp |
45 | | \brief prediction class |
46 | | */ |
47 | | |
48 | | #include "IntraPrediction.h" |
49 | | #include "Unit.h" |
50 | | #include "UnitTools.h" |
51 | | #include "Rom.h" |
52 | | #include "InterpolationFilter.h" |
53 | | #include "dtrace_next.h" |
54 | | |
55 | | #include <memory.h> |
56 | | |
57 | | //! \ingroup CommonLib |
58 | | //! \{ |
59 | | |
60 | | namespace vvenc { |
61 | | |
62 | | // ==================================================================================================================== |
63 | | // Tables |
64 | | // ==================================================================================================================== |
65 | | |
66 | | const uint8_t IntraPrediction::m_aucIntraFilter[MAX_INTRA_FILTER_DEPTHS] = |
67 | | { |
68 | | 24, // 1xn |
69 | | 24, // 2xn |
70 | | 24, // 4xn |
71 | | 14, // 8xn |
72 | | 2, // 16xn |
73 | | 0, // 32xn |
74 | | 0, // 64xn |
75 | | 0 // 128xn |
76 | | }; |
77 | | |
78 | | //NOTE: Bit-Limit - 24-bit source |
79 | | void xPredIntraPlanar_Core( PelBuf& pDst, const CPelBuf& pSrc ) |
80 | 0 | { |
81 | 0 | const uint32_t width = pDst.width; |
82 | 0 | const uint32_t height = pDst.height; |
83 | 0 | const uint32_t log2W = Log2(width); |
84 | 0 | const uint32_t log2H = Log2(height); |
85 | |
|
86 | 0 | int leftColumn[MAX_TB_SIZEY + 1], topRow[MAX_TB_SIZEY + 1], bottomRow[MAX_TB_SIZEY], rightColumn[MAX_TB_SIZEY]; |
87 | 0 | const uint32_t offset = 1 << (log2W + log2H); |
88 | | |
89 | | // Get left and above reference column and row |
90 | 0 | for( int k = 0; k < width + 1; k++ ) |
91 | 0 | { |
92 | 0 | topRow[k] = pSrc.at( k + 1, 0 ); |
93 | 0 | } |
94 | |
|
95 | 0 | for( int k = 0; k < height + 1; k++ ) |
96 | 0 | { |
97 | 0 | leftColumn[k] = pSrc.at( k + 1, 1 ); |
98 | 0 | } |
99 | | |
100 | | // Prepare intermediate variables used in interpolation |
101 | 0 | int bottomLeft = leftColumn[height]; |
102 | 0 | int topRight = topRow[width]; |
103 | | |
104 | | // with some optimizations gcc-8 gives spurious "-Wmaybe-uninitialized" warnings here (says leftColumn or topRow would be uninitialized here) |
105 | 0 | GCC_WARNING_DISABLE_maybe_uninitialized |
106 | 0 | for( int k = 0; k < width; k++ ) |
107 | 0 | { |
108 | 0 | bottomRow[k] = bottomLeft - topRow[k]; |
109 | 0 | topRow[k] = topRow[k] << log2H; |
110 | 0 | } |
111 | |
|
112 | 0 | for( int k = 0; k < height; k++ ) |
113 | 0 | { |
114 | 0 | rightColumn[k] = topRight - leftColumn[k]; |
115 | 0 | leftColumn[k] = leftColumn[k] << log2W; |
116 | 0 | } |
117 | 0 | GCC_WARNING_RESET |
118 | |
|
119 | 0 | const uint32_t finalShift = 1 + log2W + log2H; |
120 | 0 | const uint32_t stride = pDst.stride; |
121 | 0 | Pel* pred = pDst.buf; |
122 | 0 | for( int y = 0; y < height; y++, pred += stride ) |
123 | 0 | { |
124 | 0 | int horPred = leftColumn[y]; |
125 | |
|
126 | 0 | for( int x = 0; x < width; x++ ) |
127 | 0 | { |
128 | 0 | horPred += rightColumn[y]; |
129 | 0 | topRow[x] += bottomRow[x]; |
130 | |
|
131 | 0 | int vertPred = topRow[x]; |
132 | 0 | pred[x] = ( ( horPred << log2H ) + ( vertPred << log2W ) + offset ) >> finalShift; |
133 | 0 | } |
134 | 0 | } |
135 | 0 | } |
136 | | |
137 | | void IntraPredSampleFilter_Core(PelBuf& dstBuf, const CPelBuf& pSrc) |
138 | 0 | { |
139 | 0 | const int iWidth = dstBuf.width; |
140 | 0 | const int iHeight = dstBuf.height; |
141 | |
|
142 | 0 | const int scale = ((Log2(iWidth*iHeight) - 2) >> 2); |
143 | 0 | CHECK(scale < 0 || scale > 31, "PDPC: scale < 0 || scale > 31"); |
144 | |
|
145 | 0 | for (int y = 0; y < iHeight; y++) |
146 | 0 | { |
147 | 0 | const int wT = 32 >> std::min(31, ((y << 1) >> scale)); |
148 | 0 | const Pel left = pSrc.at(y + 1, 1); |
149 | 0 | for (int x = 0; x < iWidth; x++) |
150 | 0 | { |
151 | 0 | const int wL = 32 >> std::min(31, ((x << 1) >> scale)); |
152 | 0 | const Pel top = pSrc.at(x + 1, 0); |
153 | 0 | const Pel val = dstBuf.at(x, y); |
154 | 0 | dstBuf.at(x, y) = val + ((wL * (left - val) + wT * (top - val) + 32) >> 6); |
155 | 0 | } |
156 | 0 | } |
157 | 0 | } |
158 | | |
159 | | void IntraHorVerPDPC_Core(Pel* pDsty,const int dstStride,Pel* refSide,const int width,const int height,int scale,const Pel* refMain, const ClpRng& clpRng) |
160 | 0 | { |
161 | 0 | const Pel topLeft = refMain[0]; |
162 | |
|
163 | 0 | for( int y = 0; y < height; y++ ) |
164 | 0 | { |
165 | 0 | memcpy(pDsty,&refMain[1],width*sizeof(Pel)); |
166 | 0 | const Pel left = refSide[1 + y]; |
167 | 0 | for (int x = 0; x < std::min(3 << scale, width); x++) |
168 | 0 | { |
169 | 0 | const int wL = 32 >> (2 * x >> scale); |
170 | 0 | const Pel val = pDsty[x]; |
171 | 0 | pDsty[x] = ClipPel(val + ((wL * (left - topLeft) + 32) >> 6), clpRng); |
172 | 0 | } |
173 | 0 | pDsty += dstStride; |
174 | 0 | } |
175 | 0 | } |
176 | | void IntraAnglePDPC_Core(Pel* pDsty,const int dstStride,Pel* refSide,const int width,const int height,int scale,int invAngle) |
177 | 0 | { |
178 | 0 | for (int y = 0; y<height; y++, pDsty += dstStride) |
179 | 0 | { |
180 | 0 | int invAngleSum = 256; |
181 | 0 | for (int x = 0; x < std::min(3 << scale, width); x++) |
182 | 0 | { |
183 | 0 | invAngleSum += invAngle; |
184 | 0 | int wL = 32 >> (2 * x >> scale); |
185 | 0 | Pel left = refSide[y + (invAngleSum >> 9) + 1]; |
186 | 0 | pDsty[x] = pDsty[x] + ((wL * (left - pDsty[x]) + 32) >> 6); |
187 | 0 | } |
188 | 0 | } |
189 | 0 | } |
190 | | |
191 | | void IntraPredAngleLuma_Core(Pel* pDstBuf,const ptrdiff_t dstStride,Pel* refMain,int width,int height,int deltaPos,int intraPredAngle,const TFilterCoeff *ff_unused,const bool useCubicFilter,const ClpRng& clpRng) |
192 | 0 | { |
193 | 0 | for (int y = 0; y<height; y++ ) |
194 | 0 | { |
195 | 0 | const int deltaInt = deltaPos >> 5; |
196 | 0 | const int deltaFract = deltaPos & ( 32 - 1 ); |
197 | |
|
198 | 0 | const TFilterCoeff intraSmoothingFilter[4] = {TFilterCoeff(16 - (deltaFract >> 1)), TFilterCoeff(32 - (deltaFract >> 1)), TFilterCoeff(16 + (deltaFract >> 1)), TFilterCoeff(deltaFract >> 1)}; |
199 | 0 | const TFilterCoeff *f = useCubicFilter ? InterpolationFilter::getChromaFilterTable(deltaFract) : intraSmoothingFilter; |
200 | |
|
201 | 0 | Pel p[4]; |
202 | |
|
203 | 0 | int refMainIndex = deltaInt + 1; |
204 | | |
205 | | // const TFilterCoeff *f = &ff[deltaFract << 2]; |
206 | |
|
207 | 0 | for( int x = 0; x < width; x++, refMainIndex++ ) |
208 | 0 | { |
209 | 0 | p[0] = refMain[refMainIndex - 1]; |
210 | 0 | p[1] = refMain[refMainIndex ]; |
211 | 0 | p[2] = refMain[refMainIndex + 1]; |
212 | 0 | p[3] = refMain[refMainIndex + 2]; |
213 | |
|
214 | 0 | pDstBuf[y*dstStride + x] = static_cast<Pel>((static_cast<int>(f[0] * p[0]) + static_cast<int>(f[1] * p[1]) + static_cast<int>(f[2] * p[2]) + static_cast<int>(f[3] * p[3]) + 32) >> 6); |
215 | |
|
216 | 0 | if( useCubicFilter ) // only cubic filter has negative coefficients and requires clipping |
217 | 0 | { |
218 | 0 | pDstBuf[y*dstStride + x] = ClipPel( pDstBuf[y*dstStride + x], clpRng ); |
219 | 0 | } |
220 | 0 | } |
221 | 0 | deltaPos += intraPredAngle; |
222 | 0 | } |
223 | 0 | } |
224 | | |
225 | | void IntraPredAngleChroma_Core(Pel* pDstBuf,const ptrdiff_t dstStride,int16_t* pBorder,int width,int height,int deltaPos,int intraPredAngle) |
226 | 0 | { |
227 | 0 | for (int y = 0; y<height; y++) |
228 | 0 | { |
229 | 0 | const int deltaInt = deltaPos >> 5; |
230 | 0 | const int deltaFract = deltaPos & (32 - 1); |
231 | | |
232 | | // Do linear filtering |
233 | 0 | const Pel* pRM = pBorder + deltaInt + 1; |
234 | 0 | int lastRefMainPel = *pRM++; |
235 | |
|
236 | 0 | for( int x = 0; x < width; pRM++, x++ ) |
237 | 0 | { |
238 | 0 | int thisRefMainPel = *pRM; |
239 | 0 | pDstBuf[x + 0] = ( Pel ) ( ( ( 32 - deltaFract )*lastRefMainPel + deltaFract*thisRefMainPel + 16 ) >> 5 ); |
240 | 0 | lastRefMainPel = thisRefMainPel; |
241 | 0 | } |
242 | 0 | deltaPos += intraPredAngle; |
243 | 0 | pDstBuf += dstStride; |
244 | 0 | } |
245 | 0 | } |
246 | | |
247 | | // ==================================================================================================================== |
248 | | // Constructor / destructor / initialize |
249 | | // ==================================================================================================================== |
250 | | |
251 | | IntraPrediction::IntraPrediction( bool enableOpt ) |
252 | 0 | : m_pMdlmTemp( nullptr ) |
253 | 0 | , m_currChromaFormat( NUM_CHROMA_FORMAT ) |
254 | 0 | { |
255 | 0 | IntraPredAngleLuma = IntraPredAngleLuma_Core; |
256 | 0 | IntraPredAngleChroma = IntraPredAngleChroma_Core; |
257 | 0 | IntraAnglePDPC = IntraAnglePDPC_Core; |
258 | 0 | IntraHorVerPDPC = IntraHorVerPDPC_Core; |
259 | 0 | IntraPredSampleFilter = IntraPredSampleFilter_Core; |
260 | 0 | xPredIntraPlanar = xPredIntraPlanar_Core; |
261 | |
|
262 | 0 | #if ENABLE_SIMD_OPT_INTRAPRED |
263 | 0 | if( enableOpt ) |
264 | 0 | { |
265 | 0 | #if defined( TARGET_SIMD_X86 ) |
266 | 0 | initIntraPredictionX86(); |
267 | 0 | #endif |
268 | | #if defined( TARGET_SIMD_ARM ) |
269 | | initIntraPredictionARM(); |
270 | | #endif |
271 | 0 | } |
272 | 0 | #endif // ENABLE_SIMD_OPT_INTRAPRED |
273 | 0 | } |
274 | | |
275 | | IntraPrediction::~IntraPrediction() |
276 | 0 | { |
277 | 0 | destroy(); |
278 | 0 | } |
279 | | |
280 | | void IntraPrediction::destroy() |
281 | 0 | { |
282 | 0 | delete[] m_pMdlmTemp; |
283 | 0 | m_pMdlmTemp = nullptr; |
284 | 0 | } |
285 | | |
286 | | void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepthY) |
287 | 0 | { |
288 | 0 | m_currChromaFormat = chromaFormatIDC; |
289 | |
|
290 | 0 | if (m_pMdlmTemp == nullptr) |
291 | 0 | { |
292 | 0 | m_pMdlmTemp = new Pel[(2 * MAX_TB_SIZEY + 1)*(2 * MAX_TB_SIZEY + 1)];//MDLM will use top-above and left-below samples. |
293 | 0 | } |
294 | 0 | } |
295 | | |
296 | | // ==================================================================================================================== |
297 | | // Public member functions |
298 | | // ==================================================================================================================== |
299 | | |
300 | | // Function for calculating DC value of the reference samples used in Intra prediction |
301 | | //NOTE: Bit-Limit - 25-bit source |
302 | | Pel IntraPrediction::xGetPredValDc( const CPelBuf& pSrc, const Size& dstSize ) |
303 | 0 | { |
304 | 0 | CHECK( dstSize.width == 0 || dstSize.height == 0, "Empty area provided" ); |
305 | |
|
306 | 0 | int idx, sum = 0; |
307 | 0 | Pel dcVal; |
308 | 0 | const int width = dstSize.width; |
309 | 0 | const int height = dstSize.height; |
310 | 0 | const auto denom = (width == height) ? (width << 1) : std::max(width,height); |
311 | 0 | const auto divShift = Log2(denom); |
312 | 0 | const auto divOffset = (denom >> 1); |
313 | 0 | const int off = m_ipaParam.multiRefIndex + 1; |
314 | | |
315 | |
|
316 | 0 | if ( width >= height ) |
317 | 0 | { |
318 | 0 | for( idx = 0; idx < width; idx++ ) |
319 | 0 | { |
320 | 0 | sum += pSrc.at( off + idx, 0); |
321 | 0 | } |
322 | 0 | } |
323 | 0 | if ( width <= height ) |
324 | 0 | { |
325 | 0 | for( idx = 0; idx < height; idx++ ) |
326 | 0 | { |
327 | 0 | sum += pSrc.at( off + idx, 1); |
328 | 0 | } |
329 | 0 | } |
330 | |
|
331 | 0 | dcVal = (sum + divOffset) >> divShift; |
332 | 0 | return dcVal; |
333 | 0 | } |
334 | | |
335 | | int IntraPrediction::getWideAngle( int width, int height, int predMode ) |
336 | 0 | { |
337 | 0 | if ( predMode > DC_IDX && predMode <= VDIA_IDX ) |
338 | 0 | { |
339 | 0 | int modeShift[] = { 0, 6, 10, 12, 14, 15 }; |
340 | 0 | int deltaSize = abs(Log2(width) - Log2(height)); |
341 | 0 | if (width > height && predMode < 2 + modeShift[deltaSize]) |
342 | 0 | { |
343 | 0 | predMode += (VDIA_IDX - 1); |
344 | 0 | } |
345 | 0 | else if (height > width && predMode > VDIA_IDX - modeShift[deltaSize]) |
346 | 0 | { |
347 | 0 | predMode -= (VDIA_IDX - 1); |
348 | 0 | } |
349 | 0 | } |
350 | 0 | return predMode; |
351 | 0 | } |
352 | | |
353 | | void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf& piPred, const CodingUnit& cu) |
354 | 0 | { |
355 | 0 | const ComponentID compID = compId; |
356 | 0 | const ChannelType channelType = toChannelType( compID ); |
357 | 0 | const uint32_t uiDirMode = cu.bdpcmM[channelType] ? BDPCM_IDX : CU::getFinalIntraMode(cu, channelType); |
358 | |
|
359 | 0 | CHECK( Log2(piPred.width) > 7, "Size not allowed" ); |
360 | | |
361 | | // const int multiRefIdx = m_ipaParam.multiRefIndex; |
362 | 0 | const int srcStride = m_refBufferStride[compID]; |
363 | 0 | const int srcHStride = 2; |
364 | |
|
365 | 0 | const CPelBuf& srcBuf = CPelBuf(getPredictorPtr(compID), srcStride, srcHStride); |
366 | 0 | const ClpRng& clpRng(cu.cs->slice->clpRngs[compID]); |
367 | |
|
368 | 0 | switch (uiDirMode) |
369 | 0 | { |
370 | 0 | case(PLANAR_IDX): xPredIntraPlanar(piPred, srcBuf); break; |
371 | 0 | case(DC_IDX): xPredIntraDc ( piPred, srcBuf ); break; |
372 | 0 | case(BDPCM_IDX): xPredIntraBDPCM ( piPred, srcBuf, cu.bdpcmM[channelType], clpRng); break; |
373 | 0 | default: xPredIntraAng ( piPred, srcBuf, channelType, clpRng); break; |
374 | 0 | } |
375 | | |
376 | 0 | if (m_ipaParam.applyPDPC) |
377 | 0 | { |
378 | 0 | if (uiDirMode == PLANAR_IDX || uiDirMode == DC_IDX) |
379 | 0 | { |
380 | 0 | IntraPredSampleFilter(piPred, srcBuf); |
381 | 0 | } |
382 | 0 | } |
383 | 0 | } |
384 | | |
385 | | void IntraPrediction::predIntraChromaLM(const ComponentID compID, PelBuf& piPred, const CodingUnit& cu, const CompArea& chromaArea, int intraDir) |
386 | 0 | { |
387 | 0 | CHECK( piPred.width > MAX_TB_SIZEY || piPred.height > MAX_TB_SIZEY, "not enough memory"); |
388 | 0 | const int iLumaStride = 2 * MAX_TB_SIZEY + 1; |
389 | 0 | PelBuf Temp = PelBuf(m_pMdlmTemp + iLumaStride + 1, iLumaStride, Size(chromaArea)); |
390 | |
|
391 | 0 | int a, b, iShift; |
392 | 0 | xGetLMParameters(cu, compID, chromaArea, a, b, iShift); // th shift result is unsigned |
393 | | |
394 | | ////// final prediction |
395 | 0 | piPred.copyFrom(Temp); |
396 | 0 | piPred.linearTransform(a, iShift, b, true, cu.cs->slice->clpRngs[compID]); |
397 | 0 | } |
398 | | |
399 | | /** Function for deriving planar intra prediction. This function derives the prediction samples for planar mode (intra coding). |
400 | | */ |
401 | | |
402 | | void IntraPrediction::xPredIntraDc( PelBuf& pDst, const CPelBuf& pSrc ) |
403 | 0 | { |
404 | 0 | const Pel dcval = xGetPredValDc( pSrc, pDst ); |
405 | 0 | pDst.fill( dcval ); |
406 | 0 | } |
407 | | |
408 | | // Function for initialization of intra prediction parameters |
409 | | void IntraPrediction::initPredIntraParams(const CodingUnit& cu, const CompArea area, const SPS& sps) |
410 | 0 | { |
411 | 0 | const ComponentID compId = area.compID; |
412 | 0 | const ChannelType chType = toChannelType(compId); |
413 | |
|
414 | 0 | const bool useISP = NOT_INTRA_SUBPARTITIONS != cu.ispMode && isLuma( chType ); |
415 | |
|
416 | 0 | const Size cuSize = Size( cu.blocks[compId].width, cu.blocks[compId].height ); |
417 | 0 | const Size puSize = Size( area.width, area.height ); |
418 | 0 | const Size& blockSize = useISP ? cuSize : puSize; |
419 | 0 | const int dirMode = CU::getFinalIntraMode(cu, chType); |
420 | 0 | const int predMode = getWideAngle( blockSize.width, blockSize.height, dirMode ); |
421 | |
|
422 | 0 | m_ipaParam.isModeVer = predMode >= DIA_IDX; |
423 | 0 | m_ipaParam.multiRefIndex = isLuma (chType) ? cu.multiRefIdx : 0 ; |
424 | 0 | m_ipaParam.refFilterFlag = false; |
425 | 0 | m_ipaParam.interpolationFlag = false; |
426 | 0 | m_ipaParam.applyPDPC = (puSize.width >= MIN_TB_SIZEY && puSize.height >= MIN_TB_SIZEY) && m_ipaParam.multiRefIndex == 0; |
427 | |
|
428 | 0 | const int intraPredAngleMode = (m_ipaParam.isModeVer) ? predMode - VER_IDX : -(predMode - HOR_IDX); |
429 | | |
430 | |
|
431 | 0 | int absAng = 0; |
432 | 0 | if (dirMode > DC_IDX && dirMode < NUM_LUMA_MODE) // intraPredAngle for directional modes |
433 | 0 | { |
434 | 0 | static const int angTable[32] = { 0, 1, 2, 3, 4, 6, 8, 10, 12, 14, 16, 18, 20, 23, 26, 29, 32, 35, 39, 45, 51, 57, 64, 73, 86, 102, 128, 171, 256, 341, 512, 1024 }; |
435 | 0 | static const int invAngTable[32] = { |
436 | 0 | 0, 16384, 8192, 5461, 4096, 2731, 2048, 1638, 1365, 1170, 1024, 910, 819, 712, 630, 565, |
437 | 0 | 512, 468, 420, 364, 321, 287, 256, 224, 191, 161, 128, 96, 64, 48, 32, 16 |
438 | 0 | }; // (512 * 32) / Angle |
439 | |
|
440 | 0 | const int absAngMode = abs(intraPredAngleMode); |
441 | 0 | const int signAng = intraPredAngleMode < 0 ? -1 : 1; |
442 | 0 | absAng = angTable [absAngMode]; |
443 | |
|
444 | 0 | m_ipaParam.absInvAngle = invAngTable[absAngMode]; |
445 | 0 | m_ipaParam.intraPredAngle = signAng * absAng; |
446 | 0 | if (intraPredAngleMode < 0) |
447 | 0 | { |
448 | 0 | m_ipaParam.applyPDPC = false; |
449 | 0 | } |
450 | 0 | else if (intraPredAngleMode > 0) |
451 | 0 | { |
452 | 0 | const int sideSize = m_ipaParam.isModeVer ? puSize.height : puSize.width; |
453 | 0 | const int maxScale = 2; |
454 | |
|
455 | 0 | m_ipaParam.angularScale = std::min(maxScale, floorLog2(sideSize) - (floorLog2(3 * m_ipaParam.absInvAngle - 2) - 8)); |
456 | 0 | m_ipaParam.applyPDPC &= m_ipaParam.angularScale >= 0; |
457 | 0 | } |
458 | 0 | } |
459 | | |
460 | | // high level conditions and DC intra prediction |
461 | 0 | if( !isLuma( chType ) |
462 | 0 | || useISP |
463 | 0 | || CU::isMIP( cu, chType ) //th remove this |
464 | 0 | || m_ipaParam.multiRefIndex |
465 | 0 | || DC_IDX == dirMode |
466 | 0 | ) |
467 | 0 | { |
468 | 0 | } |
469 | 0 | else if (cu.bdpcmM[chType]) |
470 | 0 | { |
471 | 0 | m_ipaParam.refFilterFlag = false; |
472 | 0 | } |
473 | 0 | else if (dirMode == PLANAR_IDX) // Planar intra prediction |
474 | 0 | { |
475 | 0 | m_ipaParam.refFilterFlag = puSize.width * puSize.height > 32 ? true : false; |
476 | 0 | } |
477 | 0 | else if (!useISP)// HOR, VER and angular modes (MDIS) |
478 | 0 | { |
479 | 0 | bool filterFlag = false; |
480 | 0 | { |
481 | 0 | const int diff = std::min<int>( abs( predMode - HOR_IDX ), abs( predMode - VER_IDX ) ); |
482 | 0 | const int log2Size = (Log2(puSize.width * puSize.height) >> 1); |
483 | 0 | CHECK( log2Size >= MAX_INTRA_FILTER_DEPTHS, "Size not supported" ); |
484 | 0 | filterFlag = (diff > m_aucIntraFilter[log2Size]); |
485 | 0 | } |
486 | | |
487 | | // Selelection of either ([1 2 1] / 4 ) refrence filter OR Gaussian 4-tap interpolation filter |
488 | 0 | if (filterFlag) |
489 | 0 | { |
490 | 0 | const bool isRefFilter = isIntegerSlope(absAng); |
491 | 0 | CHECK( puSize.width * puSize.height <= 32, "DCT-IF interpolation filter is always used for 4x4, 4x8, and 8x4 luma CB" ); |
492 | 0 | m_ipaParam.refFilterFlag = isRefFilter; |
493 | 0 | m_ipaParam.interpolationFlag = !isRefFilter; |
494 | 0 | } |
495 | 0 | } |
496 | 0 | } |
497 | | |
498 | | } // namespace vvenc |
499 | | |
500 | | #ifdef TARGET_SIMD_X86 |
501 | | #include "x86/CommonDefX86.h" |
502 | | #endif |
503 | | |
504 | | namespace vvenc { |
505 | | |
506 | | /** Function for deriving the simplified angular intra predictions. |
507 | | * |
508 | | * This function derives the prediction samples for the angular mode based on the prediction direction indicated by |
509 | | * the prediction mode index. The prediction direction is given by the displacement of the bottom row of the block and |
510 | | * the reference row above the block in the case of vertical prediction or displacement of the rightmost column |
511 | | * of the block and reference column left from the block in the case of the horizontal prediction. The displacement |
512 | | * is signalled at 1/32 pixel accuracy. When projection of the predicted pixel falls inbetween reference samples, |
513 | | * the predicted value for the pixel is linearly interpolated from the reference samples. All reference samples are taken |
514 | | * from the extended main reference. |
515 | | */ |
516 | | //NOTE: Bit-Limit - 25-bit source |
517 | | |
518 | | void IntraPrediction::xPredIntraAng( PelBuf& pDst, const CPelBuf& pSrc, const ChannelType channelType, const ClpRng& clpRng) |
519 | 0 | { |
520 | 0 | int width =int(pDst.width); |
521 | 0 | int height=int(pDst.height); |
522 | |
|
523 | 0 | const bool bIsModeVer = m_ipaParam.isModeVer; |
524 | 0 | const int multiRefIdx = m_ipaParam.multiRefIndex; |
525 | 0 | const int intraPredAngle = m_ipaParam.intraPredAngle; |
526 | 0 | const int absInvAngle = m_ipaParam.absInvAngle; |
527 | |
|
528 | 0 | Pel* refMain; |
529 | 0 | Pel* refSide; |
530 | |
|
531 | 0 | Pel refAbove[2 * MAX_CU_SIZE + 3 + 33 * MAX_REF_LINE_IDX]; |
532 | 0 | Pel refLeft [2 * MAX_CU_SIZE + 3 + 33 * MAX_REF_LINE_IDX]; |
533 | | |
534 | | // Initialize the Main and Left reference array. |
535 | 0 | if (intraPredAngle < 0) |
536 | 0 | { |
537 | 0 | memcpy(&refAbove[height],pSrc.buf,(width + 2 + multiRefIdx)*sizeof(Pel)); |
538 | 0 | for (int y = 0; y <= height + 1 + multiRefIdx; y++) |
539 | 0 | { |
540 | 0 | refLeft[y + width] = pSrc.at(y, 1); |
541 | 0 | } |
542 | 0 | refMain = bIsModeVer ? refAbove + height : refLeft + width; |
543 | 0 | refSide = bIsModeVer ? refLeft + width : refAbove + height; |
544 | | |
545 | | // Extend the Main reference to the left. |
546 | 0 | int sizeSide = bIsModeVer ? height : width; |
547 | 0 | for (int k = -sizeSide; k <= -1; k++) |
548 | 0 | { |
549 | 0 | refMain[k] = refSide[std::min((-k * absInvAngle + 256) >> 9, sizeSide)]; |
550 | 0 | } |
551 | 0 | } |
552 | 0 | else |
553 | 0 | { |
554 | 0 | memcpy(&refAbove[0], pSrc.buf, ((m_topRefLength)+multiRefIdx + 1) * sizeof(Pel)); |
555 | 0 | for (int y = 0; y <= m_leftRefLength + multiRefIdx; y++) |
556 | 0 | { |
557 | 0 | refLeft[y] = pSrc.at(y, 1); |
558 | 0 | } |
559 | |
|
560 | 0 | refMain = bIsModeVer ? refAbove : refLeft; |
561 | 0 | refSide = bIsModeVer ? refLeft : refAbove; |
562 | | |
563 | | // Extend main reference to right using replication |
564 | 0 | const int log2Ratio = Log2(width) - Log2(height); |
565 | 0 | const int s = std::max<int>(0, bIsModeVer ? log2Ratio : -log2Ratio); |
566 | 0 | const int maxIndex = (multiRefIdx << s) + 2; |
567 | 0 | const int refLength = bIsModeVer ? m_topRefLength : m_leftRefLength; |
568 | 0 | const Pel val = refMain[refLength + multiRefIdx]; |
569 | 0 | for (int z = 1; z <= maxIndex; z++) |
570 | 0 | { |
571 | 0 | refMain[refLength + multiRefIdx + z] = val; |
572 | 0 | } |
573 | 0 | } |
574 | | |
575 | | // swap width/height if we are doing a horizontal mode: |
576 | 0 | if (!bIsModeVer) |
577 | 0 | { |
578 | 0 | std::swap(width, height); |
579 | 0 | } |
580 | 0 | Pel tempArray[MAX_CU_SIZE*MAX_CU_SIZE]; |
581 | 0 | const int dstStride = bIsModeVer ? pDst.stride : MAX_CU_SIZE; |
582 | 0 | Pel* pDstBuf = bIsModeVer ? pDst.buf : tempArray; |
583 | | |
584 | | // compensate for line offset in reference line buffers |
585 | 0 | refMain += multiRefIdx; |
586 | 0 | refSide += multiRefIdx; |
587 | |
|
588 | 0 | Pel* pDsty = pDstBuf; |
589 | |
|
590 | 0 | if( intraPredAngle == 0 ) // pure vertical or pure horizontal |
591 | 0 | { |
592 | 0 | if (m_ipaParam.applyPDPC) |
593 | 0 | { |
594 | 0 | const int scale = (Log2(width * height) - 2) >> 2; |
595 | 0 | IntraHorVerPDPC(pDsty,dstStride,refSide,width,height,scale,refMain,clpRng); |
596 | 0 | } |
597 | 0 | else |
598 | 0 | { |
599 | 0 | for( int y = 0; y < height; y++ ) |
600 | 0 | { |
601 | 0 | memcpy(pDsty,&refMain[1],width*sizeof(Pel)); |
602 | 0 | pDsty += dstStride; |
603 | 0 | } |
604 | 0 | } |
605 | 0 | } |
606 | 0 | else |
607 | 0 | { |
608 | 0 | if( !isIntegerSlope( abs( intraPredAngle ) ) ) |
609 | 0 | { |
610 | 0 | int deltaPos = intraPredAngle * ( 1 + multiRefIdx ); |
611 | 0 | if( isLuma( channelType ) ) |
612 | 0 | { |
613 | 0 | if( width <= 2 ) |
614 | 0 | { |
615 | 0 | for( int y = 0, deltaPos = intraPredAngle * ( 1 + multiRefIdx ); |
616 | 0 | y < height; |
617 | 0 | y++, deltaPos += intraPredAngle, pDsty += dstStride ) |
618 | 0 | { |
619 | 0 | const int deltaInt = deltaPos >> 5; |
620 | 0 | const int deltaFract = deltaPos & 31; |
621 | |
|
622 | 0 | if( !isIntegerSlope( abs( intraPredAngle ) ) ) |
623 | 0 | { |
624 | 0 | const bool useCubicFilter = !m_ipaParam.interpolationFlag; |
625 | |
|
626 | 0 | const TFilterCoeff intraSmoothingFilter[4] = { TFilterCoeff( 16 - ( deltaFract >> 1 ) ), |
627 | 0 | TFilterCoeff( 32 - ( deltaFract >> 1 ) ), |
628 | 0 | TFilterCoeff( 16 + ( deltaFract >> 1 ) ), |
629 | 0 | TFilterCoeff( ( deltaFract >> 1 ) ) }; |
630 | 0 | const TFilterCoeff* const f = |
631 | 0 | ( useCubicFilter ) ? InterpolationFilter::getChromaFilterTable( deltaFract ) : intraSmoothingFilter; |
632 | |
|
633 | 0 | for( int x = 0; x < width; x++ ) |
634 | 0 | { |
635 | 0 | Pel p[4]; |
636 | |
|
637 | 0 | p[0] = refMain[deltaInt + x + 0]; |
638 | 0 | p[1] = refMain[deltaInt + x + 1]; |
639 | 0 | p[2] = refMain[deltaInt + x + 2]; |
640 | 0 | p[3] = refMain[deltaInt + x + 3]; |
641 | |
|
642 | 0 | Pel val = ( f[0] * p[0] + f[1] * p[1] + f[2] * p[2] + f[3] * p[3] + 32 ) >> 6; |
643 | |
|
644 | 0 | pDsty[x] = ClipPel( val, clpRng ); // always clip even though not always needed |
645 | 0 | } |
646 | 0 | } |
647 | 0 | } |
648 | 0 | } |
649 | 0 | else |
650 | 0 | { |
651 | 0 | IntraPredAngleLuma(pDstBuf, dstStride, refMain, width, height, deltaPos, intraPredAngle, nullptr, !m_ipaParam.interpolationFlag, clpRng); |
652 | 0 | } |
653 | 0 | } |
654 | 0 | else |
655 | 0 | { |
656 | 0 | IntraPredAngleChroma(pDstBuf,dstStride,refMain,width,height,deltaPos,intraPredAngle); |
657 | 0 | } |
658 | 0 | } |
659 | 0 | else |
660 | 0 | { |
661 | 0 | for (int y = 0, deltaPos = intraPredAngle * (1 + multiRefIdx); y<height; y++, deltaPos += intraPredAngle, pDsty += dstStride) |
662 | 0 | { |
663 | 0 | const int deltaInt = deltaPos >> 5; |
664 | | // Just copy the integer samples |
665 | 0 | memcpy(pDsty,refMain + deltaInt + 1,width*sizeof(Pel)); |
666 | 0 | } |
667 | 0 | } |
668 | |
|
669 | 0 | if (m_ipaParam.applyPDPC) |
670 | 0 | { |
671 | 0 | pDsty = pDstBuf; |
672 | 0 | IntraAnglePDPC(pDsty,dstStride,refSide,width,height,m_ipaParam.angularScale,absInvAngle); |
673 | 0 | } |
674 | 0 | } // else |
675 | | |
676 | | // Flip the block if this is the horizontal mode |
677 | 0 | if( !bIsModeVer ) |
678 | 0 | { |
679 | 0 | pDst.transposedFrom( CPelBuf( pDstBuf, dstStride, width, height) ); |
680 | 0 | } |
681 | 0 | } |
682 | | |
683 | | void IntraPrediction::xPredIntraBDPCM(PelBuf& pDst, const CPelBuf& pSrc, const uint32_t dirMode, const ClpRng& clpRng) |
684 | 0 | { |
685 | 0 | const int wdt = pDst.width; |
686 | 0 | const int hgt = pDst.height; |
687 | |
|
688 | 0 | const int strideP = pDst.stride; |
689 | 0 | const int strideS = pSrc.stride; |
690 | |
|
691 | 0 | CHECK(!(dirMode == 1 || dirMode == 2), "Incorrect BDPCM mode parameter."); |
692 | |
|
693 | 0 | Pel* pred = &pDst.buf[0]; |
694 | 0 | if (dirMode == 1) |
695 | 0 | { |
696 | 0 | Pel val; |
697 | 0 | for (int y = 0; y < hgt; y++) |
698 | 0 | { |
699 | 0 | val = pSrc.buf[(y + 1) + strideS]; |
700 | 0 | for (int x = 0; x < wdt; x++) |
701 | 0 | { |
702 | 0 | pred[x] = val; |
703 | 0 | } |
704 | 0 | pred += strideP; |
705 | 0 | } |
706 | 0 | } |
707 | 0 | else |
708 | 0 | { |
709 | 0 | for (int y = 0; y < hgt; y++) |
710 | 0 | { |
711 | 0 | for (int x = 0; x < wdt; x++) |
712 | 0 | { |
713 | 0 | pred[x] = pSrc.buf[x + 1]; |
714 | 0 | } |
715 | 0 | pred += strideP; |
716 | 0 | } |
717 | 0 | } |
718 | 0 | } |
719 | | |
720 | | inline bool isAboveLeftAvailable ( const CodingUnit &cu, const ChannelType& chType, const Position& posLT ); |
721 | | inline int isAboveAvailable ( const CodingUnit &cu, const ChannelType& chType, const Position& posLT, const uint32_t numUnits, const uint32_t unitWidth, bool *validFlags ); |
722 | | inline int isLeftAvailable ( const CodingUnit &cu, const ChannelType& chType, const Position& posLT, const uint32_t numUnits, const uint32_t unitWidth, bool *validFlags ); |
723 | | inline int isAboveRightAvailable ( const CodingUnit &cu, const ChannelType& chType, const Position& posRT, const uint32_t numUnits, const uint32_t unitHeight, bool *validFlags ); |
724 | | inline int isBelowLeftAvailable ( const CodingUnit &cu, const ChannelType& chType, const Position& posLB, const uint32_t numUnits, const uint32_t unitHeight, bool *validFlags ); |
725 | | |
726 | | void IntraPrediction::initIntraPatternChType(const CodingUnit &cu, const CompArea& area, const bool forceRefFilterFlag) |
727 | 0 | { |
728 | 0 | const CodingStructure& cs = *cu.cs; |
729 | |
|
730 | 0 | if (!forceRefFilterFlag) |
731 | 0 | { |
732 | 0 | initPredIntraParams(cu, area, *cs.sps); |
733 | 0 | } |
734 | |
|
735 | 0 | Pel *refBufUnfiltered = m_refBuffer[area.compID][PRED_BUF_UNFILTERED]; |
736 | 0 | Pel *refBufFiltered = m_refBuffer[area.compID][PRED_BUF_FILTERED]; |
737 | |
|
738 | 0 | setReferenceArrayLengths(area); |
739 | | |
740 | | // ----- Step 1: unfiltered reference samples ----- |
741 | 0 | xFillReferenceSamples( cs.picture->getRecoBuf( area ), refBufUnfiltered, area, cu ); |
742 | | // ----- Step 2: filtered reference samples ----- |
743 | 0 | if( m_ipaParam.refFilterFlag || forceRefFilterFlag ) |
744 | 0 | { |
745 | 0 | xFilterReferenceSamples( refBufUnfiltered, refBufFiltered, area, *cs.sps, cu.multiRefIdx ); |
746 | 0 | } |
747 | 0 | } |
748 | | |
749 | | void IntraPrediction::reset() |
750 | 0 | { |
751 | 0 | m_lastCh = MAX_NUM_CH; |
752 | 0 | m_lastArea = Area(0,0,0,0); |
753 | 0 | } |
754 | | |
755 | | void IntraPrediction::xFillReferenceSamples( const CPelBuf& recoBuf, Pel* refBufUnfiltered, const CompArea& area, const CodingUnit &cu ) |
756 | 0 | { |
757 | 0 | const ChannelType chType = toChannelType( area.compID ); |
758 | 0 | const CodingStructure &cs = *cu.cs; |
759 | 0 | const SPS &sps = *cs.sps; |
760 | 0 | const PreCalcValues &pcv = *cs.pcv; |
761 | |
|
762 | 0 | const int multiRefIdx = (area.compID == COMP_Y) ? cu.multiRefIdx : 0; |
763 | |
|
764 | 0 | const int tuWidth = area.width; |
765 | 0 | const int tuHeight = area.height; |
766 | 0 | const int predSize = m_topRefLength; |
767 | 0 | const int predHSize = m_leftRefLength; |
768 | 0 | const int predStride = predSize + 1 + multiRefIdx; |
769 | 0 | m_refBufferStride[area.compID] = predStride; |
770 | |
|
771 | 0 | const int unitWidth = tuWidth <= 2 && cu.ispMode && isLuma(area.compID) ? tuWidth : pcv.minCUSize >> getComponentScaleX(area.compID, sps.chromaFormatIdc); |
772 | 0 | const int unitHeight = tuHeight <= 2 && cu.ispMode && isLuma(area.compID) ? tuHeight : pcv.minCUSize >> getComponentScaleY(area.compID, sps.chromaFormatIdc); |
773 | |
|
774 | 0 | const int totalAboveUnits = (predSize + (unitWidth - 1)) / unitWidth; |
775 | 0 | const int totalLeftUnits = (predHSize + (unitHeight - 1)) / unitHeight; |
776 | 0 | const int totalUnits = totalAboveUnits + totalLeftUnits + 1; //+1 for top-left |
777 | |
|
778 | 0 | if( m_lastArea != area || m_lastCh != chType ) |
779 | 0 | { |
780 | 0 | m_lastCh = chType; |
781 | 0 | m_lastArea = area; |
782 | 0 | const int numAboveUnits = std::max<int>( tuWidth / unitWidth, 1 ); |
783 | 0 | const int numLeftUnits = std::max<int>( tuHeight / unitHeight, 1 ); |
784 | 0 | const int numAboveRightUnits = totalAboveUnits - numAboveUnits; |
785 | 0 | const int numLeftBelowUnits = totalLeftUnits - numLeftUnits; |
786 | |
|
787 | 0 | CHECK( numAboveUnits <= 0 || numLeftUnits <= 0 || numAboveRightUnits <= 0 || numLeftBelowUnits <= 0, "Size not supported" ); |
788 | | |
789 | | // ----- Step 1: analyze neighborhood ----- |
790 | 0 | const Position posLT = area; |
791 | 0 | const Position posRT = area.topRight(); |
792 | 0 | const Position posLB = area.bottomLeft(); |
793 | |
|
794 | 0 | m_numIntraNeighbor = 0; |
795 | |
|
796 | 0 | memset( m_neighborFlags, 0, totalUnits ); |
797 | |
|
798 | 0 | m_neighborFlags[totalLeftUnits] = isAboveLeftAvailable( cu, chType, posLT ); |
799 | 0 | m_numIntraNeighbor += m_neighborFlags[totalLeftUnits] ? 1 : 0; |
800 | 0 | m_numIntraNeighbor += isAboveAvailable ( cu, chType, posLT, numAboveUnits, unitWidth, (m_neighborFlags + totalLeftUnits + 1) ); |
801 | 0 | m_numIntraNeighbor += isAboveRightAvailable( cu, chType, posRT, numAboveRightUnits, unitWidth, (m_neighborFlags + totalLeftUnits + 1 + numAboveUnits) ); |
802 | 0 | m_numIntraNeighbor += isLeftAvailable ( cu, chType, posLT, numLeftUnits, unitHeight, (m_neighborFlags + totalLeftUnits - 1) ); |
803 | 0 | m_numIntraNeighbor += isBelowLeftAvailable ( cu, chType, posLB, numLeftBelowUnits, unitHeight, (m_neighborFlags + totalLeftUnits - 1 - numLeftUnits) ); |
804 | 0 | } |
805 | | // ----- Step 2: fill reference samples (depending on neighborhood) ----- |
806 | | |
807 | 0 | const Pel* srcBuf = recoBuf.buf; |
808 | 0 | const int srcStride = recoBuf.stride; |
809 | 0 | Pel* ptrDst = refBufUnfiltered; |
810 | 0 | const Pel* ptrSrc; |
811 | 0 | const Pel valueDC = 1 << (sps.bitDepths[ chType ] - 1); |
812 | | |
813 | |
|
814 | 0 | if( m_numIntraNeighbor == 0 ) |
815 | 0 | { |
816 | | // Fill border with DC value |
817 | 0 | for (int j = 0; j <= predSize + multiRefIdx; j++) { ptrDst[j] = valueDC; } |
818 | 0 | for (int i = 0; i <= predHSize + multiRefIdx; i++) { ptrDst[i+predStride] = valueDC; } |
819 | 0 | } |
820 | 0 | else if( m_numIntraNeighbor == totalUnits ) |
821 | 0 | { |
822 | | // Fill top-left border and top and top right with rec. samples |
823 | 0 | ptrSrc = srcBuf - (1 + multiRefIdx) * srcStride - (1 + multiRefIdx); |
824 | 0 | for (int j = 0; j <= predSize + multiRefIdx; j++) { ptrDst[j] = ptrSrc[j]; } |
825 | 0 | for (int i = 0; i <= predHSize + multiRefIdx; i++) |
826 | 0 | { |
827 | 0 | ptrDst[i + predStride] = ptrSrc[i * srcStride]; |
828 | 0 | } |
829 | 0 | } |
830 | 0 | else // reference samples are partially available |
831 | 0 | { |
832 | | // Fill top-left sample(s) if available |
833 | 0 | ptrSrc = srcBuf - (1 + multiRefIdx) * srcStride - (1 + multiRefIdx); |
834 | 0 | ptrDst = refBufUnfiltered; |
835 | 0 | if (m_neighborFlags[totalLeftUnits]) |
836 | 0 | { |
837 | 0 | ptrDst[0] = ptrSrc[0]; |
838 | 0 | ptrDst[predStride] = ptrSrc[0]; |
839 | 0 | for (int i = 1; i <= multiRefIdx; i++) |
840 | 0 | { |
841 | 0 | ptrDst[i] = ptrSrc[i]; |
842 | 0 | ptrDst[i + predStride] = ptrSrc[i * srcStride]; |
843 | 0 | } |
844 | 0 | } |
845 | | |
846 | | // Fill left & below-left samples if available (downwards) |
847 | 0 | ptrSrc += (1 + multiRefIdx) * srcStride; |
848 | 0 | ptrDst += (1 + multiRefIdx) + predStride; |
849 | 0 | for (int unitIdx = totalLeftUnits - 1; unitIdx > 0; unitIdx--) |
850 | 0 | { |
851 | 0 | if (m_neighborFlags[unitIdx]) |
852 | 0 | { |
853 | 0 | for (int i = 0; i < unitHeight; i++) |
854 | 0 | { |
855 | 0 | ptrDst[i] = ptrSrc[i*srcStride]; |
856 | 0 | } |
857 | 0 | } |
858 | 0 | ptrSrc += unitHeight * srcStride; |
859 | 0 | ptrDst += unitHeight; |
860 | 0 | } |
861 | | // Fill last below-left sample(s) |
862 | 0 | if (m_neighborFlags[0]) |
863 | 0 | { |
864 | 0 | int lastSample = (predHSize % unitHeight == 0) ? unitHeight : predHSize % unitHeight; |
865 | 0 | for (int i = 0; i < lastSample; i++) |
866 | 0 | { |
867 | 0 | ptrDst[i] = ptrSrc[i*srcStride]; |
868 | 0 | } |
869 | 0 | } |
870 | | |
871 | | // Fill above & above-right samples if available (left-to-right) |
872 | 0 | ptrSrc = srcBuf - srcStride * (1 + multiRefIdx); |
873 | 0 | ptrDst = refBufUnfiltered + 1 + multiRefIdx; |
874 | 0 | for (int unitIdx = totalLeftUnits + 1; unitIdx < totalUnits - 1; unitIdx++) |
875 | 0 | { |
876 | 0 | if (m_neighborFlags[unitIdx]) |
877 | 0 | { |
878 | 0 | memcpy(ptrDst,ptrSrc,unitWidth*sizeof(Pel)); |
879 | 0 | } |
880 | 0 | ptrSrc += unitWidth; |
881 | 0 | ptrDst += unitWidth; |
882 | 0 | } |
883 | | // Fill last above-right sample(s) |
884 | 0 | if (m_neighborFlags[totalUnits - 1]) |
885 | 0 | { |
886 | 0 | int lastSample = (predSize % unitWidth == 0) ? unitWidth : predSize % unitWidth; |
887 | 0 | memcpy(ptrDst,ptrSrc,lastSample*sizeof(Pel)); |
888 | 0 | } |
889 | | |
890 | | // pad from first available down to the last below-left |
891 | 0 | ptrDst = refBufUnfiltered; |
892 | 0 | int lastAvailUnit = 0; |
893 | 0 | if (!m_neighborFlags[0]) |
894 | 0 | { |
895 | 0 | int firstAvailUnit = 1; |
896 | 0 | while (firstAvailUnit < totalUnits && !m_neighborFlags[firstAvailUnit]) |
897 | 0 | { |
898 | 0 | firstAvailUnit++; |
899 | 0 | } |
900 | | |
901 | | // first available sample |
902 | 0 | int firstAvailRow = -1; |
903 | 0 | int firstAvailCol = 0; |
904 | 0 | if (firstAvailUnit < totalLeftUnits) |
905 | 0 | { |
906 | 0 | firstAvailRow = (totalLeftUnits - firstAvailUnit) * unitHeight + multiRefIdx; |
907 | 0 | } |
908 | 0 | else if (firstAvailUnit == totalLeftUnits) |
909 | 0 | { |
910 | 0 | firstAvailRow = multiRefIdx; |
911 | 0 | } |
912 | 0 | else |
913 | 0 | { |
914 | 0 | firstAvailCol = (firstAvailUnit - totalLeftUnits - 1) * unitWidth + 1 + multiRefIdx; |
915 | 0 | } |
916 | 0 | const Pel firstAvailSample = ptrDst[firstAvailRow < 0 ? firstAvailCol : firstAvailRow + predStride]; |
917 | | |
918 | | // last sample below-left (n.a.) |
919 | 0 | int lastRow = predHSize + multiRefIdx; |
920 | | |
921 | | // fill left column |
922 | 0 | for (int i = lastRow; i > firstAvailRow; i--) |
923 | 0 | { |
924 | 0 | ptrDst[i + predStride] = firstAvailSample; |
925 | 0 | } |
926 | | // fill top row |
927 | 0 | if (firstAvailCol > 0) |
928 | 0 | { |
929 | 0 | for (int j = 0; j < firstAvailCol; j++) |
930 | 0 | { |
931 | 0 | ptrDst[j] = firstAvailSample; |
932 | 0 | } |
933 | 0 | } |
934 | 0 | lastAvailUnit = firstAvailUnit; |
935 | 0 | } |
936 | | |
937 | | // pad all other reference samples. |
938 | 0 | int currUnit = lastAvailUnit + 1; |
939 | 0 | while (currUnit < totalUnits) |
940 | 0 | { |
941 | 0 | if (!m_neighborFlags[currUnit]) // samples not available |
942 | 0 | { |
943 | | // last available sample |
944 | 0 | int lastAvailRow = -1; |
945 | 0 | int lastAvailCol = 0; |
946 | 0 | if (lastAvailUnit < totalLeftUnits) |
947 | 0 | { |
948 | 0 | lastAvailRow = (totalLeftUnits - lastAvailUnit - 1) * unitHeight + multiRefIdx + 1; |
949 | 0 | } |
950 | 0 | else if (lastAvailUnit == totalLeftUnits) |
951 | 0 | { |
952 | 0 | lastAvailCol = multiRefIdx; |
953 | 0 | } |
954 | 0 | else |
955 | 0 | { |
956 | 0 | lastAvailCol = (lastAvailUnit - totalLeftUnits) * unitWidth + multiRefIdx; |
957 | 0 | } |
958 | 0 | const Pel lastAvailSample = ptrDst[lastAvailRow < 0 ? lastAvailCol : lastAvailRow + predStride]; |
959 | | |
960 | | // fill current unit with last available sample |
961 | 0 | if (currUnit < totalLeftUnits) |
962 | 0 | { |
963 | 0 | for (int i = lastAvailRow - 1; i >= lastAvailRow - unitHeight; i--) |
964 | 0 | { |
965 | 0 | ptrDst[i + predStride] = lastAvailSample; |
966 | 0 | } |
967 | 0 | } |
968 | 0 | else if (currUnit == totalLeftUnits) |
969 | 0 | { |
970 | 0 | for (int i = 0; i < multiRefIdx + 1; i++) |
971 | 0 | { |
972 | 0 | ptrDst[i + predStride] = lastAvailSample; |
973 | 0 | } |
974 | 0 | for (int j = 0; j < multiRefIdx + 1; j++) |
975 | 0 | { |
976 | 0 | ptrDst[j] = lastAvailSample; |
977 | 0 | } |
978 | 0 | } |
979 | 0 | else |
980 | 0 | { |
981 | 0 | int numSamplesInUnit = (currUnit == totalUnits - 1) ? ((predSize % unitWidth == 0) ? unitWidth : predSize % unitWidth) : unitWidth; |
982 | 0 | for (int j = lastAvailCol + 1; j <= lastAvailCol + numSamplesInUnit; j++) |
983 | 0 | { |
984 | 0 | ptrDst[j] = lastAvailSample; |
985 | 0 | } |
986 | 0 | } |
987 | 0 | } |
988 | 0 | lastAvailUnit = currUnit; |
989 | 0 | currUnit++; |
990 | 0 | } |
991 | 0 | } |
992 | 0 | } |
993 | | |
994 | | void IntraPrediction::xFilterReferenceSamples( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea& area, const SPS &sps |
995 | | , int multiRefIdx |
996 | | , int stride |
997 | | ) |
998 | 0 | { |
999 | 0 | if (area.compID != COMP_Y) |
1000 | 0 | { |
1001 | 0 | multiRefIdx = 0; |
1002 | 0 | } |
1003 | 0 | const int predSize = m_topRefLength + multiRefIdx; |
1004 | 0 | const int predHSize = m_leftRefLength + multiRefIdx; |
1005 | 0 | const int predStride = stride == 0 ? predSize + 1 : stride; |
1006 | | |
1007 | |
|
1008 | 0 | const Pel topLeft = |
1009 | 0 | (refBufUnfiltered[0] + refBufUnfiltered[1] + refBufUnfiltered[predStride] + refBufUnfiltered[predStride + 1] + 2) |
1010 | 0 | >> 2; |
1011 | |
|
1012 | 0 | refBufFiltered[0] = topLeft; |
1013 | |
|
1014 | 0 | for (int i = 1; i < predSize; i++) |
1015 | 0 | { |
1016 | 0 | refBufFiltered[i] = (refBufUnfiltered[i - 1] + 2 * refBufUnfiltered[i] + refBufUnfiltered[i + 1] + 2) >> 2; |
1017 | 0 | } |
1018 | 0 | refBufFiltered[predSize] = refBufUnfiltered[predSize]; |
1019 | |
|
1020 | 0 | refBufFiltered += predStride; |
1021 | 0 | refBufUnfiltered += predStride; |
1022 | |
|
1023 | 0 | refBufFiltered[0] = topLeft; |
1024 | |
|
1025 | 0 | for (int i = 1; i < predHSize; i++) |
1026 | 0 | { |
1027 | 0 | refBufFiltered[i] = (refBufUnfiltered[i - 1] + 2 * refBufUnfiltered[i] + refBufUnfiltered[i + 1] + 2) >> 2; |
1028 | 0 | } |
1029 | 0 | refBufFiltered[predHSize] = refBufUnfiltered[predHSize]; |
1030 | 0 | } |
1031 | | |
1032 | | bool isAboveLeftAvailable(const CodingUnit &cu, const ChannelType& chType, const Position& posLT) |
1033 | 0 | { |
1034 | 0 | const CodingStructure& cs = *cu.cs; |
1035 | 0 | const Position refPos = posLT.offset(-1, -1); |
1036 | |
|
1037 | 0 | return (cs.getCURestricted(refPos, cu, chType) != NULL); |
1038 | 0 | } |
1039 | | |
1040 | | int isAboveAvailable(const CodingUnit &cu, const ChannelType& chType, const Position& posLT, const uint32_t numUnits, const uint32_t unitWidth, bool *bValidFlags) |
1041 | 0 | { |
1042 | 0 | const CodingStructure& cs = *cu.cs; |
1043 | |
|
1044 | 0 | bool * validFlags = bValidFlags; |
1045 | 0 | int numIntra = 0; |
1046 | 0 | const int maxDx = numUnits * unitWidth; |
1047 | 0 | unsigned checkPosX = 0; |
1048 | 0 | bool valid = false; |
1049 | |
|
1050 | 0 | for (int dx = 0; dx < maxDx; dx += unitWidth) |
1051 | 0 | { |
1052 | 0 | if( dx >= checkPosX ) |
1053 | 0 | { |
1054 | 0 | const Position refPos = posLT.offset(dx, -1); |
1055 | |
|
1056 | 0 | const CodingUnit* cuN = cs.getCURestricted(refPos, cu, chType); |
1057 | 0 | valid = (cuN != NULL); |
1058 | 0 | if( cuN ) checkPosX = chType == CH_C ? (cuN->Cb().x + cuN->Cb().width - posLT.x) : (cuN->Y().x + cuN->Y().width - posLT.x); |
1059 | 0 | else break; |
1060 | 0 | } |
1061 | | |
1062 | 0 | numIntra += valid ? 1 : 0; |
1063 | 0 | *validFlags = valid; |
1064 | |
|
1065 | 0 | validFlags++; |
1066 | 0 | } |
1067 | |
|
1068 | 0 | return numIntra; |
1069 | 0 | } |
1070 | | |
1071 | | int isLeftAvailable(const CodingUnit &cu, const ChannelType& chType, const Position& posLT, const uint32_t numUnits, const uint32_t unitHeight, bool *bValidFlags) |
1072 | 0 | { |
1073 | 0 | const CodingStructure& cs = *cu.cs; |
1074 | |
|
1075 | 0 | bool * validFlags = bValidFlags; |
1076 | 0 | int numIntra = 0; |
1077 | 0 | const int maxDy = numUnits * unitHeight; |
1078 | 0 | unsigned checkPosY = 0; |
1079 | 0 | bool valid = false; |
1080 | |
|
1081 | 0 | for (int dy = 0; dy < maxDy; dy += unitHeight) |
1082 | 0 | { |
1083 | 0 | if( dy >= checkPosY ) |
1084 | 0 | { |
1085 | 0 | const Position refPos = posLT.offset(-1, dy); |
1086 | |
|
1087 | 0 | const CodingUnit* cuN = cs.getCURestricted(refPos, cu, chType); |
1088 | 0 | valid = (cuN != NULL); |
1089 | 0 | if( cuN ) checkPosY = chType == CH_C ? (cuN->Cb().y + cuN->Cb().height - posLT.y) : (cuN->Y().y + cuN->Y().height - posLT.y); |
1090 | 0 | else break; |
1091 | 0 | } |
1092 | | |
1093 | 0 | numIntra += valid ? 1 : 0; |
1094 | 0 | *validFlags = valid; |
1095 | |
|
1096 | 0 | validFlags--; |
1097 | 0 | } |
1098 | |
|
1099 | 0 | return numIntra; |
1100 | 0 | } |
1101 | | |
1102 | | int isAboveRightAvailable(const CodingUnit &cu, const ChannelType& chType, const Position& posRT, const uint32_t numUnits, const uint32_t unitWidth, bool *bValidFlags ) |
1103 | 0 | { |
1104 | 0 | const CodingStructure& cs = *cu.cs; |
1105 | |
|
1106 | 0 | bool * validFlags = bValidFlags; |
1107 | 0 | int numIntra = 0; |
1108 | 0 | const int maxDx = numUnits * unitWidth; |
1109 | 0 | unsigned checkPosX = 0; |
1110 | 0 | bool valid = false; |
1111 | |
|
1112 | 0 | for (int dx = 0; dx < maxDx; dx += unitWidth) |
1113 | 0 | { |
1114 | 0 | if( dx >= checkPosX ) |
1115 | 0 | { |
1116 | 0 | const Position refPos = posRT.offset(unitWidth + dx, -1); |
1117 | |
|
1118 | 0 | const CodingUnit* cuN = cs.getCURestricted(refPos, cu, chType); |
1119 | 0 | valid = (cuN != NULL); |
1120 | 0 | if(cuN) checkPosX = chType == CH_C ? (cuN->Cb().x + cuN->Cb().width - (posRT.x + unitWidth)) : (cuN->Y().x + cuN->Y().width - (posRT.x + unitWidth)); |
1121 | 0 | else break; |
1122 | 0 | } |
1123 | | |
1124 | 0 | numIntra += valid ? 1 : 0; |
1125 | 0 | *validFlags = valid; |
1126 | |
|
1127 | 0 | validFlags++; |
1128 | 0 | } |
1129 | |
|
1130 | 0 | return numIntra; |
1131 | 0 | } |
1132 | | |
1133 | | int isBelowLeftAvailable(const CodingUnit &cu, const ChannelType& chType, const Position& posLB, const uint32_t numUnits, const uint32_t unitHeight, bool *bValidFlags ) |
1134 | 0 | { |
1135 | 0 | const CodingStructure& cs = *cu.cs; |
1136 | |
|
1137 | 0 | bool * validFlags = bValidFlags; |
1138 | 0 | int numIntra = 0; |
1139 | 0 | const int maxDy = numUnits * unitHeight; |
1140 | 0 | unsigned checkPosY = 0; |
1141 | 0 | bool valid = false; |
1142 | |
|
1143 | 0 | for (int dy = 0; dy < maxDy; dy += unitHeight) |
1144 | 0 | { |
1145 | 0 | if( dy >= checkPosY ) |
1146 | 0 | { |
1147 | 0 | const Position refPos = posLB.offset(-1, unitHeight + dy); |
1148 | |
|
1149 | 0 | const CodingUnit* cuN = cs.getCURestricted(refPos, cu, chType); |
1150 | 0 | valid = (cuN != NULL); |
1151 | 0 | if( cuN ) checkPosY = chType == CH_C ? (cuN->Cb().y + cuN->Cb().height - (posLB.y + unitHeight)) : (cuN->Y().y + cuN->Y().height - (posLB.y + unitHeight)); |
1152 | 0 | else break; |
1153 | 0 | } |
1154 | | |
1155 | 0 | numIntra += valid ? 1 : 0; |
1156 | 0 | *validFlags = valid; |
1157 | |
|
1158 | 0 | validFlags--; |
1159 | 0 | } |
1160 | |
|
1161 | 0 | return numIntra; |
1162 | 0 | } |
1163 | | |
1164 | | // LumaRecPixels |
1165 | | void IntraPrediction::loadLMLumaRecPels(const CodingUnit& cu, const CompArea& chromaArea ) |
1166 | 0 | { |
1167 | 0 | int iDstStride = 2 * MAX_TB_SIZEY + 1; |
1168 | 0 | Pel* pDst0 = m_pMdlmTemp + iDstStride + 1; |
1169 | | //assert 420 chroma subsampling |
1170 | 0 | CompArea lumaArea = CompArea( COMP_Y, cu.chromaFormat, chromaArea.lumaPos(), recalcSize( cu.chromaFormat, CH_C, CH_L, chromaArea.size() ) );//needed for correct pos/size (4x4 Tus) |
1171 | |
|
1172 | 0 | CHECK(lumaArea.width == chromaArea.width && CHROMA_444 != cu.chromaFormat, ""); |
1173 | 0 | CHECK(lumaArea.height == chromaArea.height && CHROMA_444 != cu.chromaFormat && CHROMA_422 != cu.chromaFormat, ""); |
1174 | |
|
1175 | 0 | const SizeType uiCWidth = chromaArea.width; |
1176 | 0 | const SizeType uiCHeight = chromaArea.height; |
1177 | |
|
1178 | 0 | const CPelBuf Src = cu.cs->picture->getRecoBuf( lumaArea ); |
1179 | 0 | Pel const* pRecSrc0 = Src.bufAt( 0, 0 ); |
1180 | 0 | int iRecStride = Src.stride; |
1181 | 0 | int logSubWidthC = getChannelTypeScaleX(CH_C, cu.chromaFormat); |
1182 | 0 | int logSubHeightC = getChannelTypeScaleY(CH_C, cu.chromaFormat); |
1183 | |
|
1184 | 0 | int iRecStride2 = iRecStride << logSubHeightC; |
1185 | |
|
1186 | 0 | const CompArea& area = isChroma( cu.chType ) ? chromaArea : lumaArea; |
1187 | |
|
1188 | 0 | const uint32_t uiTuWidth = area.width; |
1189 | 0 | const uint32_t uiTuHeight = area.height; |
1190 | |
|
1191 | 0 | const int unitWidthLog2 = MIN_CU_LOG2 - getComponentScaleX( area.compID, area.chromaFormat ); |
1192 | 0 | const int unitHeightLog2 = MIN_CU_LOG2 - getComponentScaleY( area.compID, area.chromaFormat ); |
1193 | 0 | const int unitWidth = 1<<unitWidthLog2; |
1194 | 0 | const int unitHeight = 1<<unitHeightLog2; |
1195 | |
|
1196 | 0 | const int iTUWidthInUnits = uiTuWidth >> unitWidthLog2; |
1197 | 0 | const int iTUHeightInUnits = uiTuHeight >> unitHeightLog2; |
1198 | 0 | const int iAboveUnits = iTUWidthInUnits; |
1199 | 0 | const int iLeftUnits = iTUHeightInUnits; |
1200 | |
|
1201 | 0 | const int chromaUnitWidthLog2 = MIN_CU_LOG2 - logSubWidthC; |
1202 | 0 | const int chromaUnitHeightLog2 = MIN_CU_LOG2 - logSubHeightC; |
1203 | 0 | const int chromaUnitWidth = 1<<chromaUnitWidthLog2; |
1204 | 0 | const int chromaUnitHeight = 1<<chromaUnitHeightLog2; |
1205 | 0 | const int topTemplateSampNum = 2 * uiCWidth; // for MDLM, the number of template samples is 2W or 2H. |
1206 | 0 | const int leftTemplateSampNum = 2 * uiCHeight; |
1207 | 0 | const int totalAboveUnits = (topTemplateSampNum + (chromaUnitWidth - 1)) >> chromaUnitWidthLog2; |
1208 | 0 | const int totalLeftUnits = (leftTemplateSampNum + (chromaUnitHeight - 1)) >> chromaUnitHeightLog2; |
1209 | 0 | const int totalUnits = totalLeftUnits + totalAboveUnits + 1; |
1210 | 0 | const int aboveRightUnits = totalAboveUnits - iAboveUnits; |
1211 | 0 | const int leftBelowUnits = totalLeftUnits - iLeftUnits; |
1212 | |
|
1213 | 0 | int avaiAboveRightUnits = 0; |
1214 | 0 | int avaiLeftBelowUnits = 0; |
1215 | 0 | bool bNeighborFlags[4 * MAX_NUM_PART_IDXS_IN_CTU_WIDTH + 1]; |
1216 | 0 | memset(bNeighborFlags, 0, totalUnits); |
1217 | 0 | bool aboveIsAvailable, leftIsAvailable; |
1218 | 0 | const ChannelType areaCh = toChannelType( area.compID ); |
1219 | |
|
1220 | 0 | int availlableUnit = isLeftAvailable(cu, areaCh, area.pos(), iLeftUnits, unitHeight, (bNeighborFlags + iLeftUnits + leftBelowUnits - 1)); |
1221 | |
|
1222 | 0 | leftIsAvailable = availlableUnit == iTUHeightInUnits; |
1223 | |
|
1224 | 0 | availlableUnit = isAboveAvailable(cu, areaCh, area.pos(), iAboveUnits, unitWidth, (bNeighborFlags + iLeftUnits + leftBelowUnits + 1)); |
1225 | |
|
1226 | 0 | aboveIsAvailable = availlableUnit == iTUWidthInUnits; |
1227 | |
|
1228 | 0 | if (leftIsAvailable) // if left is not available, then the below left is not available |
1229 | 0 | { |
1230 | 0 | avaiLeftBelowUnits = isBelowLeftAvailable(cu, areaCh, area.bottomLeftComp(area.compID), leftBelowUnits, unitHeight, (bNeighborFlags + leftBelowUnits - 1)); |
1231 | 0 | } |
1232 | |
|
1233 | 0 | if (aboveIsAvailable) // if above is not available, then the above right is not available. |
1234 | 0 | { |
1235 | 0 | avaiAboveRightUnits = isAboveRightAvailable(cu, areaCh, area.topRightComp(area.compID), aboveRightUnits, unitWidth, (bNeighborFlags + iLeftUnits + leftBelowUnits + iAboveUnits + 1)); |
1236 | 0 | } |
1237 | |
|
1238 | 0 | Pel* pDst = nullptr; |
1239 | 0 | Pel const* piSrc = nullptr; |
1240 | |
|
1241 | 0 | bool isFirstRowOfCtu = (lumaArea.y & ((cu.cs->sps)->CTUSize - 1)) == 0; |
1242 | |
|
1243 | 0 | if (aboveIsAvailable) |
1244 | 0 | { |
1245 | 0 | pDst = pDst0 - iDstStride; |
1246 | 0 | int addedAboveRight = 0; |
1247 | 0 | if ((cu.intraDir[1] == MDLM_L_IDX) || (cu.intraDir[1] == MDLM_T_IDX)) |
1248 | 0 | { |
1249 | 0 | addedAboveRight = avaiAboveRightUnits*chromaUnitWidth; |
1250 | 0 | } |
1251 | 0 | for (int i = 0; i < uiCWidth + addedAboveRight; i++) |
1252 | 0 | { |
1253 | 0 | const bool leftPadding = i == 0 && !leftIsAvailable; |
1254 | 0 | if (cu.chromaFormat == CHROMA_444) |
1255 | 0 | { |
1256 | 0 | piSrc = pRecSrc0 - iRecStride; |
1257 | 0 | pDst[i] = piSrc[i]; |
1258 | 0 | } |
1259 | 0 | else if (isFirstRowOfCtu) |
1260 | 0 | { |
1261 | 0 | piSrc = pRecSrc0 - iRecStride; |
1262 | 0 | pDst[i] = (piSrc[2 * i] * 2 + piSrc[2 * i - (leftPadding ? 0 : 1)] + piSrc[2 * i + 1] + 2) >> 2; |
1263 | 0 | } |
1264 | 0 | else if (cu.chromaFormat == CHROMA_422) |
1265 | 0 | { |
1266 | 0 | piSrc = pRecSrc0 - iRecStride2; |
1267 | |
|
1268 | 0 | int s = 2; |
1269 | 0 | s += piSrc[2 * i] * 2; |
1270 | 0 | s += piSrc[2 * i - (leftPadding ? 0 : 1)]; |
1271 | 0 | s += piSrc[2 * i + 1]; |
1272 | 0 | pDst[i] = s >> 2; |
1273 | 0 | } |
1274 | 0 | else if (cu.cs->sps->verCollocatedChroma ) |
1275 | 0 | { |
1276 | 0 | piSrc = pRecSrc0 - iRecStride2; |
1277 | |
|
1278 | 0 | int s = 4; |
1279 | 0 | s += piSrc[2 * i - iRecStride]; |
1280 | 0 | s += piSrc[2 * i] * 4; |
1281 | 0 | s += piSrc[2 * i - (leftPadding ? 0 : 1)]; |
1282 | 0 | s += piSrc[2 * i + 1]; |
1283 | 0 | s += piSrc[2 * i + iRecStride]; |
1284 | 0 | pDst[i] = s >> 3; |
1285 | 0 | } |
1286 | 0 | else |
1287 | 0 | { |
1288 | 0 | piSrc = pRecSrc0 - iRecStride2; |
1289 | 0 | int s = 4; |
1290 | 0 | s += piSrc[2 * i] * 2; |
1291 | 0 | s += piSrc[2 * i + 1]; |
1292 | 0 | s += piSrc[2 * i - (leftPadding ? 0 : 1)]; |
1293 | 0 | s += piSrc[2 * i + iRecStride] * 2; |
1294 | 0 | s += piSrc[2 * i + 1 + iRecStride]; |
1295 | 0 | s += piSrc[2 * i + iRecStride - (leftPadding ? 0 : 1)]; |
1296 | 0 | pDst[i] = s >> 3; |
1297 | 0 | } |
1298 | 0 | } |
1299 | 0 | } |
1300 | |
|
1301 | 0 | if (leftIsAvailable) |
1302 | 0 | { |
1303 | 0 | pDst = pDst0 - 1; |
1304 | 0 | piSrc = pRecSrc0 - 1 - logSubWidthC; |
1305 | |
|
1306 | 0 | int addedLeftBelow = 0; |
1307 | 0 | if ((cu.intraDir[1] == MDLM_L_IDX) || (cu.intraDir[1] == MDLM_T_IDX)) |
1308 | 0 | { |
1309 | 0 | addedLeftBelow = avaiLeftBelowUnits*chromaUnitHeight; |
1310 | 0 | } |
1311 | |
|
1312 | 0 | for (int j = 0; j < uiCHeight + addedLeftBelow; j++) |
1313 | 0 | { |
1314 | 0 | if (cu.chromaFormat == CHROMA_444) |
1315 | 0 | { |
1316 | 0 | pDst[0] = piSrc[0]; |
1317 | 0 | } |
1318 | 0 | else if (cu.chromaFormat == CHROMA_422) |
1319 | 0 | { |
1320 | 0 | int s = 2; |
1321 | 0 | s += piSrc[0] * 2; |
1322 | 0 | s += piSrc[-1]; |
1323 | 0 | s += piSrc[1]; |
1324 | 0 | pDst[0] = s >> 2; |
1325 | 0 | } |
1326 | 0 | else if (cu.cs->sps->verCollocatedChroma) |
1327 | 0 | { |
1328 | 0 | const bool abovePadding = j == 0 && !aboveIsAvailable; |
1329 | |
|
1330 | 0 | int s = 4; |
1331 | 0 | s += piSrc[-(abovePadding ? 0 : iRecStride)]; |
1332 | 0 | s += piSrc[0] * 4; |
1333 | 0 | s += piSrc[-1]; |
1334 | 0 | s += piSrc[1]; |
1335 | 0 | s += piSrc[iRecStride]; |
1336 | 0 | pDst[0] = s >> 3; |
1337 | 0 | } |
1338 | 0 | else |
1339 | 0 | { |
1340 | 0 | int s = 4; |
1341 | 0 | s += piSrc[0] * 2; |
1342 | 0 | s += piSrc[1]; |
1343 | 0 | s += piSrc[-1]; |
1344 | 0 | s += piSrc[iRecStride] * 2; |
1345 | 0 | s += piSrc[iRecStride + 1]; |
1346 | 0 | s += piSrc[iRecStride - 1]; |
1347 | 0 | pDst[0] = s >> 3; |
1348 | 0 | } |
1349 | |
|
1350 | 0 | piSrc += iRecStride2; |
1351 | 0 | pDst += iDstStride; |
1352 | 0 | } |
1353 | 0 | } |
1354 | | |
1355 | | // inner part from reconstructed picture buffer |
1356 | 0 | for( int j = 0; j < uiCHeight; j++ ) |
1357 | 0 | { |
1358 | 0 | for( int i = 0; i < uiCWidth; i++ ) |
1359 | 0 | { |
1360 | 0 | if (cu.chromaFormat == CHROMA_444) |
1361 | 0 | { |
1362 | 0 | pDst0[i] = pRecSrc0[i]; |
1363 | 0 | } |
1364 | 0 | else if (cu.chromaFormat == CHROMA_422) |
1365 | 0 | { |
1366 | 0 | const bool leftPadding = i == 0 && !leftIsAvailable; |
1367 | |
|
1368 | 0 | int s = 2; |
1369 | 0 | s += pRecSrc0[2 * i] * 2; |
1370 | 0 | s += pRecSrc0[2 * i - (leftPadding ? 0 : 1)]; |
1371 | 0 | s += pRecSrc0[2 * i + 1]; |
1372 | 0 | pDst0[i] = s >> 2; |
1373 | 0 | } |
1374 | 0 | else if (cu.cs->sps->verCollocatedChroma) |
1375 | 0 | { |
1376 | 0 | const bool leftPadding = i == 0 && !leftIsAvailable; |
1377 | 0 | const bool abovePadding = j == 0 && !aboveIsAvailable; |
1378 | |
|
1379 | 0 | int s = 4; |
1380 | 0 | s += pRecSrc0[2 * i - (abovePadding ? 0 : iRecStride)]; |
1381 | 0 | s += pRecSrc0[2 * i] * 4; |
1382 | 0 | s += pRecSrc0[2 * i - (leftPadding ? 0 : 1)]; |
1383 | 0 | s += pRecSrc0[2 * i + 1]; |
1384 | 0 | s += pRecSrc0[2 * i + iRecStride]; |
1385 | 0 | pDst0[i] = s >> 3; |
1386 | 0 | } |
1387 | 0 | else |
1388 | 0 | { |
1389 | 0 | CHECK(cu.chromaFormat != CHROMA_420, "Chroma format must be 4:2:0 for vertical filtering"); |
1390 | 0 | const bool leftPadding = i == 0 && !leftIsAvailable; |
1391 | |
|
1392 | 0 | int s = 4; |
1393 | 0 | s += pRecSrc0[2 * i] * 2; |
1394 | 0 | s += pRecSrc0[2 * i + 1]; |
1395 | 0 | s += pRecSrc0[2 * i - (leftPadding ? 0 : 1)]; |
1396 | 0 | s += pRecSrc0[2 * i + iRecStride] * 2; |
1397 | 0 | s += pRecSrc0[2 * i + 1 + iRecStride]; |
1398 | 0 | s += pRecSrc0[2 * i + iRecStride - (leftPadding ? 0 : 1)]; |
1399 | 0 | pDst0[i] = s >> 3; |
1400 | 0 | } |
1401 | 0 | } |
1402 | | |
1403 | 0 | pDst0 += iDstStride; |
1404 | 0 | pRecSrc0 += iRecStride2; |
1405 | 0 | } |
1406 | 0 | } |
1407 | | |
1408 | | void IntraPrediction::xGetLMParameters(const CodingUnit& cu, const ComponentID compID, |
1409 | | const CompArea& chromaArea, |
1410 | | int& a, int& b, int& iShift) |
1411 | 0 | { |
1412 | 0 | CHECK(compID == COMP_Y, ""); |
1413 | |
|
1414 | 0 | const SizeType cWidth = chromaArea.width; |
1415 | 0 | const SizeType cHeight = chromaArea.height; |
1416 | |
|
1417 | 0 | const Position posLT = chromaArea; |
1418 | |
|
1419 | 0 | CodingStructure & cs = *(cu.cs); |
1420 | |
|
1421 | 0 | const SPS & sps = *cs.sps; |
1422 | 0 | const uint32_t tuWidth = chromaArea.width; |
1423 | 0 | const uint32_t tuHeight = chromaArea.height; |
1424 | 0 | const ChromaFormat nChromaFormat = sps.chromaFormatIdc; |
1425 | |
|
1426 | 0 | const int unitWidthLog2 = MIN_CU_LOG2 - getComponentScaleX(chromaArea.compID, nChromaFormat); |
1427 | 0 | const int unitHeightLog2 = MIN_CU_LOG2 - getComponentScaleY(chromaArea.compID, nChromaFormat); |
1428 | 0 | const int unitWidth = 1<<unitWidthLog2; |
1429 | 0 | const int unitHeight = 1<<unitHeightLog2; |
1430 | |
|
1431 | 0 | const int tuWidthInUnits = tuWidth >> unitWidthLog2; |
1432 | 0 | const int tuHeightInUnits = tuHeight >> unitHeightLog2; |
1433 | 0 | const int aboveUnits = tuWidthInUnits; |
1434 | 0 | const int leftUnits = tuHeightInUnits; |
1435 | 0 | int topTemplateSampNum = 2 * cWidth; // for MDLM, the template sample number is 2W or 2H; |
1436 | 0 | int leftTemplateSampNum = 2 * cHeight; |
1437 | 0 | int totalAboveUnits = (topTemplateSampNum + (unitWidth - 1)) >> unitWidthLog2; |
1438 | 0 | int totalLeftUnits = (leftTemplateSampNum + (unitHeight - 1)) >> unitHeightLog2; |
1439 | 0 | int totalUnits = totalLeftUnits + totalAboveUnits + 1; |
1440 | 0 | int aboveRightUnits = totalAboveUnits - aboveUnits; |
1441 | 0 | int leftBelowUnits = totalLeftUnits - leftUnits; |
1442 | 0 | int avaiAboveRightUnits = 0; |
1443 | 0 | int avaiLeftBelowUnits = 0; |
1444 | 0 | int avaiAboveUnits = 0; |
1445 | 0 | int avaiLeftUnits = 0; |
1446 | |
|
1447 | 0 | const int curChromaMode = cu.intraDir[1]; |
1448 | 0 | bool neighborFlags[4 * MAX_NUM_PART_IDXS_IN_CTU_WIDTH + 1]; |
1449 | 0 | memset(neighborFlags, 0, totalUnits); |
1450 | |
|
1451 | 0 | bool aboveAvailable, leftAvailable; |
1452 | |
|
1453 | 0 | int availableUnit = isAboveAvailable(cu, CH_C, posLT, aboveUnits, unitWidth, |
1454 | 0 | (neighborFlags + leftUnits + leftBelowUnits + 1)); |
1455 | 0 | aboveAvailable = availableUnit == tuWidthInUnits; |
1456 | |
|
1457 | 0 | availableUnit = isLeftAvailable(cu, CH_C, posLT, leftUnits, unitHeight, |
1458 | 0 | (neighborFlags + leftUnits + leftBelowUnits - 1)); |
1459 | 0 | leftAvailable = availableUnit == tuHeightInUnits; |
1460 | 0 | if (leftAvailable) // if left is not available, then the below left is not available |
1461 | 0 | { |
1462 | 0 | avaiLeftUnits = tuHeightInUnits; |
1463 | 0 | avaiLeftBelowUnits = isBelowLeftAvailable(cu, CH_C, chromaArea.bottomLeftComp(chromaArea.compID), leftBelowUnits, unitHeight, (neighborFlags + leftBelowUnits - 1)); |
1464 | 0 | } |
1465 | 0 | if (aboveAvailable) // if above is not available, then the above right is not available. |
1466 | 0 | { |
1467 | 0 | avaiAboveUnits = tuWidthInUnits; |
1468 | 0 | avaiAboveRightUnits = isAboveRightAvailable(cu, CH_C, chromaArea.topRightComp(chromaArea.compID), aboveRightUnits, unitWidth, (neighborFlags + leftUnits + leftBelowUnits + aboveUnits + 1)); |
1469 | 0 | } |
1470 | |
|
1471 | 0 | const int srcStride = 2 * MAX_TB_SIZEY + 1; |
1472 | 0 | Pel* srcColor0 = m_pMdlmTemp + srcStride + 1; |
1473 | |
|
1474 | 0 | Pel* curChroma0 = getPredictorPtr(compID); |
1475 | |
|
1476 | 0 | unsigned internalBitDepth = sps.bitDepths[CH_C]; |
1477 | |
|
1478 | 0 | int minLuma[2] = { MAX_INT, 0 }; |
1479 | 0 | int maxLuma[2] = { -MAX_INT, 0 }; |
1480 | |
|
1481 | 0 | Pel* src = srcColor0 - srcStride; |
1482 | 0 | int actualTopTemplateSampNum = 0; |
1483 | 0 | int actualLeftTemplateSampNum = 0; |
1484 | 0 | if (curChromaMode == MDLM_T_IDX) |
1485 | 0 | { |
1486 | 0 | leftAvailable = 0; |
1487 | 0 | avaiAboveRightUnits = avaiAboveRightUnits > (cHeight>>unitWidthLog2) ? cHeight>>unitWidthLog2 : avaiAboveRightUnits; |
1488 | 0 | actualTopTemplateSampNum = unitWidth*(avaiAboveUnits + avaiAboveRightUnits); |
1489 | 0 | } |
1490 | 0 | else if (curChromaMode == MDLM_L_IDX) |
1491 | 0 | { |
1492 | 0 | aboveAvailable = 0; |
1493 | 0 | avaiLeftBelowUnits = avaiLeftBelowUnits > (cWidth>>unitHeightLog2) ? cWidth>>unitHeightLog2 : avaiLeftBelowUnits; |
1494 | 0 | actualLeftTemplateSampNum = unitHeight*(avaiLeftUnits + avaiLeftBelowUnits); |
1495 | 0 | } |
1496 | 0 | else if (curChromaMode == LM_CHROMA_IDX) |
1497 | 0 | { |
1498 | 0 | actualTopTemplateSampNum = cWidth; |
1499 | 0 | actualLeftTemplateSampNum = cHeight; |
1500 | 0 | } |
1501 | 0 | int startPos[2]; //0:Above, 1: Left |
1502 | 0 | int pickStep[2]; |
1503 | |
|
1504 | 0 | int aboveIs4 = leftAvailable ? 0 : 1; |
1505 | 0 | int leftIs4 = aboveAvailable ? 0 : 1; |
1506 | |
|
1507 | 0 | startPos[0] = actualTopTemplateSampNum >> (2 + aboveIs4); |
1508 | 0 | pickStep[0] = std::max(1, actualTopTemplateSampNum >> (1 + aboveIs4)); |
1509 | |
|
1510 | 0 | startPos[1] = actualLeftTemplateSampNum >> (2 + leftIs4); |
1511 | 0 | pickStep[1] = std::max(1, actualLeftTemplateSampNum >> (1 + leftIs4)); |
1512 | |
|
1513 | 0 | Pel selectLumaPix[4] = { 0, 0, 0, 0 }; |
1514 | 0 | Pel selectChromaPix[4] = { 0, 0, 0, 0 }; |
1515 | |
|
1516 | 0 | int cntT, cntL; |
1517 | 0 | cntT = cntL = 0; |
1518 | 0 | int cnt = 0; |
1519 | 0 | if (aboveAvailable) |
1520 | 0 | { |
1521 | 0 | cntT = std::min(actualTopTemplateSampNum, (1 + aboveIs4) << 1); |
1522 | 0 | src = srcColor0 - srcStride; |
1523 | 0 | const Pel *cur = curChroma0 + 1; |
1524 | 0 | for (int pos = startPos[0]; cnt < cntT; pos += pickStep[0], cnt++) |
1525 | 0 | { |
1526 | 0 | selectLumaPix[cnt] = src[pos]; |
1527 | 0 | selectChromaPix[cnt] = cur[pos]; |
1528 | 0 | } |
1529 | 0 | } |
1530 | |
|
1531 | 0 | if (leftAvailable) |
1532 | 0 | { |
1533 | 0 | cntL = std::min(actualLeftTemplateSampNum, ( 1 + leftIs4 ) << 1 ); |
1534 | 0 | src = srcColor0 - 1; |
1535 | 0 | const Pel *cur = curChroma0 + m_refBufferStride[compID] + 1; |
1536 | 0 | for (int pos = startPos[1], cnt = 0; cnt < cntL; pos += pickStep[1], cnt++) |
1537 | 0 | { |
1538 | 0 | selectLumaPix[cnt + cntT] = src[pos * srcStride]; |
1539 | 0 | selectChromaPix[cnt + cntT] = cur[pos]; |
1540 | 0 | } |
1541 | 0 | } |
1542 | 0 | cnt = cntL + cntT; |
1543 | |
|
1544 | 0 | if (cnt == 2) |
1545 | 0 | { |
1546 | 0 | selectLumaPix[3] = selectLumaPix[0]; selectChromaPix[3] = selectChromaPix[0]; |
1547 | 0 | selectLumaPix[2] = selectLumaPix[1]; selectChromaPix[2] = selectChromaPix[1]; |
1548 | 0 | selectLumaPix[0] = selectLumaPix[1]; selectChromaPix[0] = selectChromaPix[1]; |
1549 | 0 | selectLumaPix[1] = selectLumaPix[3]; selectChromaPix[1] = selectChromaPix[3]; |
1550 | 0 | } |
1551 | |
|
1552 | 0 | int minGrpIdx[2] = { 0, 2 }; |
1553 | 0 | int maxGrpIdx[2] = { 1, 3 }; |
1554 | 0 | int *tmpMinGrp = minGrpIdx; |
1555 | 0 | int *tmpMaxGrp = maxGrpIdx; |
1556 | 0 | if (selectLumaPix[tmpMinGrp[0]] > selectLumaPix[tmpMinGrp[1]]) std::swap(tmpMinGrp[0], tmpMinGrp[1]); |
1557 | 0 | if (selectLumaPix[tmpMaxGrp[0]] > selectLumaPix[tmpMaxGrp[1]]) std::swap(tmpMaxGrp[0], tmpMaxGrp[1]); |
1558 | 0 | if (selectLumaPix[tmpMinGrp[0]] > selectLumaPix[tmpMaxGrp[1]]) std::swap(tmpMinGrp, tmpMaxGrp); |
1559 | 0 | if (selectLumaPix[tmpMinGrp[1]] > selectLumaPix[tmpMaxGrp[0]]) std::swap(tmpMinGrp[1], tmpMaxGrp[0]); |
1560 | |
|
1561 | 0 | minLuma[0] = (selectLumaPix[tmpMinGrp[0]] + selectLumaPix[tmpMinGrp[1]] + 1 )>>1; |
1562 | 0 | minLuma[1] = (selectChromaPix[tmpMinGrp[0]] + selectChromaPix[tmpMinGrp[1]] + 1) >> 1; |
1563 | 0 | maxLuma[0] = (selectLumaPix[tmpMaxGrp[0]] + selectLumaPix[tmpMaxGrp[1]] + 1 )>>1; |
1564 | 0 | maxLuma[1] = (selectChromaPix[tmpMaxGrp[0]] + selectChromaPix[tmpMaxGrp[1]] + 1) >> 1; |
1565 | |
|
1566 | 0 | if (leftAvailable || aboveAvailable) |
1567 | 0 | { |
1568 | 0 | int diff = maxLuma[0] - minLuma[0]; |
1569 | 0 | if (diff > 0) |
1570 | 0 | { |
1571 | 0 | int diffC = maxLuma[1] - minLuma[1]; |
1572 | 0 | int x = floorLog2( diff ); |
1573 | 0 | static const uint8_t DivSigTable[1 << 4] = { |
1574 | | // 4bit significands - 8 ( MSB is omitted ) |
1575 | 0 | 0, 7, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 1, 1, 0 |
1576 | 0 | }; |
1577 | 0 | int normDiff = (diff << 4 >> x) & 15; |
1578 | 0 | int v = DivSigTable[normDiff] | 8; |
1579 | 0 | x += normDiff != 0; |
1580 | |
|
1581 | 0 | int y = diffC == 0 ? 0 : floorLog2( abs( diffC ) ) + 1; |
1582 | 0 | int add = 1 << y >> 1; |
1583 | 0 | a = (diffC * v + add) >> y; |
1584 | 0 | iShift = 3 + x - y; |
1585 | 0 | if ( iShift < 1 ) |
1586 | 0 | { |
1587 | 0 | iShift = 1; |
1588 | 0 | a = ( (a == 0)? 0: (a < 0)? -15 : 15 ); // a=Sign(a)*15 |
1589 | 0 | } |
1590 | 0 | b = minLuma[1] - ((a * minLuma[0]) >> iShift); |
1591 | 0 | } |
1592 | 0 | else |
1593 | 0 | { |
1594 | 0 | a = 0; |
1595 | 0 | b = minLuma[1]; |
1596 | 0 | iShift = 0; |
1597 | 0 | } |
1598 | 0 | } |
1599 | 0 | else |
1600 | 0 | { |
1601 | 0 | a = 0; |
1602 | 0 | b = 1 << (internalBitDepth - 1); |
1603 | 0 | iShift = 0; |
1604 | 0 | } |
1605 | 0 | } |
1606 | | |
1607 | | void IntraPrediction::initIntraMip( const CodingUnit& cu ) |
1608 | 0 | { |
1609 | 0 | CHECK( cu.lwidth() > cu.cs->sps->getMaxTbSize() || cu.lheight() > cu.cs->sps->getMaxTbSize(), "Error: block size not supported for MIP" ); |
1610 | | |
1611 | | // prepare input (boundary) data for prediction |
1612 | 0 | CHECK(m_ipaParam.refFilterFlag, "ERROR: unfiltered refs expected for MIP"); |
1613 | 0 | Pel *ptrSrc = getPredictorPtr(COMP_Y); |
1614 | 0 | const int srcStride = m_refBufferStride[COMP_Y]; |
1615 | 0 | const int srcHStride = 2; |
1616 | |
|
1617 | 0 | m_matrixIntraPred.prepareInputForPred(CPelBuf(ptrSrc, srcStride, srcHStride), cu.Y(), cu.slice->sps->bitDepths[CH_L]); |
1618 | 0 | } |
1619 | | |
1620 | | void IntraPrediction::predIntraMip( PelBuf &piPred, const CodingUnit& cu ) |
1621 | 0 | { |
1622 | 0 | CHECK( cu.lwidth() > cu.cs->sps->getMaxTbSize() || cu.lheight() > cu.cs->sps->getMaxTbSize(), "Error: block size not supported for MIP" ); |
1623 | 0 | CHECK( cu.lwidth() != (1 << floorLog2(cu.lwidth())) || cu.lheight() != (1 << floorLog2(cu.lheight())), "Error: expecting blocks of size 2^M x 2^N" ); |
1624 | | |
1625 | | // generate mode-specific prediction |
1626 | 0 | const int bitDepth = cu.slice->sps->bitDepths[CH_L]; |
1627 | |
|
1628 | 0 | CHECK( cu.lwidth() != piPred.stride, " no support yet" ); |
1629 | | |
1630 | 0 | m_matrixIntraPred.predBlock(piPred.buf, cu.intraDir[CH_L], cu.mipTransposedFlag, bitDepth); |
1631 | 0 | } |
1632 | | |
1633 | | void IntraPrediction::initIntraPatternChTypeISP(const CodingUnit& cu, const CompArea& area, PelBuf& recBuf, |
1634 | | const bool forceRefFilterFlag) |
1635 | 0 | { |
1636 | 0 | const CodingStructure& cs = *cu.cs; |
1637 | |
|
1638 | 0 | if (!forceRefFilterFlag) |
1639 | 0 | { |
1640 | 0 | initPredIntraParams(cu, area, *cs.sps); |
1641 | 0 | } |
1642 | |
|
1643 | 0 | const Position posLT = area; |
1644 | 0 | bool isLeftAvail = |
1645 | 0 | (cs.getCURestricted(posLT.offset(-1, 0), cu, CH_L) != NULL); |
1646 | 0 | bool isAboveAvail = |
1647 | 0 | (cs.getCURestricted(posLT.offset(0, -1), cu, CH_L) != NULL); |
1648 | | // ----- Step 1: unfiltered reference samples ----- |
1649 | 0 | if (cu.blocks[area.compID].x == area.x && cu.blocks[area.compID].y == area.y) |
1650 | 0 | { |
1651 | 0 | Pel* refBufUnfiltered = m_refBuffer[area.compID][PRED_BUF_UNFILTERED]; |
1652 | | // With the first subpartition all the CU reference samples are fetched at once in a single call to |
1653 | | // xFillReferenceSamples |
1654 | 0 | if (cu.ispMode == HOR_INTRA_SUBPARTITIONS) |
1655 | 0 | { |
1656 | 0 | m_leftRefLength = cu.Y().height << 1; |
1657 | 0 | m_topRefLength = cu.Y().width + area.width; |
1658 | 0 | } |
1659 | 0 | else // if (cu.ispMode == VER_INTRA_SUBPARTITIONS) |
1660 | 0 | { |
1661 | 0 | m_leftRefLength = cu.Y().height + area.height; |
1662 | 0 | m_topRefLength = cu.Y().width << 1; |
1663 | 0 | } |
1664 | |
|
1665 | 0 | xFillReferenceSamples(cs.picture->getRecoBuf(cu.Y()), refBufUnfiltered, cu.Y(), cu); |
1666 | | |
1667 | | // After having retrieved all the CU reference samples, the number of reference samples is now adjusted for the |
1668 | | // current subpartition |
1669 | 0 | m_topRefLength = cu.blocks[area.compID].width + area.width; |
1670 | 0 | m_leftRefLength = cu.blocks[area.compID].height + area.height; |
1671 | 0 | } |
1672 | 0 | else |
1673 | 0 | { |
1674 | 0 | m_topRefLength = cu.blocks[area.compID].width + area.width; |
1675 | 0 | m_leftRefLength = cu.blocks[area.compID].height + area.height; |
1676 | |
|
1677 | 0 | const int predSizeHor = m_topRefLength; |
1678 | 0 | const int predSizeVer = m_leftRefLength; |
1679 | 0 | if (cu.ispMode == HOR_INTRA_SUBPARTITIONS) |
1680 | 0 | { |
1681 | 0 | Pel* src = recBuf.bufAt(0, -1); |
1682 | 0 | Pel* ref = m_refBuffer[area.compID][PRED_BUF_UNFILTERED] + m_refBufferStride[area.compID]; |
1683 | 0 | if (isLeftAvail) |
1684 | 0 | { |
1685 | 0 | for (int i = 0; i <= 2 * cu.blocks[area.compID].height - area.height; i++) |
1686 | 0 | { |
1687 | 0 | ref[i] = ref[i + area.height]; |
1688 | 0 | } |
1689 | 0 | } |
1690 | 0 | else |
1691 | 0 | { |
1692 | 0 | for (int i = 0; i <= predSizeVer; i++) |
1693 | 0 | { |
1694 | 0 | ref[i] = src[0]; |
1695 | 0 | } |
1696 | 0 | } |
1697 | 0 | Pel* dst = m_refBuffer[area.compID][PRED_BUF_UNFILTERED] + 1; |
1698 | 0 | dst[-1] = ref[0]; |
1699 | 0 | for (int i = 0; i < area.width; i++) |
1700 | 0 | { |
1701 | 0 | dst[i] = src[i]; |
1702 | 0 | } |
1703 | 0 | Pel sample = src[area.width - 1]; |
1704 | 0 | dst += area.width; |
1705 | 0 | for (int i = 0; i < predSizeHor - area.width; i++) |
1706 | 0 | { |
1707 | 0 | dst[i] = sample; |
1708 | 0 | } |
1709 | 0 | } |
1710 | 0 | else |
1711 | 0 | { |
1712 | 0 | Pel* src = recBuf.bufAt(-1, 0); |
1713 | 0 | Pel* ref = m_refBuffer[area.compID][PRED_BUF_UNFILTERED]; |
1714 | 0 | if (isAboveAvail) |
1715 | 0 | { |
1716 | 0 | for (int i = 0; i <= 2 * cu.blocks[area.compID].width - area.width; i++) |
1717 | 0 | { |
1718 | 0 | ref[i] = ref[i + area.width]; |
1719 | 0 | } |
1720 | 0 | } |
1721 | 0 | else |
1722 | 0 | { |
1723 | 0 | for (int i = 0; i <= predSizeHor; i++) |
1724 | 0 | { |
1725 | 0 | ref[i] = src[0]; |
1726 | 0 | } |
1727 | 0 | } |
1728 | 0 | Pel* dst = m_refBuffer[area.compID][PRED_BUF_UNFILTERED] + m_refBufferStride[area.compID] + 1; |
1729 | 0 | dst[-1] = ref[0]; |
1730 | 0 | for (int i = 0; i < area.height; i++) |
1731 | 0 | { |
1732 | 0 | *dst = *src; |
1733 | 0 | src += recBuf.stride; |
1734 | 0 | dst++; |
1735 | 0 | } |
1736 | 0 | Pel sample = src[-recBuf.stride]; |
1737 | 0 | for (int i = 0; i < predSizeVer - area.height; i++) |
1738 | 0 | { |
1739 | 0 | *dst = sample; |
1740 | 0 | dst++; |
1741 | 0 | } |
1742 | 0 | } |
1743 | 0 | } |
1744 | | // ----- Step 2: filtered reference samples ----- |
1745 | 0 | if (m_ipaParam.refFilterFlag || forceRefFilterFlag) |
1746 | 0 | { |
1747 | 0 | Pel* refBufUnfiltered = m_refBuffer[area.compID][PRED_BUF_UNFILTERED]; |
1748 | 0 | Pel* refBufFiltered = m_refBuffer[area.compID][PRED_BUF_FILTERED]; |
1749 | 0 | xFilterReferenceSamples(refBufUnfiltered, refBufFiltered, area, *cs.sps, cu.multiRefIdx); |
1750 | 0 | } |
1751 | 0 | } |
1752 | | |
1753 | | void IntraPrediction::setReferenceArrayLengths(const CompArea& area) |
1754 | 0 | { |
1755 | | // set Top and Left reference samples length |
1756 | 0 | const int width = area.width; |
1757 | 0 | const int height = area.height; |
1758 | |
|
1759 | 0 | m_leftRefLength = (height << 1); |
1760 | 0 | m_topRefLength = (width << 1); |
1761 | 0 | } |
1762 | | |
1763 | | } // namespace vvenc |
1764 | | |
1765 | | //! \} |
1766 | | |