/work/vvdec/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) 2018-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVdeC 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 | | /** \file Prediction.cpp |
44 | | \brief prediction class |
45 | | */ |
46 | | |
47 | | #define DONT_UNDEF_SIZE_AWARE_PER_EL_OP |
48 | | |
49 | | #include "IntraPrediction.h" |
50 | | |
51 | | #include "Unit.h" |
52 | | #include "UnitTools.h" |
53 | | |
54 | | #include "Buffer.h" |
55 | | |
56 | | #include "dtrace_next.h" |
57 | | #include "Rom.h" |
58 | | |
59 | | #include <memory.h> |
60 | | #include <array> |
61 | | |
62 | | #include "CommonLib/InterpolationFilter.h" |
63 | | #include "CommonLib/TimeProfiler.h" |
64 | | |
65 | | namespace vvdec |
66 | | { |
67 | | |
68 | | // ==================================================================================================================== |
69 | | // Tables |
70 | | // ==================================================================================================================== |
71 | | |
72 | | const uint8_t IntraPrediction::m_aucIntraFilter[MAX_NUM_CHANNEL_TYPE][MAX_INTRA_FILTER_DEPTHS] = |
73 | | { |
74 | | { // Luma |
75 | | 24, // 1xn |
76 | | 24, // 2xn |
77 | | 24, // 4xn |
78 | | 14, // 8xn |
79 | | 2, // 16xn |
80 | | 0, // 32xn |
81 | | 0, // 64xn |
82 | | 0, // 128xn |
83 | | }, |
84 | | { // Chroma |
85 | | 40, // 1xn |
86 | | 40, // 2xn |
87 | | 40, // 4xn |
88 | | 28, // 8xn |
89 | | 4, // 16xn |
90 | | 0, // 32xn |
91 | | 0, // 64xn |
92 | | 0, // 128xn |
93 | | } |
94 | | }; |
95 | | |
96 | | const TFilterCoeff g_intraGaussFilter[32][4] = { |
97 | | { 16, 32, 16, 0 }, |
98 | | { 16, 32, 16, 0 }, |
99 | | { 15, 31, 17, 1 }, |
100 | | { 15, 31, 17, 1 }, |
101 | | { 14, 30, 18, 2 }, |
102 | | { 14, 30, 18, 2 }, |
103 | | { 13, 29, 19, 3 }, |
104 | | { 13, 29, 19, 3 }, |
105 | | { 12, 28, 20, 4 }, |
106 | | { 12, 28, 20, 4 }, |
107 | | { 11, 27, 21, 5 }, |
108 | | { 11, 27, 21, 5 }, |
109 | | { 10, 26, 22, 6 }, |
110 | | { 10, 26, 22, 6 }, |
111 | | { 9, 25, 23, 7 }, |
112 | | { 9, 25, 23, 7 }, |
113 | | { 8, 24, 24, 8 }, |
114 | | { 8, 24, 24, 8 }, |
115 | | { 7, 23, 25, 9 }, |
116 | | { 7, 23, 25, 9 }, |
117 | | { 6, 22, 26, 10 }, |
118 | | { 6, 22, 26, 10 }, |
119 | | { 5, 21, 27, 11 }, |
120 | | { 5, 21, 27, 11 }, |
121 | | { 4, 20, 28, 12 }, |
122 | | { 4, 20, 28, 12 }, |
123 | | { 3, 19, 29, 13 }, |
124 | | { 3, 19, 29, 13 }, |
125 | | { 2, 18, 30, 14 }, |
126 | | { 2, 18, 30, 14 }, |
127 | | { 1, 17, 31, 15 }, |
128 | | { 1, 17, 31, 15 }, |
129 | | }; |
130 | | |
131 | | // Pure vertical prediction with PDPC. A horizontal mode is predicted transposed with the same function. |
132 | | // refMain and refSide point at the reference sample before the first one of the block. |
133 | | void IntraPredHorVerPdpcCore( Pel* pDst, const ptrdiff_t dstStride, const Pel* refMain, const Pel* refSide, const int width, const int height, const int scale, const Pel topLeft, const ClpRng& clpRng ) |
134 | 0 | { |
135 | 0 | const int lev[4] = { std::min( 3, width ), std::min( 6, width ), std::min( 12, width ), std::min( 24, width ) }; |
136 | |
|
137 | 0 | for( int y = 0; y < height; y++ ) |
138 | 0 | { |
139 | 0 | const Pel left = refSide[y + 1]; |
140 | 0 | Pel *line = &pDst[y * dstStride]; |
141 | 0 | for( int x = 0; x < lev[scale]; x++ ) |
142 | 0 | { |
143 | 0 | int wL = 32 >> std::min( 31, ( ( x << 1 ) >> scale ) ); |
144 | 0 | *line++ = ClipPel( ( wL * ( left - topLeft ) + refMain[x + 1] * ( 1 << 6 ) + 32 ) >> 6, clpRng ); |
145 | 0 | } |
146 | 0 | memcpy( line, refMain + lev[scale] + 1, ( width - lev[scale] ) * sizeof( Pel ) ); |
147 | 0 | } |
148 | 0 | } |
149 | | |
150 | | void GetLumaRecPixel420Core (const int width,const int height, const Pel* pRecSrc0,const ptrdiff_t iRecStride,Pel* pDst0,const ptrdiff_t iDstStride) |
151 | 0 | { |
152 | 0 | for( int y = 0; y < height; y++ ) |
153 | 0 | { |
154 | 0 | for( int x = 0; x < width; x ++ ) |
155 | 0 | { |
156 | 0 | pDst0[x + 0 ] = ( pRecSrc0[( (x + 0 ) << 1 ) ] * 2 |
157 | 0 | + pRecSrc0[( (x + 0 ) << 1 ) + 1] * 1 |
158 | 0 | + pRecSrc0[( (x + 0 ) << 1 ) - 1] * 1 |
159 | 0 | + pRecSrc0[( (x + 0 ) << 1 ) + iRecStride] * 2 |
160 | 0 | + pRecSrc0[( (x + 0 ) << 1 ) + 1 + iRecStride] * 1 |
161 | 0 | + pRecSrc0[( (x + 0 ) << 1 ) - 1 + iRecStride] * 1 |
162 | 0 | + 4 ) >> 3; |
163 | 0 | } |
164 | 0 | pDst0 += iDstStride; |
165 | 0 | pRecSrc0 += (iRecStride<<1); |
166 | 0 | } |
167 | 0 | } |
168 | | |
169 | | /** Function for deriving planar intra prediction. This function derives the prediction samples for planar mode (intra coding). |
170 | | */ |
171 | | |
172 | | //NOTE: Bit-Limit - 24-bit source |
173 | | void xPredIntraPlanarCore( const CPelBuf &pSrc, PelBuf &pDst, const SPS& sps ) |
174 | 0 | { |
175 | | // with some optimizations gcc gives spurious "-Wmaybe-uninitialized" warnings here |
176 | | GCC_WARNING_DISABLE_maybe_uninitialized |
177 | |
|
178 | 0 | const uint32_t width = pDst.width; |
179 | 0 | const uint32_t height = pDst.height; |
180 | 0 | const uint32_t log2W = getLog2( width ); |
181 | 0 | const uint32_t log2H = getLog2( height ); |
182 | 0 | int leftColumn[MAX_CU_SIZE + 1], topRow[MAX_CU_SIZE + 1], bottomRow[MAX_CU_SIZE], rightColumn[MAX_CU_SIZE]; |
183 | 0 | const uint32_t offset = 1 << (log2W + log2H); |
184 | | // Get left and above reference column and row |
185 | 0 | for( int k = 0; k < width + 1; k++ ) |
186 | 0 | { |
187 | 0 | topRow[k] = pSrc.at( k + 1, 0 ); |
188 | 0 | } |
189 | |
|
190 | 0 | for( int k = 0; k < height + 1; k++ ) |
191 | 0 | { |
192 | 0 | leftColumn[k] = pSrc.at( 0, k + 1 ); |
193 | 0 | } |
194 | | |
195 | | // Prepare intermediate variables used in interpolation |
196 | 0 | int bottomLeft = leftColumn[height]; |
197 | 0 | int topRight = topRow[width]; |
198 | |
|
199 | 0 | for( int k = 0; k < width; k++ ) |
200 | 0 | { |
201 | 0 | bottomRow[k] = bottomLeft - topRow[k]; |
202 | 0 | topRow[k] = topRow[k] << log2H; |
203 | 0 | } |
204 | |
|
205 | 0 | for( int k = 0; k < height; k++ ) |
206 | 0 | { |
207 | 0 | rightColumn[k] = topRight - leftColumn[k]; |
208 | 0 | leftColumn[k] = leftColumn[k] << log2W; |
209 | 0 | } |
210 | |
|
211 | 0 | const uint32_t finalShift = 1 + log2W + log2H; |
212 | 0 | const ptrdiff_t stride = pDst.stride; |
213 | 0 | Pel* pred = pDst.buf; |
214 | 0 | for( int y = 0; y < height; y++, pred += stride ) |
215 | 0 | { |
216 | 0 | int horPred = leftColumn[y]; |
217 | |
|
218 | 0 | for( int x = 0; x < width; x++ ) |
219 | 0 | { |
220 | 0 | horPred += rightColumn[y]; |
221 | 0 | topRow[x] += bottomRow[x]; |
222 | |
|
223 | 0 | int vertPred = topRow[x]; |
224 | 0 | pred[x] = ( ( horPred << log2H ) + ( vertPred << log2W ) + offset ) >> finalShift; |
225 | |
|
226 | 0 | } |
227 | 0 | } |
228 | 0 | GCC_WARNING_RESET |
229 | 0 | } |
230 | | |
231 | | void IntraPredSampleFilterCore(Pel *ptrSrc,const ptrdiff_t srcStride,PelBuf &piPred,const uint32_t uiDirMode,const ClpRng& clpRng) |
232 | 0 | { |
233 | 0 | const CPelBuf srcBuf ( ptrSrc, ( SizeType ) srcStride, ( SizeType ) srcStride ); |
234 | 0 | const int iWidth = piPred.width; |
235 | 0 | const int iHeight = piPred.height; |
236 | 0 | PelBuf dstBuf = piPred; |
237 | |
|
238 | 0 | const int scale = ((getLog2(iWidth) - 2 + getLog2(iHeight) - 2 + 2) >> 2); |
239 | 0 | CHECK(scale < 0 || scale > 31, "PDPC: scale < 0 || scale > 31"); |
240 | |
|
241 | 0 | #if 1 |
242 | 0 | if( uiDirMode == PLANAR_IDX || uiDirMode == DC_IDX ) |
243 | 0 | { |
244 | 0 | for( int y = 0; y < iHeight; y++ ) |
245 | 0 | { |
246 | 0 | const int wT = 32 >> std::min(31, ((y << 1) >> scale)); |
247 | | // const Pel left = srcBuf.at(y + 1, 1); |
248 | 0 | const Pel left = srcBuf.at(0, y + 1 ); |
249 | 0 | for (int x = 0; x < iWidth; x++) |
250 | 0 | { |
251 | 0 | const int wL = 32 >> std::min(31, ((x << 1) >> scale)); |
252 | 0 | const Pel top = srcBuf.at(x + 1, 0); |
253 | 0 | const Pel val = dstBuf.at(x, y); |
254 | 0 | dstBuf.at(x, y) = val + ((wL * (left - val) + wT * (top - val) + 32) >> 6); |
255 | 0 | } |
256 | 0 | } |
257 | 0 | } |
258 | | #else |
259 | | const int lev[4]={std::min(3,iWidth),std::min(6,iWidth),std::min(12,iWidth),std::min(24,iWidth)}; |
260 | | if (uiDirMode == PLANAR_IDX) |
261 | | { |
262 | | for (int y = 0; y < iHeight; y++) |
263 | | { |
264 | | int wT = 32 >> std::min(31, ((y << 1) >> scale)); |
265 | | const Pel left = srcBuf.at(0, y + 1); |
266 | | if (wT) |
267 | | { |
268 | | for (int x = 0; x < iWidth; x++) |
269 | | { |
270 | | const Pel top = srcBuf.at(x + 1, 0); |
271 | | int wL = 32 >> std::min(31, ((x << 1) >> scale)); |
272 | | dstBuf.at(x, y) = ClipPel((wL * left + wT * top + (64 - wL - wT) * dstBuf.at(x, y) + 32) >> 6, clpRng); |
273 | | |
274 | | } |
275 | | } |
276 | | else |
277 | | { |
278 | | for (int x = 0; x < lev[scale]; x++) // bis wL 0 ist, das ist bei x lev[scale] |
279 | | { |
280 | | int wL = 32 >> std::min(31, ((x << 1) >> scale)); |
281 | | dstBuf.at(x, y) = ClipPel((wL * left + (64 - wL) * dstBuf.at(x, y) + 32) >> 6, clpRng); |
282 | | } |
283 | | } |
284 | | } |
285 | | } |
286 | | else if (uiDirMode == DC_IDX) |
287 | | { |
288 | | const Pel topLeft = srcBuf.at(0, 0); |
289 | | for (int y = 0; y < iHeight; y++) |
290 | | { |
291 | | int wT = 32 >> std::min(31, ((y << 1) >> scale)); |
292 | | const Pel left = srcBuf.at(0, y + 1); |
293 | | if (wT) |
294 | | { |
295 | | |
296 | | for (int x = 0; x < iWidth; x++) |
297 | | { |
298 | | const Pel top = srcBuf.at(x + 1, 0); |
299 | | int wL = 32 >> std::min(31, ((x << 1) >> scale)); |
300 | | int wTL = (wL >> 4) + (wT >> 4); |
301 | | dstBuf.at(x, y) = ClipPel((wL * left + wT * top - wTL * topLeft + (64 - wL - wT + wTL) * dstBuf.at(x, y) + 32) >> 6, clpRng); |
302 | | } |
303 | | } |
304 | | else |
305 | | { |
306 | | for (int x = 0; x < lev[scale]; x++) |
307 | | { |
308 | | const Pel top = srcBuf.at(x + 1, 0); |
309 | | int wL = 32 >> std::min(31, ((x << 1) >> scale)); |
310 | | int wTL = (wL >> 4) + (wT >> 4); |
311 | | dstBuf.at(x, y) = ClipPel((wL * left + wT * top - wTL * topLeft + (64 - wL - wT + wTL) * dstBuf.at(x, y) + 32) >> 6, clpRng); |
312 | | } |
313 | | |
314 | | } |
315 | | } |
316 | | } |
317 | | #endif |
318 | 0 | } |
319 | | |
320 | | template<typename T> |
321 | | void IntraPredAngleCore(T* pDstBuf,const ptrdiff_t dstStride,T* refMain,int width,int height,int deltaPos,int intraPredAngle,const TFilterCoeff *ff,const bool useCubicFilter,const ClpRng& clpRng) |
322 | 0 | { |
323 | 0 | for (int y = 0; y<height; y++ ) |
324 | 0 | { |
325 | 0 | const int deltaInt = deltaPos >> 5; |
326 | 0 | const int deltaFract = deltaPos & ( 32 - 1 ); |
327 | |
|
328 | 0 | Pel p[4]; |
329 | |
|
330 | 0 | int refMainIndex = deltaInt + 1; |
331 | |
|
332 | 0 | const TFilterCoeff *f = &ff[deltaFract << 2]; |
333 | |
|
334 | 0 | for( int x = 0; x < width; x++, refMainIndex++ ) |
335 | 0 | { |
336 | 0 | p[0] = refMain[refMainIndex - 1]; |
337 | 0 | p[1] = refMain[refMainIndex ]; |
338 | 0 | p[2] = refMain[refMainIndex + 1]; |
339 | 0 | p[3] = refMain[refMainIndex + 2]; |
340 | |
|
341 | 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); |
342 | |
|
343 | 0 | if( useCubicFilter ) // only cubic filter has negative coefficients and requires clipping |
344 | 0 | { |
345 | 0 | pDstBuf[y*dstStride + x] = ClipPel( pDstBuf[y*dstStride + x], clpRng ); |
346 | 0 | } |
347 | 0 | } |
348 | 0 | deltaPos += intraPredAngle; |
349 | 0 | } |
350 | 0 | } |
351 | | |
352 | | template<typename T> |
353 | | void IntraPredAngleChroma(T* pDstBuf,const ptrdiff_t dstStride,int16_t* pBorder,int width,int height,int deltaPos,int intraPredAngle) |
354 | 0 | { |
355 | 0 | for (int y = 0; y<height; y++) |
356 | 0 | { |
357 | 0 | const int deltaInt = deltaPos >> 5; |
358 | 0 | const int deltaFract = deltaPos & (32 - 1); |
359 | | |
360 | | // Do linear filtering |
361 | 0 | const Pel *pRM = pBorder + deltaInt + 1; |
362 | 0 | int lastRefMainPel = *pRM++; |
363 | |
|
364 | 0 | for( int x = 0; x < width; pRM++, x++ ) |
365 | 0 | { |
366 | 0 | int thisRefMainPel = *pRM; |
367 | 0 | pDstBuf[x + 0] = ( Pel ) ( ( ( 32 - deltaFract )*lastRefMainPel + deltaFract*thisRefMainPel + 16 ) >> 5 ); |
368 | 0 | lastRefMainPel = thisRefMainPel; |
369 | 0 | } |
370 | 0 | deltaPos += intraPredAngle; |
371 | 0 | pDstBuf += dstStride; |
372 | 0 | } |
373 | |
|
374 | 0 | } |
375 | | |
376 | | // ==================================================================================================================== |
377 | | // Constructor / destructor / initialize |
378 | | // ==================================================================================================================== |
379 | | |
380 | 30.5k | IntraPrediction::IntraPrediction() : m_currChromaFormat( NUM_CHROMA_FORMAT ) |
381 | 30.5k | { |
382 | 30.5k | IntraPredAngleCore4 = IntraPredAngleCore; |
383 | 30.5k | IntraPredAngleCore8 = IntraPredAngleCore; |
384 | 30.5k | IntraPredAngleChroma4 = IntraPredAngleChroma; |
385 | 30.5k | IntraPredAngleChroma8 = IntraPredAngleChroma; |
386 | | |
387 | 30.5k | IntraPredSampleFilter8 = IntraPredSampleFilterCore; |
388 | 30.5k | IntraPredSampleFilter16 = IntraPredSampleFilterCore; |
389 | | |
390 | 30.5k | xPredIntraPlanar = xPredIntraPlanarCore; |
391 | 30.5k | IntraPredHorVerPdpc = IntraPredHorVerPdpcCore; |
392 | | |
393 | 30.5k | GetLumaRecPixel420 = GetLumaRecPixel420Core; |
394 | 30.5k | } |
395 | | |
396 | | IntraPrediction::~IntraPrediction() |
397 | 30.5k | { |
398 | 30.5k | destroy(); |
399 | 30.5k | } |
400 | | |
401 | | void IntraPrediction::destroy() |
402 | 30.5k | { |
403 | 30.5k | } |
404 | | |
405 | | void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepthY) |
406 | 0 | { |
407 | | // if it has been initialised before, but the chroma format has changed, release the memory and start again. |
408 | 0 | if (m_currChromaFormat != chromaFormatIDC) |
409 | 0 | { |
410 | 0 | destroy(); |
411 | 0 | } |
412 | |
|
413 | 0 | m_currChromaFormat = chromaFormatIDC; |
414 | |
|
415 | 0 | std::fill_n( m_neighborSize, 3, 0 ); |
416 | 0 | m_lastCUidx = -1; |
417 | |
|
418 | | #if ENABLE_SIMD_OPT_INTRAPRED && defined( TARGET_SIMD_X86 ) |
419 | | initIntraPredictionX86(); |
420 | | #endif |
421 | | #if ENABLE_SIMD_OPT_INTRAPRED && defined( TARGET_SIMD_ARM ) |
422 | | initIntraPredictionARM(); |
423 | | #endif |
424 | 0 | } |
425 | | |
426 | | // ==================================================================================================================== |
427 | | // Public member functions |
428 | | // ==================================================================================================================== |
429 | | |
430 | | // Function for calculating DC value of the reference samples used in Intra prediction |
431 | | //NOTE: Bit-Limit - 25-bit source |
432 | | Pel IntraPrediction::xGetPredValDc( const CPelBuf &pSrc, const Size &dstSize, const int mrlIdx ) |
433 | 0 | { |
434 | 0 | CHECK( dstSize.width == 0 || dstSize.height == 0, "Empty area provided" ); |
435 | |
|
436 | 0 | int idx, sum = 0; |
437 | 0 | Pel dcVal; |
438 | 0 | const int width = dstSize.width; |
439 | 0 | const int height = dstSize.height; |
440 | 0 | const auto denom = (width == height) ? (width << 1) : std::max(width,height); |
441 | 0 | const auto divShift = getLog2(denom); |
442 | 0 | const auto divOffset = (denom >> 1); |
443 | |
|
444 | 0 | if( width >= height ) |
445 | 0 | { |
446 | 0 | for( idx = 0; idx < width; idx++ ) |
447 | 0 | { |
448 | 0 | sum += pSrc.at( mrlIdx + 1 + idx, 0 ); |
449 | 0 | } |
450 | 0 | } |
451 | 0 | if( width <= height ) |
452 | 0 | { |
453 | 0 | for( idx = 0; idx < height; idx++ ) |
454 | 0 | { |
455 | 0 | sum += pSrc.at( 0, mrlIdx + 1 + idx ); |
456 | 0 | } |
457 | 0 | } |
458 | |
|
459 | 0 | dcVal = (sum + divOffset) >> divShift; |
460 | 0 | return dcVal; |
461 | 0 | } |
462 | | |
463 | | int IntraPrediction::getWideAngle( int width, int height, int predMode ) |
464 | 0 | { |
465 | 0 | if ( predMode > DC_IDX && predMode <= VDIA_IDX ) |
466 | 0 | { |
467 | 0 | int modeShift[] = { 0, 6, 10, 12, 14, 15 }; |
468 | 0 | int deltaSize = abs(getLog2(width) - getLog2(height)); |
469 | 0 | if (width > height && predMode < 2 + modeShift[deltaSize]) |
470 | 0 | { |
471 | 0 | predMode += (VDIA_IDX - 1); |
472 | 0 | } |
473 | 0 | else if (height > width && predMode > VDIA_IDX - modeShift[deltaSize]) |
474 | 0 | { |
475 | 0 | predMode -= (VDIA_IDX - 1); |
476 | 0 | } |
477 | 0 | } |
478 | 0 | return predMode; |
479 | 0 | } |
480 | | |
481 | | void IntraPrediction::setReferenceArrayLengths( const CompArea &area ) |
482 | 0 | { |
483 | | // set Top and Left reference samples length |
484 | 0 | const int width = area.width; |
485 | 0 | const int height = area.height; |
486 | |
|
487 | 0 | m_leftRefLength = (height << 1); |
488 | 0 | m_topRefLength = (width << 1); |
489 | |
|
490 | 0 | } |
491 | | |
492 | | |
493 | | |
494 | | void IntraPrediction::predIntraAng( const ComponentID compID, PelBuf &piPred, const CodingUnit &cu, const bool useFilteredPredSamples ) |
495 | 0 | { |
496 | 0 | const ChannelType channelType = toChannelType( compID ); |
497 | 0 | const int iWidth = piPred.width; |
498 | 0 | const int iHeight = piPred.height; |
499 | 0 | const Size cuSize = Size( cu.blocks[compID].width, cu.blocks[compID].height ); |
500 | 0 | CHECK( CU::isMIP(cu, toChannelType(compID)), "We should not get here for MIP." ); |
501 | 0 | const uint32_t uiDirMode = isLuma( compID ) && cu.bdpcmMode() ? BDPCM_IDX : !isLuma(compID) && cu.bdpcmModeChroma() ? BDPCM_IDX : PU::getFinalIntraMode(cu, channelType); |
502 | |
|
503 | 0 | CHECKD( iWidth == 2, "Width of 2 is not supported" ); |
504 | |
|
505 | 0 | const int multiRefIdx = ( compID == COMPONENT_Y ) ? cu.multiRefIdx() : 0; |
506 | 0 | const bool useISP = cu.ispMode() && isLuma( compID ); |
507 | 0 | const int srcStride = m_topRefLength + 1 + multiRefIdx; |
508 | 0 | const int srcHStride = m_leftRefLength + 1 + multiRefIdx; |
509 | 0 | const ClpRng& clpRng ( cu.slice->clpRng( compID ) ); |
510 | 0 | bool doPDPC = ( iWidth >= MIN_TB_SIZEY && iHeight >= MIN_TB_SIZEY ) && multiRefIdx == 0; |
511 | |
|
512 | 0 | const PelBuf& srcBuf = cu.ispMode() && isLuma(compID) ? getISPBuffer( useFilteredPredSamples ) : PelBuf(getPredictorPtr(compID, useFilteredPredSamples), srcStride, srcHStride); |
513 | |
|
514 | 0 | switch (uiDirMode) |
515 | 0 | { |
516 | 0 | case(PLANAR_IDX): xPredIntraPlanar(srcBuf, piPred, *cu.sps); break; |
517 | 0 | case(DC_IDX): xPredIntraDc (srcBuf, piPred, channelType, false, multiRefIdx); break; |
518 | 0 | case(BDPCM_IDX): xPredIntraBDPCM(srcBuf, piPred, isLuma(compID) ? cu.bdpcmMode() : cu.bdpcmModeChroma(), clpRng); break; |
519 | 0 | case(2): |
520 | 0 | case(DIA_IDX): |
521 | 0 | case(VDIA_IDX): |
522 | 0 | if (getWideAngle(useISP ? cuSize.width : iWidth, useISP ? cuSize.height : iHeight, uiDirMode) == static_cast<int>(uiDirMode)) // check if uiDirMode is not wide-angle |
523 | 0 | { |
524 | 0 | xPredIntraAng(srcBuf, piPred, channelType, uiDirMode, clpRng, *cu.sps, multiRefIdx, useFilteredPredSamples, doPDPC, useISP, cuSize ); |
525 | 0 | break; |
526 | 0 | } |
527 | 0 | default: xPredIntraAng(srcBuf, piPred, channelType, uiDirMode, clpRng, *cu.sps, multiRefIdx, useFilteredPredSamples, doPDPC, useISP, cuSize); break; |
528 | 0 | } |
529 | | |
530 | 0 | if( doPDPC && (uiDirMode == PLANAR_IDX || uiDirMode == DC_IDX ) ) |
531 | 0 | { |
532 | 0 | if (iWidth>8) |
533 | 0 | IntraPredSampleFilter16(srcBuf.buf,srcBuf.stride,piPred,uiDirMode,clpRng); |
534 | 0 | else |
535 | 0 | IntraPredSampleFilter8(srcBuf.buf,srcBuf.stride,piPred,uiDirMode,clpRng); |
536 | 0 | } |
537 | 0 | } |
538 | | |
539 | | void IntraPrediction::predIntraChromaLM( const ComponentID compID, PelBuf& piPred, const CodingUnit& cu, const CompArea& chromaArea, int intraDir ) |
540 | 0 | { |
541 | 0 | int iLumaStride = 0; |
542 | 0 | PelBuf Temp; |
543 | 0 | if( (intraDir == MDLM_L_IDX) || (intraDir == MDLM_T_IDX) ) |
544 | 0 | { |
545 | 0 | iLumaStride = 2 * MAX_TU_SIZE_FOR_PROFILE + 1; |
546 | 0 | Temp = PelBuf( m_piYuvExt[1] + iLumaStride + 1, iLumaStride, Size( chromaArea ) ); |
547 | 0 | } |
548 | 0 | else |
549 | 0 | { |
550 | 0 | iLumaStride = MAX_TU_SIZE_FOR_PROFILE + 1; |
551 | 0 | Temp = PelBuf( m_piYuvExt[1] + iLumaStride + 1, iLumaStride, Size( chromaArea ) ); |
552 | 0 | } |
553 | 0 | int a, b, iShift; |
554 | 0 | xGetLMParameters( cu, compID, chromaArea, a, b, iShift ); |
555 | | |
556 | | ////// final prediction |
557 | 0 | piPred.copyFrom( Temp ); |
558 | 0 | piPred.linearTransform( a, iShift, b, true, cu.slice->clpRng( compID ) ); |
559 | 0 | } |
560 | | |
561 | | void IntraPrediction::xPredIntraDc( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const bool enableBoundaryFilter, const int mrlIdx ) |
562 | 0 | { |
563 | 0 | const Pel dcval = xGetPredValDc( pSrc, pDst, mrlIdx ); |
564 | 0 | pDst.fill( dcval ); |
565 | 0 | } |
566 | | |
567 | | // Function for deriving the angular Intra predictions |
568 | | void IntraPredAngleCore(Pel *pDstBuf,const int dstStride,Pel* refMain,int width,int height,int deltaPos,int intraPredAngle,const TFilterCoeff *ff,const bool useCubicFilter,const ClpRng& clpRng) |
569 | 0 | { |
570 | 0 | for (int y = 0; y<height; y++ ) |
571 | 0 | { |
572 | 0 | const int deltaInt = deltaPos >> 5; |
573 | 0 | const int deltaFract = deltaPos & ( 32 - 1 ); |
574 | |
|
575 | 0 | Pel p[4]; |
576 | |
|
577 | 0 | int refMainIndex = deltaInt + 1; |
578 | |
|
579 | 0 | const TFilterCoeff *f = &ff[deltaFract << 2]; |
580 | |
|
581 | 0 | for( int x = 0; x < width; x++, refMainIndex++ ) |
582 | 0 | { |
583 | 0 | p[0] = refMain[refMainIndex - 1]; |
584 | 0 | p[1] = refMain[refMainIndex ]; |
585 | 0 | p[2] = refMain[refMainIndex + 1]; |
586 | 0 | p[3] = refMain[refMainIndex + 2]; |
587 | |
|
588 | 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); |
589 | |
|
590 | 0 | if( useCubicFilter ) // only cubic filter has negative coefficients and requires clipping |
591 | 0 | { |
592 | 0 | pDstBuf[y*dstStride + x] = ClipPel( pDstBuf[y*dstStride + x], clpRng ); |
593 | 0 | } |
594 | 0 | } |
595 | 0 | deltaPos += intraPredAngle; |
596 | 0 | } |
597 | 0 | } |
598 | | |
599 | | |
600 | | /** Function for deriving the simplified angular intra predictions. |
601 | | * |
602 | | * This function derives the prediction samples for the angular mode based on the prediction direction indicated by |
603 | | * the prediction mode index. The prediction direction is given by the displacement of the bottom row of the block and |
604 | | * the reference row above the block in the case of vertical prediction or displacement of the rightmost column |
605 | | * of the block and reference column left from the block in the case of the horizontal prediction. The displacement |
606 | | * is signalled at 1/32 pixel accuracy. When projection of the predicted pixel falls inbetween reference samples, |
607 | | * the predicted value for the pixel is linearly interpolated from the reference samples. All reference samples are taken |
608 | | * from the extended main reference. |
609 | | */ |
610 | | //NOTE: Bit-Limit - 25-bit source |
611 | | |
612 | | void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps, |
613 | | int multiRefIdx, |
614 | | const bool useFilteredPredSamples , |
615 | | bool &doPDPC, |
616 | | const bool useISP, |
617 | | const Size cuSize |
618 | | ) |
619 | 0 | { |
620 | 0 | int width =int(pDst.width); |
621 | 0 | int height=int(pDst.height); |
622 | |
|
623 | 0 | CHECK( !( dirMode > DC_IDX && dirMode < NUM_LUMA_MODE ), "Invalid intra dir" ); |
624 | 0 | int predMode = useISP ? getWideAngle( cuSize.width, cuSize.height, dirMode ) : getWideAngle( width, height, dirMode ); |
625 | 0 | const bool bIsModeVer = predMode >= DIA_IDX; |
626 | 0 | const int intraPredAngleMode = (bIsModeVer) ? predMode - VER_IDX : -(predMode - HOR_IDX); |
627 | 0 | const int absAngMode = abs(intraPredAngleMode); |
628 | 0 | const int signAng = intraPredAngleMode < 0 ? -1 : 1; |
629 | | |
630 | | // Set bitshifts and scale the angle parameter to block size |
631 | 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 }; |
632 | 0 | static const int invAngTable[32] = { |
633 | 0 | 0, 16384, 8192, 5461, 4096, 2731, 2048, 1638, 1365, 1170, 1024, 910, 819, 712, 630, 565, |
634 | 0 | 512, 468, 420, 364, 321, 287, 256, 224, 191, 161, 128, 96, 64, 48, 32, 16 |
635 | 0 | }; // (512 * 32) / Angle |
636 | 0 | int invAngle = invAngTable[absAngMode]; |
637 | 0 | int absAng = angTable [absAngMode]; |
638 | 0 | int intraPredAngle = signAng * absAng; |
639 | |
|
640 | 0 | Pel* refMain; |
641 | 0 | Pel* refSide; |
642 | |
|
643 | 0 | Pel refAbove[2 * MAX_CU_SIZE + 3 + 33 * MAX_REF_LINE_IDX]; |
644 | 0 | Pel refLeft [2 * MAX_CU_SIZE + 3 + 33 * MAX_REF_LINE_IDX]; |
645 | | |
646 | | // Initialize the Main and Left reference array. |
647 | 0 | if (intraPredAngle < 0) |
648 | 0 | { |
649 | 0 | for (int x = 0; x <= width + 1 + multiRefIdx; x++) |
650 | 0 | { |
651 | 0 | refAbove[x + height] = pSrc.at(x, 0); |
652 | 0 | } |
653 | 0 | for (int y = 0; y <= height + 1 + multiRefIdx; y++) |
654 | 0 | { |
655 | 0 | refLeft[y + width] = pSrc.at(0, y); |
656 | 0 | } |
657 | 0 | refMain = bIsModeVer ? refAbove + height : refLeft + width; |
658 | 0 | refSide = bIsModeVer ? refLeft + width : refAbove + height; |
659 | | |
660 | | // Extend the Main reference to the left. |
661 | 0 | int sizeSide = bIsModeVer ? height : width; |
662 | 0 | for (int k = -sizeSide; k <= -1; k++) |
663 | 0 | { |
664 | 0 | refMain[k] = refSide[std::min((-k * invAngle + 256) >> 9, sizeSide)]; |
665 | 0 | } |
666 | 0 | } |
667 | 0 | else |
668 | 0 | { |
669 | | //for (int x = 0; x <= m_topRefLength + multiRefIdx; x++) |
670 | | //{ |
671 | | // refAbove[x] = pSrc.at(x, 0); |
672 | | //} |
673 | 0 | memcpy( refAbove, pSrc.buf, ( m_topRefLength + multiRefIdx + 1 ) * sizeof( Pel ) ); |
674 | 0 | for (int y = 0; y <= m_leftRefLength + multiRefIdx; y++) |
675 | 0 | { |
676 | 0 | refLeft[y] = pSrc.at(0, y); |
677 | 0 | } |
678 | |
|
679 | 0 | refMain = bIsModeVer ? refAbove : refLeft; |
680 | 0 | refSide = bIsModeVer ? refLeft : refAbove; |
681 | | |
682 | | // Extend main reference to right using replication |
683 | 0 | const int log2Ratio = getLog2(width) - getLog2(height); |
684 | 0 | const int s = std::max<int>(0, bIsModeVer ? log2Ratio : -log2Ratio); |
685 | 0 | const int maxIndex = (multiRefIdx << s) + 2; |
686 | 0 | const int refLength = bIsModeVer ? m_topRefLength : m_leftRefLength; |
687 | 0 | const Pel val = refMain[refLength + multiRefIdx]; |
688 | 0 | for (int z = 1; z <= maxIndex; z++) |
689 | 0 | { |
690 | 0 | refMain[refLength + multiRefIdx + z] = val; |
691 | 0 | } |
692 | 0 | } |
693 | | |
694 | | // swap width/height if we are doing a horizontal mode: |
695 | 0 | Pel tempArray[MAX_TB_SIZEY*MAX_TB_SIZEY]; |
696 | 0 | const ptrdiff_t dstStride = bIsModeVer ? pDst.stride : MAX_TB_SIZEY; |
697 | 0 | Pel *pDstBuf = bIsModeVer ? pDst.buf : tempArray; |
698 | 0 | if (!bIsModeVer) |
699 | 0 | { |
700 | 0 | std::swap(width, height); |
701 | 0 | } |
702 | | |
703 | | // compensate for line offset in reference line buffers |
704 | 0 | refMain += multiRefIdx; |
705 | 0 | refSide += multiRefIdx; |
706 | |
|
707 | 0 | if( intraPredAngle == 0 ) // pure vertical or pure horizontal |
708 | 0 | { |
709 | 0 | if( doPDPC ) |
710 | 0 | { |
711 | 0 | const int scale = ( ( getLog2( width ) - 2 + getLog2( height ) - 2 + 2 ) >> 2 ); |
712 | 0 | CHECK( scale < 0 || scale > 3, "PDPC: scale < 0 || scale > 3" ); |
713 | |
|
714 | 0 | IntraPredHorVerPdpc( pDstBuf, dstStride, refMain, refSide, width, height, scale, pSrc.at( 0, 0 ), clpRng ); |
715 | 0 | } |
716 | 0 | else |
717 | 0 | { |
718 | 0 | for( int y = 0; y < height; y++ ) |
719 | 0 | { |
720 | 0 | memcpy( pDstBuf + y * dstStride, refMain + 1, width * sizeof( Pel ) ); |
721 | 0 | } |
722 | |
|
723 | 0 | } |
724 | 0 | } |
725 | 0 | else |
726 | 0 | { |
727 | 0 | Pel *pDsty=pDstBuf; |
728 | |
|
729 | 0 | if( !(0 == (absAng & 0x1F)) ) |
730 | 0 | { |
731 | 0 | if( isLuma(channelType) ) |
732 | 0 | { |
733 | 0 | int deltaPos = intraPredAngle * (1 + multiRefIdx); |
734 | 0 | bool interpolationFlag = false, filterFlag = false; |
735 | 0 | const int diff = std::min<int>( abs( predMode - HOR_IDX ), abs( predMode - VER_IDX ) ); |
736 | 0 | const int log2Size = ((getLog2(width) + getLog2(height)) >> 1); |
737 | 0 | CHECKD( log2Size >= MAX_INTRA_FILTER_DEPTHS, "Size not supported" ); |
738 | 0 | filterFlag = (diff > m_aucIntraFilter[channelType][log2Size]); |
739 | |
|
740 | 0 | if( filterFlag ) |
741 | 0 | { |
742 | 0 | const bool isRefFilter = 0 == ( absAng & 0x1F ); |
743 | 0 | interpolationFlag = !isRefFilter; |
744 | 0 | } |
745 | 0 | const bool useCubicFilter = useISP ? true : ( !interpolationFlag || multiRefIdx > 0 ); |
746 | 0 | const TFilterCoeff *f = (useCubicFilter) ? InterpolationFilter::getChromaFilterTable(0) : g_intraGaussFilter[0]; |
747 | 0 | if( ( width & 7 ) == 0 ) |
748 | 0 | { |
749 | 0 | IntraPredAngleCore8(pDstBuf,dstStride,refMain,width,height,deltaPos,intraPredAngle,f,useCubicFilter,clpRng); |
750 | |
|
751 | 0 | } |
752 | 0 | else if( ( width & 3 ) == 0 ) |
753 | 0 | { |
754 | 0 | IntraPredAngleCore4(pDstBuf,dstStride,refMain,width,height,deltaPos,intraPredAngle,f,useCubicFilter,clpRng); |
755 | 0 | } |
756 | 0 | else |
757 | 0 | { |
758 | 0 | CHECK( !useISP, "should not happen" ); |
759 | |
|
760 | 0 | for (int y = 0; y<height; y++ ) |
761 | 0 | { |
762 | 0 | const int deltaInt = deltaPos >> 5; |
763 | 0 | const int deltaFract = deltaPos & ( 32 - 1 ); |
764 | |
|
765 | 0 | Pel p[4]; |
766 | |
|
767 | 0 | int refMainIndex = deltaInt + 1; |
768 | |
|
769 | 0 | const TFilterCoeff *ff = &f[deltaFract << 2]; |
770 | |
|
771 | 0 | for( int x = 0; x < width; x++, refMainIndex++ ) |
772 | 0 | { |
773 | 0 | p[0] = refMain[refMainIndex - 1]; |
774 | 0 | p[1] = refMain[refMainIndex ]; |
775 | 0 | p[2] = refMain[refMainIndex + 1]; |
776 | 0 | p[3] = refMain[refMainIndex + 2]; |
777 | |
|
778 | 0 | pDstBuf[y*dstStride + x] = static_cast<Pel>((static_cast<int>(ff[0] * p[0]) + static_cast<int>(ff[1] * p[1]) + static_cast<int>(ff[2] * p[2]) + static_cast<int>(ff[3] * p[3]) + 32) >> 6); |
779 | |
|
780 | 0 | if( useCubicFilter ) // only cubic filter has negative coefficients and requires clipping |
781 | 0 | { |
782 | 0 | pDstBuf[y*dstStride + x] = ClipPel( pDstBuf[y*dstStride + x], clpRng ); |
783 | 0 | } |
784 | 0 | } |
785 | 0 | deltaPos += intraPredAngle; |
786 | 0 | } |
787 | 0 | } |
788 | |
|
789 | 0 | } |
790 | 0 | else |
791 | 0 | { |
792 | 0 | int deltaPos = intraPredAngle * (1 + multiRefIdx); |
793 | 0 | if ( width >=8 ) |
794 | 0 | { |
795 | 0 | IntraPredAngleChroma8(pDstBuf,dstStride,refMain,width,height,deltaPos,intraPredAngle); |
796 | 0 | } |
797 | 0 | else if( width == 4 ) |
798 | 0 | { |
799 | 0 | IntraPredAngleChroma4(pDstBuf,dstStride,refMain,width,height,deltaPos,intraPredAngle); |
800 | 0 | } |
801 | 0 | else |
802 | 0 | { |
803 | 0 | IntraPredAngleChroma(pDstBuf,dstStride,refMain,width,height,deltaPos,intraPredAngle); |
804 | 0 | } |
805 | 0 | } |
806 | |
|
807 | 0 | } |
808 | 0 | else |
809 | 0 | { |
810 | 0 | for (int y = 0, deltaPos = intraPredAngle * (1 + multiRefIdx); y<height; y++, deltaPos += intraPredAngle, pDsty += dstStride) |
811 | 0 | { |
812 | 0 | const int deltaInt = deltaPos >> 5; |
813 | | // Just copy the integer samples |
814 | 0 | memcpy(pDsty,refMain + deltaInt + 1,width*sizeof(Pel)); |
815 | 0 | } |
816 | 0 | } |
817 | | |
818 | 0 | pDsty=pDstBuf; |
819 | 0 | for (int y = 0; y<height; y++, pDsty += dstStride) |
820 | 0 | { |
821 | 0 | int angularScale = 0; |
822 | 0 | if( intraPredAngle < 0 ) |
823 | 0 | { |
824 | 0 | doPDPC = false; |
825 | 0 | } |
826 | 0 | else if( intraPredAngle > 0 ) |
827 | 0 | { |
828 | 0 | const int sideSize = predMode >= DIA_IDX ? pDst.height : pDst.width; |
829 | 0 | const int maxScale = 2; |
830 | |
|
831 | 0 | angularScale = std::min(maxScale, getLog2(sideSize) - (getLog2(3 * invAngle - 2) - 8)); |
832 | 0 | doPDPC &= angularScale >= 0; |
833 | 0 | } |
834 | |
|
835 | 0 | if( doPDPC ) |
836 | 0 | { |
837 | 0 | int invAngleSum = 256; |
838 | |
|
839 | 0 | for (int x = 0; x < std::min(3 << angularScale, width); x++) |
840 | 0 | { |
841 | 0 | invAngleSum += invAngle; |
842 | |
|
843 | 0 | int wL = 32 >> (2 * x >> angularScale); |
844 | 0 | Pel left = refSide[y + (invAngleSum >> 9) + 1]; |
845 | 0 | pDsty[x] = pDsty[x] + ((wL * (left - pDsty[x]) + 32) >> 6); |
846 | 0 | } |
847 | 0 | } |
848 | 0 | } |
849 | 0 | } |
850 | | |
851 | | // Flip the block if this is the horizontal mode |
852 | 0 | if( !bIsModeVer ) |
853 | 0 | { |
854 | 0 | pDst.transposedFrom( CPelBuf( pDstBuf, dstStride, width, height ) ); |
855 | 0 | } |
856 | 0 | } |
857 | | |
858 | | void IntraPrediction::xPredIntraBDPCM(const CPelBuf &pSrc, PelBuf &pDst, const uint32_t dirMode, const ClpRng& clpRng ) |
859 | 0 | { |
860 | 0 | const int wdt = pDst.width; |
861 | 0 | const int hgt = pDst.height; |
862 | |
|
863 | 0 | const ptrdiff_t strideP = pDst.stride; |
864 | 0 | const ptrdiff_t strideS = pSrc.stride; |
865 | |
|
866 | 0 | CHECK( !( dirMode == 1 || dirMode == 2 ), "Incorrect BDPCM mode parameter." ); |
867 | |
|
868 | 0 | Pel* pred = &pDst.buf[0]; |
869 | 0 | if( dirMode == 1 ) |
870 | 0 | { |
871 | 0 | Pel val; |
872 | 0 | for( int y = 0; y < hgt; y++ ) |
873 | 0 | { |
874 | 0 | val = pSrc.buf[(y + 1) * strideS]; |
875 | 0 | for( int x = 0; x < wdt; x++ ) |
876 | 0 | { |
877 | 0 | pred[x] = val; |
878 | 0 | } |
879 | 0 | pred += strideP; |
880 | 0 | } |
881 | 0 | } |
882 | 0 | else |
883 | 0 | { |
884 | 0 | for( int y = 0; y < hgt; y++ ) |
885 | 0 | { |
886 | 0 | for( int x = 0; x < wdt; x++ ) |
887 | 0 | { |
888 | 0 | pred[x] = pSrc.buf[x + 1]; |
889 | 0 | } |
890 | 0 | pred += strideP; |
891 | 0 | } |
892 | 0 | } |
893 | 0 | } |
894 | | |
895 | | void IntraPrediction::predBlendIntraCiip( PelUnitBuf &predUnit, const CodingUnit &cu ) |
896 | 0 | { |
897 | 0 | int maxCompID = 1; |
898 | |
|
899 | 0 | if( isChromaEnabled( cu.chromaFormat ) && cu.chromaSize().width > 2 ) |
900 | 0 | { |
901 | 0 | maxCompID = MAX_NUM_COMPONENT; |
902 | 0 | } |
903 | |
|
904 | 0 | for( int currCompID = 0; currCompID < maxCompID; currCompID++ ) |
905 | 0 | { |
906 | 0 | PelBuf& pred = predUnit.bufs[ currCompID ]; |
907 | 0 | const int width = pred.width; |
908 | 0 | const int height = pred.height; |
909 | 0 | const ptrdiff_t srcStride = width; |
910 | 0 | const ptrdiff_t dstStride = pred.stride; |
911 | 0 | Pel* dstBuf = pred.buf; |
912 | 0 | const bool isUseFilter = currCompID == 0 && IntraPrediction::useFilteredIntraRefSamples( COMPONENT_Y, cu, cu ); |
913 | 0 | Pel* srcBuf = m_piYuvExt[!isUseFilter]; |
914 | 0 | PelBuf srcAreaBuf( srcBuf, srcStride, width, height ); |
915 | |
|
916 | 0 | { |
917 | 0 | PROFILER_SCOPE_AND_STAGE_EXT( 1, g_timeProfiler, P_INTRAPRED, *cu.cs, compID ); |
918 | |
|
919 | 0 | initIntraPatternChType( cu.firstTU, cu.blocks[currCompID], isUseFilter ); |
920 | 0 | predIntraAng( ComponentID( currCompID ), srcAreaBuf, cu, isUseFilter ); |
921 | 0 | } |
922 | |
|
923 | 0 | CHECKD( width == 2, "Width of 2 is not supported" ); |
924 | |
|
925 | 0 | const Position posBL = cu.Y().bottomLeft(); |
926 | 0 | const Position posTR = cu.Y().topRight(); |
927 | |
|
928 | 0 | const CodingUnit* cuLeft = cu.cs->getCURestricted( posBL.offset( -1, 0 ), cu, CHANNEL_TYPE_LUMA, cu.left ); |
929 | 0 | const CodingUnit* cuAbove = cu.cs->getCURestricted( posTR.offset( 0, -1 ), cu, CHANNEL_TYPE_LUMA, cu.above ); |
930 | |
|
931 | 0 | const bool isNeigh0Intra = cuLeft && ( CU::isIntra( *cuLeft ) ); |
932 | 0 | const bool isNeigh1Intra = cuAbove && ( CU::isIntra( *cuAbove ) ); |
933 | |
|
934 | 0 | const int wIntra = 3 - !isNeigh0Intra - !isNeigh1Intra; |
935 | 0 | const int wMerge = 3 - !!isNeigh0Intra - !!isNeigh1Intra; |
936 | |
|
937 | 0 | for( int y = 0; y < height; y++ ) |
938 | 0 | { |
939 | 0 | for( int x = 0; x < width; x += 4 ) |
940 | 0 | { |
941 | 0 | dstBuf[y * dstStride + x + 0] = ( wMerge * dstBuf[y * dstStride + x + 0] + wIntra * srcBuf[y * srcStride + x + 0] + 2 ) >> 2; |
942 | 0 | dstBuf[y * dstStride + x + 1] = ( wMerge * dstBuf[y * dstStride + x + 1] + wIntra * srcBuf[y * srcStride + x + 1] + 2 ) >> 2; |
943 | 0 | dstBuf[y * dstStride + x + 2] = ( wMerge * dstBuf[y * dstStride + x + 2] + wIntra * srcBuf[y * srcStride + x + 2] + 2 ) >> 2; |
944 | 0 | dstBuf[y * dstStride + x + 3] = ( wMerge * dstBuf[y * dstStride + x + 3] + wIntra * srcBuf[y * srcStride + x + 3] + 2 ) >> 2; |
945 | 0 | } |
946 | 0 | } |
947 | 0 | } |
948 | 0 | } |
949 | | |
950 | | inline int isAboveAvailable(const TransformUnit &tu, const ChannelType &chType, const Position &posLT, |
951 | | const uint32_t uiNumUnitsInPU, const uint32_t unitWidthLog2); |
952 | | inline int isLeftAvailable(const TransformUnit &tu, const ChannelType &chType, const Position &posLT, |
953 | | const uint32_t uiNumUnitsInPU, const uint32_t unitHeightLog2); |
954 | | |
955 | | void IntraPrediction::initIntraPatternChType(const TransformUnit &tu, const CompArea &area, const bool bFilterRefSamples) |
956 | 0 | { |
957 | 0 | CHECK( area.width == 2, "Width of 2 is not supported" ); |
958 | 0 | const CodingStructure& cs = *tu.cu->cs; |
959 | |
|
960 | 0 | Pel *refBufUnfiltered = m_piYuvExt[PRED_BUF_UNFILTERED]; |
961 | 0 | Pel *refBufFiltered = m_piYuvExt[PRED_BUF_FILTERED]; |
962 | |
|
963 | 0 | setReferenceArrayLengths( area ); |
964 | | |
965 | | // ----- Step 1: unfiltered reference samples ----- |
966 | 0 | xFillReferenceSamples( cs.picture->getRecoBuf( area ), refBufUnfiltered, area, tu ); |
967 | | // ----- Step 2: filtered reference samples ----- |
968 | 0 | if( bFilterRefSamples ) |
969 | 0 | { |
970 | 0 | xFilterReferenceSamples( refBufUnfiltered, refBufFiltered, area, *cs.sps , tu.cu->multiRefIdx() ); |
971 | 0 | } |
972 | 0 | } |
973 | | |
974 | | void IntraPrediction::initIntraPatternChTypeISP(const CodingUnit& cu, const CompArea& area, PelBuf& recBuf) |
975 | 0 | { |
976 | 0 | const CodingStructure& cs = *cu.cs; |
977 | |
|
978 | 0 | const Position &posLT = area.pos(); |
979 | 0 | bool isLeftAvail = nullptr != cs.getCURestricted( posLT.offset( -1, 0 ), cu, CH_L, posLT.x == cu.lx() ? cu.left : &cu ); |
980 | 0 | bool isAboveAvail = nullptr != cs.getCURestricted( posLT.offset( 0, -1 ), cu, CH_L, posLT.y == cu.ly() ? cu.left : &cu ); |
981 | | |
982 | | // ----- Step 1: unfiltered reference samples ----- |
983 | 0 | if( cu.blocks[area.compID()].x == area.x && cu.blocks[area.compID()].y == area.y ) |
984 | 0 | { |
985 | 0 | Pel* refBufUnfiltered = m_piYuvExt[PRED_BUF_UNFILTERED]; |
986 | | // With the first subpartition all the CU reference samples are fetched at once in a single call to xFillReferenceSamples |
987 | 0 | if( cu.ispMode() == HOR_INTRA_SUBPARTITIONS ) |
988 | 0 | { |
989 | 0 | m_leftRefLength = cu.Y().height << 1; |
990 | 0 | m_topRefLength = cu.Y().width + area.width; |
991 | 0 | } |
992 | 0 | else //if (cu.ispMode() == VER_INTRA_SUBPARTITIONS) |
993 | 0 | { |
994 | 0 | m_leftRefLength = cu.Y().height + area.height; |
995 | 0 | m_topRefLength = cu.Y().width << 1; |
996 | 0 | } |
997 | |
|
998 | 0 | const int srcStride = m_topRefLength + 1; |
999 | 0 | const int srcHStride = m_leftRefLength + 1; |
1000 | |
|
1001 | 0 | m_pelBufISP[0] = m_pelBufISPBase[0] = PelBuf(m_piYuvExt[PRED_BUF_UNFILTERED], srcStride, srcHStride); |
1002 | 0 | m_pelBufISP[1] = m_pelBufISPBase[1] = PelBuf(m_piYuvExt[PRED_BUF_FILTERED], srcStride, srcHStride); |
1003 | |
|
1004 | 0 | xFillReferenceSamples( cs.picture->getRecoBuf( cu.Y() ), refBufUnfiltered, cu.Y(), isLuma( area.compID() ) ? cu.firstTU : *cu.lastTU ); |
1005 | | |
1006 | | // After having retrieved all the CU reference samples, the number of reference samples is now adjusted for the current subpartition |
1007 | 0 | m_topRefLength = cu.blocks[area.compID()].width + area.width; |
1008 | 0 | m_leftRefLength = cu.blocks[area.compID()].height + area.height; |
1009 | 0 | } |
1010 | 0 | else |
1011 | 0 | { |
1012 | | //Now we only need to fetch the newly available reconstructed samples from the previously coded TU |
1013 | 0 | Position tuPos = area; |
1014 | 0 | tuPos.relativeTo(cu.Y()); |
1015 | 0 | m_pelBufISP[0] = m_pelBufISPBase[0].subBuf(tuPos, area.size()); |
1016 | 0 | m_pelBufISP[1] = m_pelBufISPBase[1].subBuf(tuPos, area.size()); |
1017 | |
|
1018 | 0 | PelBuf& dstBuf = m_pelBufISP[0]; |
1019 | |
|
1020 | 0 | m_topRefLength = cu.blocks[area.compID()].width + area.width; |
1021 | 0 | m_leftRefLength = cu.blocks[area.compID()].height + area.height; |
1022 | |
|
1023 | 0 | const int predSizeHor = m_topRefLength; |
1024 | 0 | const int predSizeVer = m_leftRefLength; |
1025 | 0 | if (cu.ispMode() == HOR_INTRA_SUBPARTITIONS) |
1026 | 0 | { |
1027 | 0 | Pel* src = recBuf.bufAt(0, -1); |
1028 | 0 | Pel* dst = dstBuf.bufAt(1, 0); |
1029 | 0 | for (int i = 0; i < area.width; i++) |
1030 | 0 | { |
1031 | 0 | dst[i] = src[i]; |
1032 | 0 | } |
1033 | 0 | Pel sample = src[area.width - 1]; |
1034 | 0 | dst += area.width; |
1035 | 0 | for (int i = 0; i < predSizeHor - area.width; i++) |
1036 | 0 | { |
1037 | 0 | dst[i] = sample; |
1038 | 0 | } |
1039 | 0 | if (!isLeftAvail) //if left is not avaible, then it is necessary to fetch these samples for each subpartition |
1040 | 0 | { |
1041 | 0 | Pel* dst = dstBuf.bufAt(0, 0); |
1042 | 0 | Pel sample = src[0]; |
1043 | 0 | for (int i = 0; i < predSizeVer + 1; i++) |
1044 | 0 | { |
1045 | 0 | *dst = sample; |
1046 | 0 | dst += dstBuf.stride; |
1047 | 0 | } |
1048 | 0 | } |
1049 | 0 | } |
1050 | 0 | else |
1051 | 0 | { |
1052 | 0 | Pel* src = recBuf.bufAt(-1, 0); |
1053 | 0 | Pel* dst = dstBuf.bufAt(0, 1); |
1054 | 0 | for (int i = 0; i < area.height; i++) |
1055 | 0 | { |
1056 | 0 | *dst = *src; |
1057 | 0 | src += recBuf.stride; |
1058 | 0 | dst += dstBuf.stride; |
1059 | 0 | } |
1060 | 0 | Pel sample = src[-recBuf.stride]; |
1061 | 0 | for (int i = 0; i < predSizeVer - area.height; i++) |
1062 | 0 | { |
1063 | 0 | *dst = sample; |
1064 | 0 | dst += dstBuf.stride; |
1065 | 0 | } |
1066 | |
|
1067 | 0 | if (!isAboveAvail) //if above is not avaible, then it is necessary to fetch these samples for each subpartition |
1068 | 0 | { |
1069 | 0 | Pel* dst = dstBuf.bufAt(0, 0); |
1070 | 0 | Pel sample = recBuf.at(-1, 0); |
1071 | 0 | for (int i = 0; i < predSizeHor + 1; i++) |
1072 | 0 | { |
1073 | 0 | dst[i] = sample; |
1074 | 0 | } |
1075 | 0 | } |
1076 | 0 | } |
1077 | 0 | } |
1078 | 0 | } |
1079 | | |
1080 | | void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBufUnfiltered, const CompArea &area, const TransformUnit &tu ) |
1081 | 0 | { |
1082 | 0 | const ChannelType chType = toChannelType( area.compID() ); |
1083 | 0 | const CodingUnit &cu = *tu.cu; |
1084 | 0 | const CodingStructure &cs = *cu.cs; |
1085 | 0 | const SPS &sps = *cs.sps; |
1086 | 0 | const PreCalcValues &pcv = *cs.pcv; |
1087 | |
|
1088 | 0 | const int multiRefIdx = (area.compID() == COMPONENT_Y) ? cu.multiRefIdx() : 0; |
1089 | |
|
1090 | 0 | const int tuWidth = area.width; |
1091 | 0 | const int tuHeight = area.height; |
1092 | 0 | const int predSize = m_topRefLength; |
1093 | 0 | const int predHSize = m_leftRefLength; |
1094 | 0 | const int predStride = predSize + 1 + multiRefIdx; |
1095 | |
|
1096 | 0 | const int csx = getChannelTypeScaleX( chType, pcv.chrFormat ); |
1097 | 0 | const int csy = getChannelTypeScaleY( chType, pcv.chrFormat ); |
1098 | | |
1099 | | // the unit sizes are powers of two, so shifts replace the divisions by them |
1100 | 0 | const int unitWidthLog2 = pcv.minCUWidthLog2 - csx; |
1101 | 0 | const int unitHeightLog2 = pcv.minCUHeightLog2 - csy; |
1102 | 0 | const int unitWidth = 1 << unitWidthLog2; |
1103 | 0 | const int unitHeight = 1 << unitHeightLog2; |
1104 | |
|
1105 | 0 | const int totalAboveUnits = (predSize + (unitWidth - 1)) >> unitWidthLog2; |
1106 | 0 | const int totalLeftUnits = (predHSize + (unitHeight - 1)) >> unitHeightLog2; |
1107 | 0 | const int totalUnits = totalAboveUnits + totalLeftUnits + 1; //+1 for top-left |
1108 | 0 | const int numAboveUnits = tuWidth >> unitWidthLog2; |
1109 | 0 | const int numLeftUnits = tuHeight >> unitHeightLog2; |
1110 | 0 | const int numAboveRightUnits = totalAboveUnits - numAboveUnits; |
1111 | 0 | const int numLeftBelowUnits = totalLeftUnits - numLeftUnits; |
1112 | |
|
1113 | 0 | CHECK( numAboveUnits <= 0 || numLeftUnits <= 0 || numAboveRightUnits <= 0 || numLeftBelowUnits <= 0, "Size not supported" ); |
1114 | | |
1115 | | // ----- Step 1: analyze neighborhood ----- |
1116 | 0 | if( m_lastCUidx == tu.cu->idx && area.compID() != getFirstComponentOfChannel( tu.cu->chType() ) ) |
1117 | 0 | { |
1118 | 0 | } |
1119 | 0 | else |
1120 | 0 | { |
1121 | 0 | const Position posLT = area.pos(); |
1122 | | |
1123 | 0 | const bool sameCTUx = !!( posLT.x & ( pcv.maxCUWidthMask >> csx ) ); |
1124 | 0 | const bool sameCTUy = !!( posLT.y & ( pcv.maxCUHeightMask >> csy ) ); |
1125 | 0 | const bool sameCTU = sameCTUx && sameCTUy; |
1126 | |
|
1127 | 0 | m_neighborSize[0] = sameCTU ? 1 : !!cu.cs->getCURestricted( posLT.offset( -1, -1 ), cu, chType, cu.left ? cu.left : cu.above ); |
1128 | |
|
1129 | 0 | if( cu.above || area.y > tu.cu->blocks[chType].y ) |
1130 | 0 | { |
1131 | 0 | m_neighborSize[1] = numAboveUnits; |
1132 | |
|
1133 | 0 | Position posAR{ posLT.x + ( PosType ) area.width, posLT.y }; |
1134 | 0 | m_neighborSize[1] += isAboveAvailable( tu, chType, posAR, numAboveRightUnits, unitWidthLog2 ); |
1135 | 0 | } |
1136 | 0 | else |
1137 | 0 | m_neighborSize[1] = 0; |
1138 | |
|
1139 | 0 | if( cu.left || area.x > tu.cu->blocks[chType].x ) |
1140 | 0 | { |
1141 | 0 | m_neighborSize[2] = numLeftUnits; |
1142 | |
|
1143 | 0 | Position posLB{ posLT.x, posLT.y + ( PosType ) area.height }; |
1144 | 0 | m_neighborSize[2] += isLeftAvailable( tu, chType, posLB, numLeftBelowUnits, unitHeightLog2 ); |
1145 | 0 | } |
1146 | 0 | else |
1147 | 0 | m_neighborSize[2] = 0; |
1148 | |
|
1149 | 0 | m_lastCUidx = tu.cu->idx; |
1150 | 0 | } |
1151 | |
|
1152 | 0 | int numIntraNeighbor = m_neighborSize[0] + m_neighborSize[1] + m_neighborSize[2]; |
1153 | | |
1154 | | // ----- Step 2: fill reference samples (depending on neighborhood) ----- |
1155 | 0 | const Pel* srcBuf = recoBuf.buf; |
1156 | 0 | const ptrdiff_t srcStride = recoBuf.stride; |
1157 | 0 | Pel* ptrDst = refBufUnfiltered; |
1158 | 0 | const Pel* ptrSrc; |
1159 | 0 | const Pel valueDC = 1 << (sps.getBitDepth() - 1); |
1160 | |
|
1161 | 0 | if( numIntraNeighbor == 0 ) |
1162 | 0 | { |
1163 | | // Fill border with DC value |
1164 | 0 | for (int j = 0; j <= predSize + multiRefIdx; j++) { ptrDst[j] = valueDC; } |
1165 | 0 | for (int i = 1; i <= predHSize + multiRefIdx; i++) { ptrDst[i*predStride] = valueDC; } |
1166 | 0 | } |
1167 | 0 | else if( numIntraNeighbor == totalUnits ) |
1168 | 0 | { |
1169 | | // Fill top-left border and top and top right with rec. samples |
1170 | 0 | ptrSrc = srcBuf - (1 + multiRefIdx) * srcStride - (1 + multiRefIdx); |
1171 | 0 | for (int j = 0; j <= predSize + multiRefIdx; j++) { ptrDst[j] = ptrSrc[j]; } |
1172 | 0 | ptrSrc = srcBuf - multiRefIdx * srcStride - (1 + multiRefIdx); |
1173 | 0 | for (int i = 1; i <= predHSize + multiRefIdx; i++) { ptrDst[i*predStride] = *(ptrSrc); ptrSrc += srcStride; } |
1174 | 0 | } |
1175 | 0 | else // reference samples are partially available |
1176 | 0 | { |
1177 | | // Fill top-left sample(s) if available |
1178 | 0 | if ( m_neighborSize[2] > 0) { // left is available |
1179 | | // Fill left & below-left samples if available (downwards) |
1180 | 0 | ptrSrc = srcBuf - (1 + multiRefIdx); |
1181 | 0 | ptrDst = refBufUnfiltered + (1 + multiRefIdx) * predStride; |
1182 | 0 | int tmpSize = m_neighborSize[2] * unitHeight; |
1183 | 0 | tmpSize = std::min(tmpSize, predHSize); |
1184 | 0 | for (int i = 0; i < tmpSize; i++) { |
1185 | 0 | ptrDst[i * predStride] = ptrSrc[i * srcStride]; |
1186 | 0 | } |
1187 | | |
1188 | | // pad |
1189 | 0 | Pel tmpPixel = ptrDst[(tmpSize - 1) * predStride]; |
1190 | 0 | for (int i = tmpSize; i < predHSize; i++) { |
1191 | 0 | ptrDst[i * predStride] = tmpPixel; |
1192 | 0 | } |
1193 | | |
1194 | | // Fill top-left sample(s) if available |
1195 | 0 | if ( m_neighborSize[0]) { |
1196 | 0 | ptrSrc = srcBuf - (1 + multiRefIdx) * srcStride - (1 + multiRefIdx); |
1197 | 0 | ptrDst = refBufUnfiltered; |
1198 | 0 | memcpy(ptrDst, ptrSrc, sizeof(Pel) * (multiRefIdx + 1)); |
1199 | 0 | for (int i = 1; i <= multiRefIdx; i++) { |
1200 | 0 | ptrDst[i * predStride] = ptrSrc[i * srcStride]; |
1201 | 0 | } |
1202 | 0 | } else { // pad |
1203 | 0 | ptrSrc = srcBuf - (1 + multiRefIdx); // left pixel |
1204 | 0 | ptrDst = refBufUnfiltered; |
1205 | 0 | tmpPixel = ptrSrc[0]; |
1206 | 0 | ptrDst[0] = tmpPixel; |
1207 | 0 | for (int i = 1; i <= multiRefIdx; i++) { |
1208 | 0 | ptrDst[i] = tmpPixel; |
1209 | 0 | ptrDst[i * predStride] = tmpPixel; |
1210 | 0 | } |
1211 | 0 | } |
1212 | | |
1213 | | // Fill above & above-right samples if available (left-to-right) |
1214 | 0 | if ( m_neighborSize[1]) { |
1215 | 0 | ptrSrc = srcBuf - srcStride * (1 + multiRefIdx); |
1216 | 0 | ptrDst = refBufUnfiltered + 1 + multiRefIdx; |
1217 | 0 | tmpSize = m_neighborSize[1] * unitWidth; |
1218 | 0 | tmpSize = std::min(tmpSize, predSize); |
1219 | 0 | memcpy(ptrDst, ptrSrc, tmpSize * sizeof(Pel)); |
1220 | | // pad |
1221 | 0 | Pel tmpPixel = ptrDst[tmpSize - 1]; |
1222 | 0 | for (int i = tmpSize; i < predSize; i++) { |
1223 | 0 | ptrDst[i] = tmpPixel; |
1224 | 0 | } |
1225 | 0 | } else { // all not available, pad |
1226 | 0 | ptrSrc = srcBuf - srcStride * (1 + multiRefIdx); |
1227 | 0 | ptrDst = refBufUnfiltered + 1 + multiRefIdx; |
1228 | 0 | Pel tmpPixel = ptrDst[-1]; |
1229 | 0 | std::fill_n(ptrDst, predSize, tmpPixel); |
1230 | 0 | } |
1231 | 0 | } else { // left is not available, top must be available |
1232 | | // Fill above & above-right samples (left-to-right) |
1233 | 0 | ptrSrc = srcBuf - srcStride * (1 + multiRefIdx); |
1234 | 0 | ptrDst = refBufUnfiltered + 1 + multiRefIdx; |
1235 | 0 | int tmpSize = m_neighborSize[1] * unitWidth; |
1236 | 0 | tmpSize = std::min(tmpSize, predSize); |
1237 | 0 | memcpy(ptrDst, ptrSrc, tmpSize * sizeof(Pel)); |
1238 | | // pad |
1239 | 0 | Pel tmpPixel = ptrDst[tmpSize - 1]; |
1240 | 0 | for (int i = tmpSize; i < predSize; i++) { |
1241 | 0 | ptrDst[i] = tmpPixel; |
1242 | 0 | } |
1243 | |
|
1244 | 0 | tmpPixel = ptrSrc[0]; |
1245 | | // pad top-left sample(s) |
1246 | 0 | ptrDst = refBufUnfiltered; |
1247 | 0 | ptrDst[0] = tmpPixel; |
1248 | 0 | for (int i = 1; i <= multiRefIdx; i++) { |
1249 | 0 | ptrDst[i] = tmpPixel; |
1250 | 0 | ptrDst[i * predStride] = tmpPixel; |
1251 | 0 | } |
1252 | | |
1253 | | // pad left sample(s) |
1254 | 0 | ptrDst = refBufUnfiltered + (1 + multiRefIdx) * predStride; |
1255 | 0 | for (int i = 0; i < predHSize; i++) { |
1256 | 0 | ptrDst[i * predStride] = tmpPixel; |
1257 | 0 | } |
1258 | 0 | } |
1259 | 0 | } |
1260 | 0 | } |
1261 | | |
1262 | | void IntraPrediction::xFilterReferenceSamples( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps, int multiRefIdx, ptrdiff_t stride ) const |
1263 | 0 | { |
1264 | 0 | if (area.compID() != COMPONENT_Y) |
1265 | 0 | { |
1266 | 0 | multiRefIdx = 0; |
1267 | 0 | } |
1268 | 0 | const int predSize = m_topRefLength + multiRefIdx; |
1269 | 0 | const int predHSize = m_leftRefLength + multiRefIdx; |
1270 | 0 | const ptrdiff_t predStride = stride == 0 ? predSize + 1 : stride; |
1271 | | |
1272 | | |
1273 | | |
1274 | | // Regular reference sample filter |
1275 | 0 | const Pel *piSrcPtr = refBufUnfiltered + (predStride * predHSize); // bottom left |
1276 | 0 | Pel *piDestPtr = refBufFiltered + (predStride * predHSize); // bottom left |
1277 | | |
1278 | | // bottom left (not filtered) |
1279 | 0 | *piDestPtr = *piSrcPtr; |
1280 | 0 | piDestPtr -= predStride; |
1281 | 0 | piSrcPtr -= predStride; |
1282 | | //left column (bottom to top) |
1283 | 0 | for( int i = 1; i < predHSize; i++, piDestPtr -= predStride, piSrcPtr -= predStride) |
1284 | 0 | { |
1285 | 0 | *piDestPtr = (piSrcPtr[predStride] + 2 * piSrcPtr[0] + piSrcPtr[-predStride] + 2) >> 2; |
1286 | 0 | } |
1287 | | //top-left |
1288 | 0 | *piDestPtr = (piSrcPtr[predStride] + 2 * piSrcPtr[0] + piSrcPtr[1] + 2) >> 2; |
1289 | 0 | piDestPtr++; |
1290 | 0 | piSrcPtr++; |
1291 | | //top row (left-to-right) |
1292 | 0 | for( uint32_t i=1; i < predSize; i++, piDestPtr++, piSrcPtr++ ) |
1293 | 0 | { |
1294 | 0 | *piDestPtr = (piSrcPtr[1] + 2 * piSrcPtr[0] + piSrcPtr[-1] + 2) >> 2; |
1295 | 0 | } |
1296 | | // top right (not filtered) |
1297 | 0 | *piDestPtr=*piSrcPtr; |
1298 | 0 | } |
1299 | | |
1300 | | static bool getUseFilterRef( const int predMode ) |
1301 | 0 | { |
1302 | 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 }; |
1303 | |
|
1304 | 0 | const int intraPredAngleMode = ( predMode >= DIA_IDX ) ? predMode - VER_IDX : -( predMode - HOR_IDX ); |
1305 | |
|
1306 | 0 | const int absAngMode = abs(intraPredAngleMode); |
1307 | 0 | const int absAng = angTable [absAngMode]; |
1308 | |
|
1309 | 0 | return 0 == ( absAng & 0x1F ); |
1310 | 0 | } |
1311 | | |
1312 | | bool IntraPrediction::useFilteredIntraRefSamples( const ComponentID &compID, const CodingUnit &cu, const UnitArea &tuArea ) |
1313 | 0 | { |
1314 | | //const SPS &sps = *cu.sps; |
1315 | 0 | const ChannelType chType = toChannelType( compID ); |
1316 | | |
1317 | | // high level conditions |
1318 | | //if( sps.getSpsRangeExtension().getIntraSmoothingDisabledFlag() ) { return false; } |
1319 | | //if( !isLuma( chType ) ) { return false; } |
1320 | | //if( cu.ispMode() && isLuma(compID) ) { return false; } |
1321 | | //if( CU::isMIP( cu, chType ) ) { return false; } |
1322 | 0 | if( cu.multiRefIdx() ) { return false; } |
1323 | 0 | if( cu.bdpcmMode() ) { return false; } |
1324 | | |
1325 | | // pred. mode related conditions |
1326 | 0 | const int dirMode = PU::getFinalIntraMode( cu, chType ); |
1327 | 0 | if (dirMode == DC_IDX) { return false; } |
1328 | 0 | if (dirMode == PLANAR_IDX) |
1329 | 0 | { |
1330 | 0 | return tuArea.blocks[compID].area() > 32 ? true : false; |
1331 | 0 | } |
1332 | | |
1333 | 0 | const int predMode = getWideAngle(tuArea.blocks[compID].width, tuArea.blocks[compID].height, dirMode); |
1334 | 0 | const int diff = std::min<int>( abs( predMode - HOR_IDX ), abs( predMode - VER_IDX ) ); |
1335 | 0 | const int log2Size = ( ( getLog2( tuArea.blocks[compID].width ) + getLog2( tuArea.blocks[compID].height ) ) >> 1 ); |
1336 | 0 | CHECKD( log2Size >= MAX_INTRA_FILTER_DEPTHS, "Size not supported" ); |
1337 | 0 | return diff > m_aucIntraFilter[ chType ][ log2Size ] && getUseFilterRef( predMode ); |
1338 | 0 | } |
1339 | | |
1340 | | static inline TransformUnit const* getTU( const CodingUnit& cu, const Position& pos, const ChannelType chType ) |
1341 | 0 | { |
1342 | 0 | const TransformUnit* ptu = &cu.firstTU; |
1343 | |
|
1344 | 0 | if( !ptu->next ) return ptu; |
1345 | | |
1346 | 0 | while( !( ptu->blocks[chType].x + ptu->blocks[chType].width > pos.x && ptu->blocks[chType].y + ptu->blocks[chType].height > pos.y ) ) |
1347 | 0 | { |
1348 | 0 | ptu = ptu->next; |
1349 | 0 | } |
1350 | |
|
1351 | 0 | return ptu; |
1352 | 0 | } |
1353 | | |
1354 | | int isAboveAvailable(const TransformUnit &tu, const ChannelType &chType, const Position &posLT, |
1355 | | const uint32_t uiNumUnitsInPU, const uint32_t unitWidthLog2) |
1356 | 0 | { |
1357 | 0 | const CodingUnit &cu = *tu.cu; |
1358 | 0 | const CodingStructure &cs = *cu.cs; |
1359 | |
|
1360 | 0 | int maxDx = uiNumUnitsInPU << unitWidthLog2; |
1361 | 0 | Position refPos = posLT.offset(0, -1); |
1362 | 0 | const TransformUnit *pcTUAbove = nullptr; |
1363 | 0 | const int currTUIdx = tu.idx; |
1364 | 0 | int dx = 0; |
1365 | |
|
1366 | 0 | while( dx < maxDx ) |
1367 | 0 | { |
1368 | 0 | const CodingUnit* cuAbove = cs.getCURestricted( refPos, cu, chType, pcTUAbove ? nullptr : cu.above ); |
1369 | |
|
1370 | 0 | if( !cuAbove ) break; |
1371 | 0 | pcTUAbove = getTU( *cuAbove, refPos, chType ); |
1372 | 0 | if( cuAbove->ctuData == cu.ctuData && pcTUAbove->idx >= currTUIdx ) break; |
1373 | | |
1374 | 0 | int diff = ( int ) pcTUAbove->blocks[chType].width - refPos.x + pcTUAbove->blocks[chType].x; |
1375 | 0 | dx += diff; |
1376 | 0 | refPos.x += diff; |
1377 | 0 | } |
1378 | |
|
1379 | 0 | int neighborSize = dx >> unitWidthLog2; |
1380 | 0 | neighborSize = std::min<int>( neighborSize, uiNumUnitsInPU ); |
1381 | 0 | return neighborSize; |
1382 | 0 | } |
1383 | | |
1384 | | int isLeftAvailable(const TransformUnit &tu, const ChannelType &chType, const Position &posLT, |
1385 | | const uint32_t uiNumUnitsInPU, const uint32_t unitHeightLog2) |
1386 | 0 | { |
1387 | 0 | const CodingUnit &cu = *tu.cu; |
1388 | 0 | const CodingStructure &cs = *cu.cs; |
1389 | |
|
1390 | 0 | int maxDy = uiNumUnitsInPU << unitHeightLog2; |
1391 | 0 | Position refPos = posLT.offset(-1, 0); |
1392 | 0 | const TransformUnit *pcTULeft = nullptr; |
1393 | 0 | int currTUIdx = tu.idx; |
1394 | 0 | int dy = 0; |
1395 | |
|
1396 | 0 | while( dy < maxDy ) |
1397 | 0 | { |
1398 | 0 | const CodingUnit* cuLeft = cs.getCURestricted( refPos, cu, chType, pcTULeft ? nullptr : cu.left ); |
1399 | |
|
1400 | 0 | if( !cuLeft ) break; |
1401 | 0 | pcTULeft = getTU( *cuLeft, refPos, chType ); |
1402 | 0 | if( cuLeft->ctuData == cu.ctuData && pcTULeft->idx >= currTUIdx ) break; |
1403 | | |
1404 | 0 | int diff = ( int ) pcTULeft->blocks[chType].height - refPos.y + pcTULeft->blocks[chType].y; |
1405 | 0 | dy += diff; |
1406 | 0 | refPos.y += diff; |
1407 | 0 | } |
1408 | |
|
1409 | 0 | int neighborSize = dy >> unitHeightLog2; |
1410 | 0 | neighborSize = std::min<int>( neighborSize, uiNumUnitsInPU ); |
1411 | 0 | return neighborSize; |
1412 | 0 | } |
1413 | | // LumaRecPixels |
1414 | | NO_THREAD_SANITIZE void IntraPrediction::xGetLumaRecPixels(const CodingUnit &cu, CompArea chromaArea) |
1415 | 0 | { |
1416 | 0 | int iDstStride = 0; |
1417 | 0 | Pel* pDst0 = 0; |
1418 | 0 | int curChromaMode = cu.intraDir[1]; |
1419 | 0 | if ((curChromaMode == MDLM_L_IDX) || (curChromaMode == MDLM_T_IDX)) |
1420 | 0 | { |
1421 | 0 | iDstStride = 2 * MAX_TU_SIZE_FOR_PROFILE + 1; |
1422 | 0 | pDst0 = m_piYuvExt[1] + iDstStride + 1; |
1423 | 0 | } |
1424 | 0 | else |
1425 | 0 | { |
1426 | 0 | iDstStride = MAX_TU_SIZE_FOR_PROFILE + 1; |
1427 | 0 | pDst0 = m_piYuvExt[1] + iDstStride + 1; //MMLM_SAMPLE_NEIGHBOR_LINES; |
1428 | 0 | } |
1429 | | //assert 420 chroma subsampling |
1430 | 0 | CompArea lumaArea = CompArea( COMPONENT_Y, chromaArea.lumaPos( cu.chromaFormat), |
1431 | 0 | recalcSize( cu.chromaFormat, CHANNEL_TYPE_CHROMA, CHANNEL_TYPE_LUMA, chromaArea.size() ) );//needed for correct pos/size (4x4 Tus) |
1432 | | |
1433 | |
|
1434 | 0 | CHECK( lumaArea.width == chromaArea.width && CHROMA_444 != cu.chromaFormat, "" ); |
1435 | 0 | CHECK( lumaArea.height == chromaArea.height && CHROMA_444 != cu.chromaFormat && CHROMA_422 != cu.chromaFormat, "" ); |
1436 | |
|
1437 | 0 | const SizeType uiCWidth = chromaArea.width; |
1438 | 0 | const SizeType uiCHeight = chromaArea.height; |
1439 | |
|
1440 | 0 | CPelBuf Src = cu.cs->picture->getRecoBuf( lumaArea ); |
1441 | 0 | Pel const* pRecSrc0 = Src.bufAt( 0, 0 ); |
1442 | 0 | ptrdiff_t iRecStride = Src.stride; |
1443 | 0 | int logSubWidthC = getChannelTypeScaleX(CHANNEL_TYPE_CHROMA, cu.chromaFormat); |
1444 | 0 | int logSubHeightC = getChannelTypeScaleY(CHANNEL_TYPE_CHROMA, cu.chromaFormat); |
1445 | | |
1446 | |
|
1447 | 0 | ptrdiff_t iRecStride2 = iRecStride << logSubHeightC; // TODO: really Height here? not Width? |
1448 | 0 | const int mult = 1 << logSubWidthC ; |
1449 | |
|
1450 | 0 | const CompArea& area = isChroma( cu.chType() ) ? chromaArea : lumaArea; |
1451 | |
|
1452 | 0 | const uint32_t uiTuWidth = area.width; |
1453 | 0 | const uint32_t uiTuHeight = area.height; |
1454 | |
|
1455 | 0 | int iBaseUnitSize = ( 1 << MIN_CU_LOG2 ); |
1456 | |
|
1457 | 0 | const int iUnitWidth = iBaseUnitSize >> getComponentScaleX( area.compID(), cu.chromaFormat ); |
1458 | 0 | const int iUnitHeight = iBaseUnitSize >> getComponentScaleY( area.compID(), cu.chromaFormat ); |
1459 | 0 | const int iTUWidthInUnits = uiTuWidth / iUnitWidth; |
1460 | 0 | const int iTUHeightInUnits = uiTuHeight / iUnitHeight; |
1461 | 0 | const int iAboveUnits = iTUWidthInUnits; |
1462 | 0 | const int iLeftUnits = iTUHeightInUnits; |
1463 | 0 | const int chromaUnitWidth = iBaseUnitSize >> getComponentScaleX(COMPONENT_Cb, cu.chromaFormat); |
1464 | 0 | const int chromaUnitHeight = iBaseUnitSize >> getComponentScaleY(COMPONENT_Cb, cu.chromaFormat); |
1465 | 0 | const int topTemplateSampNum = 2 * uiCWidth; // for MDLM, the number of template samples is 2W or 2H. |
1466 | 0 | const int leftTemplateSampNum = 2 * uiCHeight; |
1467 | 0 | CHECKD( !( m_topRefLength >= topTemplateSampNum ), "Error!" ); |
1468 | 0 | CHECKD( !( m_leftRefLength >= leftTemplateSampNum ), "Error!" ); |
1469 | 0 | int totalAboveUnits = (curChromaMode == MDLM_T_IDX) ? (topTemplateSampNum + (chromaUnitWidth - 1)) / chromaUnitWidth : iAboveUnits; |
1470 | 0 | int totalLeftUnits = (curChromaMode == MDLM_L_IDX) ? (leftTemplateSampNum + (chromaUnitHeight - 1)) / chromaUnitHeight : iLeftUnits; |
1471 | |
|
1472 | 0 | const int availlableLeftUnit = ( cu.left || chromaArea.x > cu.blocks[CH_C].x ) ? totalLeftUnits : 0; |
1473 | 0 | const bool bLeftAvaillable = availlableLeftUnit >= iTUHeightInUnits; |
1474 | | |
1475 | 0 | const int availlableAboveUnit = ( cu.above || chromaArea.y > cu.blocks[CH_C].y ) ? totalAboveUnits : 0; |
1476 | 0 | const bool bAboveAvaillable = availlableAboveUnit >= iTUWidthInUnits; |
1477 | |
|
1478 | 0 | Pel* pDst = nullptr; |
1479 | 0 | Pel const* piSrc = nullptr; |
1480 | |
|
1481 | 0 | bool isFirstRowOfCtu = ( lumaArea.y & ( cu.sps->getCTUSize() - 1) ) == 0; |
1482 | 0 | const ptrdiff_t strOffset = ( CHROMA_444 == cu.chromaFormat ) ? 0 : iRecStride; |
1483 | |
|
1484 | 0 | int c0_3tap = 2, c1_3tap = 1, c2_3tap = 1, offset_3tap = 2, shift_3tap = 2; //sum = 4 |
1485 | 0 | int c0_5tap = 1, c1_5tap = 4, c2_5tap = 1, c3_5tap = 1, c4_5tap = 1, offset_5tap = 4, shift_5tap = 3; //sum = 8 |
1486 | 0 | int c0_6tap = 2, c1_6tap = 1, c2_6tap = 1, c3_6tap = 2, c4_6tap = 1, c5_6tap = 1, offset_6tap = 4, shift_6tap = 3; //sum = 8 |
1487 | |
|
1488 | 0 | switch (cu.chromaFormat) |
1489 | 0 | { |
1490 | 0 | case CHROMA_422: //overwrite filter coefficient values for 422 |
1491 | 0 | c0_3tap = 2, c1_3tap = 1, c2_3tap = 1, offset_3tap = 2, shift_3tap = 2; //sum = 4 |
1492 | 0 | c0_5tap = 0, c1_5tap = 2, c2_5tap = 1, c3_5tap = 1, c4_5tap = 0, offset_5tap = 2, shift_5tap = 2; //sum = 4 |
1493 | 0 | c0_6tap = 2, c1_6tap = 1, c2_6tap = 1, c3_6tap = 0, c4_6tap = 0, c5_6tap = 0, offset_6tap = 2, shift_6tap = 2; //sum = 4 |
1494 | 0 | break; |
1495 | | |
1496 | 0 | case CHROMA_444: //overwrite filter coefficient values for 444 |
1497 | 0 | c0_3tap = 1, c1_3tap = 0, c2_3tap = 0, offset_3tap = 0, shift_3tap = 0; //sum = 1 |
1498 | 0 | c0_5tap = 0, c1_5tap = 1, c2_5tap = 0, c3_5tap = 0, c4_5tap = 0, offset_5tap = 0, shift_5tap = 0; //sum = 1 |
1499 | 0 | c0_6tap = 1, c1_6tap = 0, c2_6tap = 0, c3_6tap = 0, c4_6tap = 0, c5_6tap = 0, offset_6tap = 0, shift_6tap = 0; //sum = 1 |
1500 | 0 | break; |
1501 | | |
1502 | 0 | default: |
1503 | 0 | break; |
1504 | 0 | } |
1505 | | |
1506 | 0 | if( bAboveAvaillable ) |
1507 | 0 | { |
1508 | 0 | pDst = pDst0 - iDstStride; |
1509 | 0 | int avaiAboveSizes = availlableAboveUnit * chromaUnitWidth; |
1510 | 0 | for (int i = 0; i < avaiAboveSizes; i++) |
1511 | 0 | { |
1512 | 0 | if (isFirstRowOfCtu) |
1513 | 0 | { |
1514 | 0 | piSrc = pRecSrc0 - iRecStride; |
1515 | |
|
1516 | 0 | if ((i == 0 && !bLeftAvaillable) || (i == uiCWidth + avaiAboveSizes - 1 + logSubWidthC)) |
1517 | 0 | { |
1518 | 0 | pDst[i] = (piSrc[mult * i] * c0_3tap + piSrc[mult * i] * c1_3tap + piSrc[mult * i + 1] * c2_3tap + offset_3tap) >> shift_3tap; |
1519 | 0 | } |
1520 | 0 | else |
1521 | 0 | { |
1522 | 0 | pDst[i] = (piSrc[mult * i] * c0_3tap + piSrc[mult * i - 1] * c1_3tap + piSrc[mult * i + 1] * c2_3tap + offset_3tap) >> shift_3tap; |
1523 | 0 | } |
1524 | 0 | } |
1525 | 0 | else if( cu.sps->getCclmCollocatedChromaFlag() ) |
1526 | 0 | { |
1527 | 0 | piSrc = pRecSrc0 - iRecStride2; |
1528 | |
|
1529 | 0 | if ((i == 0 && !bLeftAvaillable) || (i == uiCWidth + avaiAboveSizes - 1 + logSubWidthC)) |
1530 | 0 | { |
1531 | 0 | pDst[i] = (piSrc[mult * i - strOffset] * c0_5tap |
1532 | 0 | + piSrc[mult * i] * c1_5tap + piSrc[mult * i] * c2_5tap + piSrc[mult * i + 1] * c3_5tap |
1533 | 0 | + piSrc[mult * i + strOffset] * c4_5tap |
1534 | 0 | + offset_5tap) >> shift_5tap; |
1535 | 0 | } |
1536 | 0 | else |
1537 | 0 | { |
1538 | 0 | pDst[i] = (piSrc[mult * i - strOffset] * c0_5tap |
1539 | 0 | + piSrc[mult * i] * c1_5tap + piSrc[mult * i - 1] * c2_5tap + piSrc[mult * i + 1] * c3_5tap |
1540 | 0 | + piSrc[mult * i + strOffset] * c4_5tap |
1541 | 0 | + offset_5tap) >> shift_5tap; |
1542 | 0 | } |
1543 | 0 | } |
1544 | 0 | else |
1545 | 0 | { |
1546 | 0 | piSrc = pRecSrc0 - iRecStride2; |
1547 | |
|
1548 | 0 | if ((i == 0 && !bLeftAvaillable) || (i == uiCWidth + avaiAboveSizes - 1 + logSubWidthC)) |
1549 | 0 | { |
1550 | 0 | pDst[i] = ((piSrc[mult * i] * c0_6tap + piSrc[mult * i] * c1_6tap + piSrc[mult * i + 1] * c2_6tap) |
1551 | 0 | + (piSrc[mult * i + strOffset] * c3_6tap + piSrc[mult * i + strOffset] * c4_6tap + piSrc[mult * i + 1 + strOffset] * c5_6tap) |
1552 | 0 | + offset_6tap) >> shift_6tap; |
1553 | 0 | } |
1554 | 0 | else |
1555 | 0 | { |
1556 | 0 | pDst[i] = ((piSrc[mult * i] * c0_6tap + piSrc[mult * i - 1] * c1_6tap + piSrc[mult * i + 1] * c2_6tap) |
1557 | 0 | + (piSrc[mult * i + strOffset] * c3_6tap + piSrc[mult * i - 1 + strOffset] * c4_6tap + piSrc[mult * i + 1 + strOffset] * c5_6tap) |
1558 | 0 | + offset_6tap) >> shift_6tap; |
1559 | 0 | } |
1560 | 0 | } |
1561 | 0 | } |
1562 | 0 | } |
1563 | |
|
1564 | 0 | if( bLeftAvaillable ) |
1565 | 0 | { |
1566 | 0 | pDst = pDst0 - 1; |
1567 | |
|
1568 | 0 | piSrc = pRecSrc0 - 2 - logSubWidthC; |
1569 | |
|
1570 | 0 | int availlableLeftSizes = availlableLeftUnit * chromaUnitHeight; |
1571 | 0 | for (int j = 0; j < availlableLeftSizes; j++) |
1572 | 0 | { |
1573 | 0 | if( cu.sps->getCclmCollocatedChromaFlag() ) |
1574 | 0 | { |
1575 | 0 | if ((j == 0 && !bAboveAvaillable) || (j == uiCHeight + availlableLeftSizes - 1 + logSubWidthC)) |
1576 | 0 | { |
1577 | 0 | pDst[0] = ( piSrc[1 ] * c0_5tap |
1578 | 0 | + piSrc[1 ] * c1_5tap + piSrc[0] * c2_5tap + piSrc[2] * c3_5tap |
1579 | 0 | + piSrc[1 + strOffset] * c4_5tap |
1580 | 0 | + offset_5tap ) >> shift_5tap; |
1581 | 0 | } |
1582 | 0 | else |
1583 | 0 | { |
1584 | 0 | pDst[0] = ( piSrc[1 - strOffset] * c0_5tap |
1585 | 0 | + piSrc[1 ] * c1_5tap + piSrc[0] * c2_5tap + piSrc[2] * c3_5tap |
1586 | 0 | + piSrc[1 + strOffset] * c4_5tap |
1587 | 0 | + offset_5tap ) >> shift_5tap; |
1588 | 0 | } |
1589 | 0 | } |
1590 | 0 | else |
1591 | 0 | { |
1592 | 0 | pDst[0] = ((piSrc[1] * c0_6tap + piSrc[0] * c1_6tap + piSrc[2] * c2_6tap) |
1593 | 0 | + (piSrc[1 + strOffset] * c3_6tap + piSrc[strOffset] * c4_6tap + piSrc[2 + strOffset] * c5_6tap) |
1594 | 0 | + offset_6tap) >> shift_6tap; |
1595 | 0 | } |
1596 | |
|
1597 | 0 | piSrc += iRecStride2; |
1598 | 0 | pDst += iDstStride; |
1599 | 0 | } |
1600 | 0 | } |
1601 | |
|
1602 | 0 | if( cu.sps->getCclmCollocatedChromaFlag() ) |
1603 | 0 | { |
1604 | | // TODO: unroll loop |
1605 | 0 | for( int j = 0; j < uiCHeight; j++ ) |
1606 | 0 | { |
1607 | 0 | for( int i = 0; i < uiCWidth; i++ ) |
1608 | 0 | { |
1609 | 0 | if( i == 0 && !bLeftAvaillable ) |
1610 | 0 | { |
1611 | 0 | if( j == 0 && !bAboveAvaillable ) |
1612 | 0 | { |
1613 | 0 | pDst0[i] = (pRecSrc0[mult * i] * c0_5tap |
1614 | 0 | + pRecSrc0[mult * i] * c1_5tap + pRecSrc0[mult * i] * c2_5tap + pRecSrc0[mult * i + 1] * c3_5tap |
1615 | 0 | + pRecSrc0[mult * i + strOffset] * c4_5tap |
1616 | 0 | + offset_5tap) >> shift_5tap; |
1617 | 0 | } |
1618 | 0 | else |
1619 | 0 | { |
1620 | 0 | pDst0[i] = (pRecSrc0[mult * i - strOffset] * c0_5tap |
1621 | 0 | + pRecSrc0[mult * i] * c1_5tap + pRecSrc0[mult * i] * c2_5tap + pRecSrc0[mult * i + 1] * c3_5tap |
1622 | 0 | + pRecSrc0[mult * i + strOffset] * c4_5tap |
1623 | 0 | + offset_5tap) >> shift_5tap; |
1624 | 0 | } |
1625 | 0 | } |
1626 | 0 | else if( j == 0 && !bAboveAvaillable ) |
1627 | 0 | { |
1628 | 0 | pDst0[i] = (pRecSrc0[mult * i] * c0_5tap |
1629 | 0 | + pRecSrc0[mult * i] * c1_5tap + pRecSrc0[mult * i - 1] * c2_5tap + pRecSrc0[mult * i + 1] * c3_5tap |
1630 | 0 | + pRecSrc0[mult * i + strOffset] * c4_5tap |
1631 | 0 | + offset_5tap) >> shift_5tap; |
1632 | 0 | } |
1633 | 0 | else |
1634 | 0 | { |
1635 | 0 | pDst0[i] = (pRecSrc0[mult * i - strOffset] * c0_5tap |
1636 | 0 | + pRecSrc0[mult * i] * c1_5tap + pRecSrc0[mult * i - 1] * c2_5tap + pRecSrc0[mult * i + 1] * c3_5tap |
1637 | 0 | + pRecSrc0[mult * i + strOffset] * c4_5tap |
1638 | 0 | + offset_5tap) >> shift_5tap; |
1639 | 0 | } |
1640 | 0 | } |
1641 | 0 | pDst0 += iDstStride; |
1642 | 0 | pRecSrc0 += iRecStride2; |
1643 | 0 | } |
1644 | 0 | return; |
1645 | 0 | } |
1646 | | |
1647 | | |
1648 | | |
1649 | | |
1650 | 0 | #define GET_LUMA_REC_PIX_INC \ |
1651 | 0 | pDst0 += iDstStride; \ |
1652 | 0 | pRecSrc0 += iRecStride2 |
1653 | | |
1654 | 0 | #define GET_LUMA_REC_PIX_OP2(ADDR) \ |
1655 | 0 | pDst0[ADDR] = ( pRecSrc0[( (ADDR) << logSubWidthC ) ] * c0_6tap \ |
1656 | 0 | + pRecSrc0[( (ADDR) << logSubWidthC ) + 1] * c1_6tap \ |
1657 | 0 | + pRecSrc0[( (ADDR) << logSubWidthC ) - 1] * c2_6tap \ |
1658 | 0 | + pRecSrc0[( (ADDR) << logSubWidthC ) + iRecStride] * c3_6tap \ |
1659 | 0 | + pRecSrc0[( (ADDR) << logSubWidthC ) + 1 + iRecStride] * c4_6tap \ |
1660 | 0 | + pRecSrc0[( (ADDR) << logSubWidthC ) - 1 + iRecStride] * c5_6tap \ |
1661 | 0 | + offset_6tap ) >> shift_6tap |
1662 | | |
1663 | 0 | #define GET_LUMA_REC_PIX_OP1(ADDR) \ |
1664 | 0 | if( !(ADDR) ) \ |
1665 | 0 | { \ |
1666 | 0 | pDst0[0] = ( pRecSrc0[0 ] * c0_6tap \ |
1667 | 0 | + pRecSrc0[0 + 1] * c1_6tap \ |
1668 | 0 | + pRecSrc0[0] * c2_6tap \ |
1669 | 0 | + pRecSrc0[0 + iRecStride] * c3_6tap \ |
1670 | 0 | + pRecSrc0[0 + 1 + iRecStride] * c4_6tap \ |
1671 | 0 | + pRecSrc0[0 + iRecStride] * c5_6tap \ |
1672 | 0 | + offset_6tap ) >> shift_6tap; \ |
1673 | 0 | } \ |
1674 | 0 | else \ |
1675 | 0 | { \ |
1676 | 0 | GET_LUMA_REC_PIX_OP2(ADDR); \ |
1677 | 0 | } |
1678 | | |
1679 | 0 | int width = uiCWidth; |
1680 | 0 | int height = uiCHeight; |
1681 | |
|
1682 | 0 | if( bLeftAvaillable ) |
1683 | 0 | { |
1684 | 0 | if( cu.chromaFormat == CHROMA_420 ) |
1685 | 0 | { |
1686 | 0 | GetLumaRecPixel420( width, height, pRecSrc0, iRecStride, pDst0, iDstStride ); |
1687 | | // SIZE_AWARE_PER_EL_OP( GET_LUMA_REC_PIX_OP2, GET_LUMA_REC_PIX_INC ); |
1688 | 0 | } |
1689 | 0 | else //TODO add SIMD for 422,444 |
1690 | 0 | { |
1691 | 0 | SIZE_AWARE_PER_EL_OP( GET_LUMA_REC_PIX_OP2, GET_LUMA_REC_PIX_INC ); |
1692 | 0 | } |
1693 | 0 | } |
1694 | 0 | else |
1695 | 0 | { |
1696 | 0 | SIZE_AWARE_PER_EL_OP( GET_LUMA_REC_PIX_OP1, GET_LUMA_REC_PIX_INC ); |
1697 | 0 | } |
1698 | 0 | } |
1699 | | |
1700 | | #undef GET_LUMA_REC_PIX_INC |
1701 | | #undef GET_LUMA_REC_PIX_OP1 |
1702 | | #undef GET_LUMA_REC_PIX_OP2 |
1703 | | #undef SIZE_AWARE_PER_EL_OP |
1704 | | |
1705 | | void IntraPrediction::xGetLMParameters(const CodingUnit &cu, const ComponentID compID, |
1706 | | const CompArea &chromaArea, |
1707 | | int &a, int &b, int &iShift) |
1708 | 0 | { |
1709 | 0 | CHECK(compID == COMPONENT_Y, ""); |
1710 | |
|
1711 | 0 | const SizeType cWidth = chromaArea.width; |
1712 | 0 | const SizeType cHeight = chromaArea.height; |
1713 | |
|
1714 | 0 | const Position posLT = chromaArea; |
1715 | |
|
1716 | 0 | const CodingStructure &cs = *cu.cs; |
1717 | |
|
1718 | 0 | const SPS & sps = *cs.sps; |
1719 | 0 | const uint32_t tuWidth = chromaArea.width; |
1720 | 0 | const uint32_t tuHeight = chromaArea.height; |
1721 | 0 | const ChromaFormat nChromaFormat = sps.getChromaFormatIdc(); |
1722 | |
|
1723 | 0 | const int baseUnitSize = 1 << MIN_CU_LOG2; |
1724 | 0 | const int unitWidthLog2 = MIN_CU_LOG2 - getComponentScaleX(chromaArea.compID(), nChromaFormat); |
1725 | 0 | const int unitHeightLog2 = MIN_CU_LOG2 - getComponentScaleX(chromaArea.compID(), nChromaFormat); |
1726 | 0 | const int unitWidth = baseUnitSize >> getComponentScaleX(chromaArea.compID(), nChromaFormat); |
1727 | 0 | const int unitHeight = baseUnitSize >> getComponentScaleX(chromaArea.compID(), nChromaFormat); |
1728 | |
|
1729 | 0 | const int tuWidthInUnits = tuWidth / unitWidth; |
1730 | 0 | const int tuHeightInUnits = tuHeight / unitHeight; |
1731 | 0 | const int aboveUnits = tuWidthInUnits; |
1732 | 0 | const int leftUnits = tuHeightInUnits; |
1733 | 0 | int topTemplateSampNum = 2 * cWidth; // for MDLM, the template sample number is 2W or 2H; |
1734 | 0 | int leftTemplateSampNum = 2 * cHeight; |
1735 | 0 | CHECKD( !(m_topRefLength >= topTemplateSampNum), "Error!" ); |
1736 | 0 | CHECKD( !(m_leftRefLength >= leftTemplateSampNum), "Error!" ); |
1737 | 0 | int totalAboveUnits = (topTemplateSampNum + (unitWidth - 1)) / unitWidth; |
1738 | 0 | int totalLeftUnits = (leftTemplateSampNum + (unitHeight - 1)) / unitHeight; |
1739 | 0 | int aboveRightUnits = totalAboveUnits - aboveUnits; |
1740 | 0 | int leftBelowUnits = totalLeftUnits - leftUnits; |
1741 | |
|
1742 | 0 | int curChromaMode = cu.intraDir[1]; |
1743 | 0 | bool aboveAvailable = 0, leftAvailable = 0; |
1744 | |
|
1745 | 0 | const TransformUnit& tu = *getTU( cu, chromaArea.pos(), CH_C ); |
1746 | |
|
1747 | 0 | Pel *srcColor0, *curChroma0; |
1748 | 0 | int srcStride, curStride; |
1749 | |
|
1750 | 0 | PelBuf temp; |
1751 | 0 | if ((curChromaMode == MDLM_L_IDX) || (curChromaMode == MDLM_T_IDX)) |
1752 | 0 | { |
1753 | 0 | srcStride = 2 * MAX_TU_SIZE_FOR_PROFILE + 1; |
1754 | 0 | temp = PelBuf(m_piYuvExt[1] + srcStride + 1, srcStride, Size(chromaArea)); |
1755 | 0 | } |
1756 | 0 | else |
1757 | 0 | { |
1758 | 0 | srcStride = MAX_TU_SIZE_FOR_PROFILE + 1; |
1759 | 0 | temp = PelBuf(m_piYuvExt[1] + srcStride + 1, srcStride, Size(chromaArea)); |
1760 | 0 | } |
1761 | 0 | srcColor0 = temp.bufAt(0, 0); |
1762 | 0 | curChroma0 = getPredictorPtr(compID); |
1763 | |
|
1764 | 0 | curStride = m_topRefLength + 1; |
1765 | |
|
1766 | 0 | curChroma0 += curStride + 1; |
1767 | |
|
1768 | 0 | unsigned internalBitDepth = sps.getBitDepth(); |
1769 | |
|
1770 | 0 | int minLuma[2] = { MAX_INT, 0 }; |
1771 | 0 | int maxLuma[2] = { -MAX_INT, 0 }; |
1772 | |
|
1773 | 0 | Pel *src = srcColor0 - srcStride; |
1774 | 0 | Pel *cur = curChroma0 - curStride; |
1775 | 0 | int actualTopTemplateSampNum = 0; |
1776 | 0 | int actualLeftTemplateSampNum = 0; |
1777 | 0 | if( curChromaMode == MDLM_T_IDX ) |
1778 | 0 | { |
1779 | 0 | int avaiAboveUnits = 0; |
1780 | |
|
1781 | 0 | if( tu.cu->above || chromaArea.y > tu.cu->blocks[CH_C].y ) |
1782 | 0 | { |
1783 | 0 | avaiAboveUnits = aboveUnits; |
1784 | 0 | aboveRightUnits = aboveRightUnits > ( cHeight / unitWidth ) ? cHeight / unitWidth : aboveRightUnits; |
1785 | 0 | avaiAboveUnits += isAboveAvailable( tu, CHANNEL_TYPE_CHROMA, { posLT.x + ( PosType ) cWidth, posLT.y }, aboveRightUnits, unitWidthLog2 ); |
1786 | 0 | } |
1787 | |
|
1788 | 0 | aboveAvailable = avaiAboveUnits >= tuWidthInUnits; |
1789 | 0 | actualTopTemplateSampNum = unitWidth * avaiAboveUnits; |
1790 | 0 | } |
1791 | 0 | else if( curChromaMode == MDLM_L_IDX ) |
1792 | 0 | { |
1793 | 0 | int avaiLeftUnits = 0; |
1794 | | |
1795 | 0 | if( tu.cu->left || chromaArea.x > tu.cu->blocks[CH_C].x ) |
1796 | 0 | { |
1797 | 0 | avaiLeftUnits = leftUnits; |
1798 | 0 | leftBelowUnits = leftBelowUnits > ( cWidth / unitHeight ) ? cWidth / unitHeight : leftBelowUnits; |
1799 | 0 | avaiLeftUnits += isLeftAvailable( tu, CHANNEL_TYPE_CHROMA, { posLT.x, posLT.y + ( PosType ) cHeight }, leftBelowUnits, unitHeightLog2 ); |
1800 | 0 | } |
1801 | | |
1802 | 0 | leftAvailable = avaiLeftUnits >= tuHeightInUnits; |
1803 | 0 | actualLeftTemplateSampNum = unitHeight * avaiLeftUnits; |
1804 | 0 | } |
1805 | 0 | else if( curChromaMode == LM_CHROMA_IDX ) |
1806 | 0 | { |
1807 | 0 | aboveAvailable = tu.cu->above || chromaArea.y > tu.cu->blocks[CH_C].y; |
1808 | 0 | leftAvailable = tu.cu->left || chromaArea.x > tu.cu->blocks[CH_C].x; |
1809 | 0 | actualTopTemplateSampNum = cWidth; |
1810 | 0 | actualLeftTemplateSampNum = cHeight; |
1811 | 0 | } |
1812 | 0 | int startPos[2]; //0:Above, 1: Left |
1813 | 0 | int pickStep[2]; |
1814 | |
|
1815 | 0 | int aboveIs4 = leftAvailable ? 0 : 1; |
1816 | 0 | int leftIs4 = aboveAvailable ? 0 : 1; |
1817 | |
|
1818 | 0 | startPos[0] = actualTopTemplateSampNum >> (2 + aboveIs4); |
1819 | 0 | pickStep[0] = std::max(1, actualTopTemplateSampNum >> (1 + aboveIs4)); |
1820 | |
|
1821 | 0 | startPos[1] = actualLeftTemplateSampNum >> (2 + leftIs4); |
1822 | 0 | pickStep[1] = std::max(1, actualLeftTemplateSampNum >> (1 + leftIs4)); |
1823 | |
|
1824 | 0 | Pel selectLumaPix[4] = { 0, 0, 0, 0 }; |
1825 | 0 | Pel selectChromaPix[4] = { 0, 0, 0, 0 }; |
1826 | |
|
1827 | 0 | int cntT, cntL; |
1828 | 0 | cntT = cntL = 0; |
1829 | 0 | int cnt = 0; |
1830 | 0 | if (aboveAvailable) |
1831 | 0 | { |
1832 | 0 | cntT = std::min(actualTopTemplateSampNum, (1 + aboveIs4) << 1); |
1833 | 0 | src = srcColor0 - srcStride; |
1834 | 0 | cur = curChroma0 - curStride; |
1835 | 0 | for (int pos = startPos[0]; cnt < cntT; pos += pickStep[0], cnt++) |
1836 | 0 | { |
1837 | 0 | selectLumaPix[cnt] = src[pos]; |
1838 | 0 | selectChromaPix[cnt] = cur[pos]; |
1839 | 0 | } |
1840 | 0 | } |
1841 | |
|
1842 | 0 | if (leftAvailable) |
1843 | 0 | { |
1844 | 0 | cntL = std::min(actualLeftTemplateSampNum, ( 1 + leftIs4 ) << 1 ); |
1845 | 0 | src = srcColor0 - 1; |
1846 | 0 | cur = curChroma0 - 1; |
1847 | 0 | for (int pos = startPos[1], cnt = 0; cnt < cntL; pos += pickStep[1], cnt++) |
1848 | 0 | { |
1849 | 0 | selectLumaPix[cnt + cntT] = src[pos * srcStride]; |
1850 | 0 | selectChromaPix[cnt+ cntT] = cur[pos * curStride]; |
1851 | 0 | } |
1852 | 0 | } |
1853 | 0 | cnt = cntL + cntT; |
1854 | |
|
1855 | 0 | if (cnt == 2) |
1856 | 0 | { |
1857 | 0 | selectLumaPix[3] = selectLumaPix[0]; selectChromaPix[3] = selectChromaPix[0]; |
1858 | 0 | selectLumaPix[2] = selectLumaPix[1]; selectChromaPix[2] = selectChromaPix[1]; |
1859 | 0 | selectLumaPix[0] = selectLumaPix[1]; selectChromaPix[0] = selectChromaPix[1]; |
1860 | 0 | selectLumaPix[1] = selectLumaPix[3]; selectChromaPix[1] = selectChromaPix[3]; |
1861 | 0 | } |
1862 | |
|
1863 | 0 | int minGrpIdx[2] = { 0, 2 }; |
1864 | 0 | int maxGrpIdx[2] = { 1, 3 }; |
1865 | 0 | int *tmpMinGrp = minGrpIdx; |
1866 | 0 | int *tmpMaxGrp = maxGrpIdx; |
1867 | 0 | if (selectLumaPix[tmpMinGrp[0]] > selectLumaPix[tmpMinGrp[1]]) std::swap(tmpMinGrp[0], tmpMinGrp[1]); |
1868 | 0 | if (selectLumaPix[tmpMaxGrp[0]] > selectLumaPix[tmpMaxGrp[1]]) std::swap(tmpMaxGrp[0], tmpMaxGrp[1]); |
1869 | 0 | if (selectLumaPix[tmpMinGrp[0]] > selectLumaPix[tmpMaxGrp[1]]) std::swap(tmpMinGrp, tmpMaxGrp); // TODO: really? not std::swap(tmpMinGrp[0], tmpMaxGrp[1]); ? |
1870 | 0 | if (selectLumaPix[tmpMinGrp[1]] > selectLumaPix[tmpMaxGrp[0]]) std::swap(tmpMinGrp[1], tmpMaxGrp[0]); |
1871 | |
|
1872 | 0 | minLuma[0] = (selectLumaPix [tmpMinGrp[0]] + selectLumaPix [tmpMinGrp[1]] + 1) >> 1; |
1873 | 0 | minLuma[1] = (selectChromaPix[tmpMinGrp[0]] + selectChromaPix[tmpMinGrp[1]] + 1) >> 1; |
1874 | 0 | maxLuma[0] = (selectLumaPix [tmpMaxGrp[0]] + selectLumaPix [tmpMaxGrp[1]] + 1) >> 1; |
1875 | 0 | maxLuma[1] = (selectChromaPix[tmpMaxGrp[0]] + selectChromaPix[tmpMaxGrp[1]] + 1) >> 1; |
1876 | |
|
1877 | 0 | if (leftAvailable || aboveAvailable) |
1878 | 0 | { |
1879 | 0 | int diff = maxLuma[0] - minLuma[0]; |
1880 | 0 | if (diff > 0) |
1881 | 0 | { |
1882 | 0 | int diffC = maxLuma[1] - minLuma[1]; |
1883 | 0 | int x = getLog2( diff ); |
1884 | 0 | static const uint8_t DivSigTable[1 << 4] = { |
1885 | | // 4bit significands - 8 ( MSB is omitted ) |
1886 | 0 | 0, 7, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 1, 1, 0 |
1887 | 0 | }; |
1888 | 0 | int normDiff = (diff << 4 >> x) & 15; |
1889 | 0 | int v = DivSigTable[normDiff] | 8; |
1890 | 0 | x += normDiff != 0; |
1891 | |
|
1892 | 0 | int y = diffC == 0 ? 0 : getLog2( abs( diffC ) ) + 1; |
1893 | 0 | int add = 1 << y >> 1; |
1894 | 0 | a = (diffC * v + add) >> y; |
1895 | 0 | iShift = 3 + x - y; |
1896 | 0 | if ( iShift < 1 ) { |
1897 | 0 | iShift = 1; |
1898 | 0 | a = ( (a == 0)? 0: (a < 0)? -15 : 15 ); // a=Sign(a)*15 |
1899 | 0 | } |
1900 | 0 | b = minLuma[1] - ((a * minLuma[0]) >> iShift); |
1901 | 0 | } |
1902 | 0 | else |
1903 | 0 | { |
1904 | 0 | a = 0; |
1905 | 0 | b = minLuma[1]; |
1906 | 0 | iShift = 0; |
1907 | 0 | } |
1908 | 0 | } |
1909 | 0 | else |
1910 | 0 | { |
1911 | 0 | a = 0; |
1912 | |
|
1913 | 0 | b = 1 << (internalBitDepth - 1); |
1914 | |
|
1915 | 0 | iShift = 0; |
1916 | 0 | } |
1917 | 0 | } |
1918 | | |
1919 | | void IntraPrediction::initIntraMip( const CodingUnit &cu, const CompArea &area ) |
1920 | 0 | { |
1921 | 0 | CHECK( area.width > MIP_MAX_WIDTH || area.height > MIP_MAX_HEIGHT, "Error: block size not supported for MIP" ); |
1922 | | |
1923 | | // prepare input (boundary) data for prediction |
1924 | | // CHECK( m_ipaParam.refFilterFlag, "ERROR: unfiltered refs expected for MIP" ); |
1925 | 0 | Pel *ptrSrc = getPredictorPtr( area.compID() ); |
1926 | 0 | const int srcStride = m_topRefLength + 1; //TODO: check this if correct |
1927 | 0 | const int srcHStride = m_leftRefLength + 1; |
1928 | |
|
1929 | 0 | m_matrixIntraPred.prepareInputForPred( CPelBuf( ptrSrc, srcStride, srcHStride ), area, cu.sps->getBitDepth(), area.compID() ); |
1930 | 0 | } |
1931 | | |
1932 | | void IntraPrediction::predIntraMip( const ComponentID compId, PelBuf &piPred, const CodingUnit &cu ) |
1933 | 0 | { |
1934 | 0 | CHECK( piPred.width > MIP_MAX_WIDTH || piPred.height > MIP_MAX_HEIGHT, "Error: block size not supported for MIP" ); |
1935 | 0 | CHECK( piPred.width != (1 << getLog2(piPred.width)) || piPred.height != (1 << getLog2(piPred.height)), "Error: expecting blocks of size 2^M x 2^N" ); |
1936 | | |
1937 | | // generate mode-specific prediction |
1938 | 0 | uint32_t modeIdx = MAX_NUM_MIP_MODE; |
1939 | 0 | bool transposeFlag = false; |
1940 | 0 | if( compId == COMPONENT_Y ) |
1941 | 0 | { |
1942 | 0 | modeIdx = cu.intraDir[CHANNEL_TYPE_LUMA]; |
1943 | 0 | transposeFlag = cu.mipTransposedFlag(); |
1944 | 0 | } |
1945 | 0 | else |
1946 | 0 | { |
1947 | 0 | const CodingUnit &coLocatedLumaPU = PU::getCoLocatedLumaPU(cu); |
1948 | |
|
1949 | 0 | CHECK(cu.intraDir[CHANNEL_TYPE_CHROMA] != DM_CHROMA_IDX, "Error: MIP is only supported for chroma with DM_CHROMA."); |
1950 | 0 | CHECK(!coLocatedLumaPU.mipFlag(), "Error: Co-located luma CU should use MIP."); |
1951 | |
|
1952 | 0 | modeIdx = coLocatedLumaPU.intraDir[CHANNEL_TYPE_LUMA]; |
1953 | 0 | transposeFlag = coLocatedLumaPU.mipTransposedFlag(); |
1954 | 0 | } |
1955 | | |
1956 | 0 | CHECK(modeIdx >= getNumModesMip(piPred), "Error: Wrong MIP mode index"); |
1957 | |
|
1958 | 0 | const int bitDepth = cu.sps->getBitDepth(); |
1959 | 0 | m_matrixIntraPred.predBlock( piPred, modeIdx, piPred, transposeFlag, bitDepth, compId, m_piYuvExt[0] ); |
1960 | 0 | } |
1961 | | |
1962 | | } |