/src/vvenc/source/Lib/CommonLib/MatrixIntraPrediction.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 MatrixIntraPrediction.cpp |
45 | | \brief matrix-based intra prediction class |
46 | | */ |
47 | | |
48 | | |
49 | | #include "MatrixIntraPrediction.h" |
50 | | #include "dtrace_next.h" |
51 | | |
52 | | #include "UnitTools.h" |
53 | | #include "MipData.h" |
54 | | |
55 | | namespace vvenc { |
56 | | |
57 | | static const int MIP_MAX_INPUT_SIZE = 8; |
58 | | static const int MIP_MAX_REDUCED_OUTPUT_SAMPLES = 64; |
59 | | |
60 | | MatrixIntraPrediction::MatrixIntraPrediction() |
61 | 0 | : m_reducedBoundary (nullptr) |
62 | 0 | , m_reducedBoundaryTransp (nullptr) |
63 | 0 | , m_inputOffset ( 0 ) |
64 | 0 | , m_inputOffsetTransp ( 0 ) |
65 | 0 | , m_refSamplesTop (nullptr) |
66 | 0 | , m_refSamplesLeft (nullptr) |
67 | 0 | , m_blockSize ( 0, 0 ) |
68 | 0 | , m_sizeId ( 0 ) |
69 | 0 | , m_reducedBdrySize ( 0 ) |
70 | 0 | , m_reducedPredSize ( 0 ) |
71 | 0 | , m_upsmpFactorHor ( 0 ) |
72 | 0 | , m_upsmpFactorVer ( 0 ) |
73 | 0 | { |
74 | 0 | m_reducedBoundary = (Pel*)xMalloc( Pel, MIP_MAX_INPUT_SIZE ); |
75 | 0 | m_reducedBoundaryTransp = (Pel*)xMalloc( Pel, MIP_MAX_INPUT_SIZE ); |
76 | 0 | } |
77 | | |
78 | | MatrixIntraPrediction::~MatrixIntraPrediction() |
79 | 0 | { |
80 | 0 | xFree( m_reducedBoundary ); m_reducedBoundary = nullptr; |
81 | 0 | xFree( m_reducedBoundaryTransp ); m_reducedBoundaryTransp = nullptr; |
82 | 0 | } |
83 | | |
84 | | void MatrixIntraPrediction::prepareInputForPred(const CPelBuf &pSrc, const Area& block, const int bitDepth) |
85 | 0 | { |
86 | | // Step 1: Save block size and calculate dependent values |
87 | 0 | initPredBlockParams(block); |
88 | |
|
89 | 0 | m_refSamplesTop = pSrc.bufAt(1, 0); |
90 | 0 | m_refSamplesLeft = pSrc.bufAt(1, 1); |
91 | | |
92 | | // Step 3: Compute the reduced boundary via Haar-downsampling (input for the prediction) |
93 | 0 | const int inputSize = 2 * m_reducedBdrySize; |
94 | |
|
95 | 0 | Pel* const topReduced = m_reducedBoundary; |
96 | 0 | boundaryDownsampling1D( topReduced, m_refSamplesTop, block.width, m_reducedBdrySize ); |
97 | |
|
98 | 0 | Pel* const leftReduced = m_reducedBoundary + m_reducedBdrySize; |
99 | 0 | boundaryDownsampling1D( leftReduced, m_refSamplesLeft, block.height, m_reducedBdrySize ); |
100 | |
|
101 | 0 | Pel* const leftReducedTransposed = m_reducedBoundaryTransp; |
102 | 0 | Pel* const topReducedTransposed = m_reducedBoundaryTransp + m_reducedBdrySize; |
103 | 0 | for( int x = 0; x < m_reducedBdrySize; x++ ) |
104 | 0 | { |
105 | 0 | topReducedTransposed[x] = topReduced[x]; |
106 | 0 | } |
107 | 0 | for( int y = 0; y < m_reducedBdrySize; y++ ) |
108 | 0 | { |
109 | 0 | leftReducedTransposed[y] = leftReduced[y]; |
110 | 0 | } |
111 | | |
112 | | // Step 4: Rebase the reduced boundary |
113 | 0 | m_inputOffset = m_reducedBoundary[0]; |
114 | 0 | m_inputOffsetTransp = m_reducedBoundaryTransp[0]; |
115 | |
|
116 | 0 | const bool hasFirstCol = (m_sizeId < 2); |
117 | 0 | m_reducedBoundary [0] = hasFirstCol ? ((1 << (bitDepth - 1)) - m_inputOffset ) : 0; // first column of matrix not needed for large blocks |
118 | 0 | m_reducedBoundaryTransp[0] = hasFirstCol ? ((1 << (bitDepth - 1)) - m_inputOffsetTransp) : 0; |
119 | 0 | for (int i = 1; i < inputSize; i++) |
120 | 0 | { |
121 | 0 | m_reducedBoundary [i] -= m_inputOffset; |
122 | 0 | m_reducedBoundaryTransp[i] -= m_inputOffsetTransp; |
123 | 0 | } |
124 | 0 | } |
125 | | |
126 | | void MatrixIntraPrediction::predBlock(Pel* const result, const int modeIdx, const bool transpose, const int bitDepth) |
127 | 0 | { |
128 | 0 | ALIGN_DATA( MEMORY_ALIGN_DEF_SIZE, Pel bufReducedPred[MIP_MAX_REDUCED_OUTPUT_SAMPLES] ); |
129 | |
|
130 | 0 | const bool needUpsampling = ( m_upsmpFactorHor > 1 ) || ( m_upsmpFactorVer > 1 ); |
131 | 0 | Pel* const reducedPred = needUpsampling ? bufReducedPred : result; |
132 | 0 | const Pel* const reducedBoundary = transpose ? m_reducedBoundaryTransp : m_reducedBoundary; |
133 | |
|
134 | 0 | { |
135 | 0 | const int outputSize = m_reducedPredSize; |
136 | 0 | const int inputSize = 2 * m_reducedBdrySize; |
137 | 0 | const int offset = transpose ? m_inputOffsetTransp : m_inputOffset; |
138 | 0 | const int maxVal = ( 1 << bitDepth ) - 1; |
139 | |
|
140 | 0 | if( outputSize == 8) |
141 | 0 | { |
142 | 0 | g_pelBufOP.mipMatrixMul_8_8( reducedPred, reducedBoundary, &mipMatrix16x16[modeIdx][0][0], maxVal, offset, transpose ); |
143 | 0 | } |
144 | 0 | else |
145 | 0 | { |
146 | 0 | if( inputSize == 4) |
147 | 0 | { |
148 | 0 | g_pelBufOP.mipMatrixMul_4_4( reducedPred, reducedBoundary, &mipMatrix4x4[modeIdx][0][0], maxVal, offset, transpose ); |
149 | 0 | } |
150 | 0 | else |
151 | 0 | { |
152 | 0 | g_pelBufOP.mipMatrixMul_8_4( reducedPred, reducedBoundary, &mipMatrix8x8[modeIdx][0][0], maxVal, offset, transpose ); |
153 | 0 | } |
154 | 0 | } |
155 | 0 | } |
156 | | |
157 | | // Reduced prediction is transposed if ( transpose && needUpsampling ). |
158 | 0 | if( needUpsampling ) |
159 | 0 | { |
160 | 0 | const Pel* verSrc = reducedPred; |
161 | 0 | SizeType verSrcStep = m_blockSize.width; |
162 | |
|
163 | 0 | if( m_upsmpFactorHor > 1 ) |
164 | 0 | { |
165 | 0 | Pel* const horDst = result + (m_upsmpFactorVer - 1) * m_blockSize.width; |
166 | 0 | verSrc = horDst; |
167 | 0 | verSrcStep *= m_upsmpFactorVer; |
168 | |
|
169 | 0 | if( m_reducedPredSize == 4) |
170 | 0 | { |
171 | 0 | if( m_upsmpFactorHor == 2 ) |
172 | 0 | predictionUpsampling1DHor<4,1>( horDst, reducedPred, &m_refSamplesLeft[0], verSrcStep, m_upsmpFactorVer ); |
173 | 0 | else if( m_upsmpFactorHor == 4 ) |
174 | 0 | predictionUpsampling1DHor<4,2>( horDst, reducedPred, &m_refSamplesLeft[0], verSrcStep, m_upsmpFactorVer ); |
175 | 0 | else |
176 | 0 | predictionUpsampling1DHor<4,3>( horDst, reducedPred, &m_refSamplesLeft[0], verSrcStep, m_upsmpFactorVer ); |
177 | 0 | } |
178 | 0 | else |
179 | 0 | { |
180 | 0 | if( m_upsmpFactorHor == 2 ) |
181 | 0 | predictionUpsampling1DHor<8,1>( horDst, reducedPred, &m_refSamplesLeft[0], verSrcStep, m_upsmpFactorVer ); |
182 | 0 | else if( m_upsmpFactorHor == 4 ) |
183 | 0 | predictionUpsampling1DHor<8,2>( horDst, reducedPred, &m_refSamplesLeft[0], verSrcStep, m_upsmpFactorVer ); |
184 | 0 | else |
185 | 0 | predictionUpsampling1DHor<8,3>( horDst, reducedPred, &m_refSamplesLeft[0], verSrcStep, m_upsmpFactorVer ); |
186 | 0 | } |
187 | 0 | } |
188 | |
|
189 | 0 | if( m_upsmpFactorVer > 1 ) |
190 | 0 | { |
191 | 0 | if( m_reducedPredSize == 4) |
192 | 0 | { |
193 | 0 | if( m_upsmpFactorVer == 2 ) |
194 | 0 | predictionUpsampling1DVer<4,1>( result, verSrc, &m_refSamplesTop[0], m_blockSize.width, verSrcStep ); |
195 | 0 | else if( m_upsmpFactorVer == 4 ) |
196 | 0 | predictionUpsampling1DVer<4,2>( result, verSrc, &m_refSamplesTop[0], m_blockSize.width, verSrcStep ); |
197 | 0 | else |
198 | 0 | predictionUpsampling1DVer<4,3>( result, verSrc, &m_refSamplesTop[0], m_blockSize.width, verSrcStep ); |
199 | 0 | } |
200 | 0 | else |
201 | 0 | { |
202 | 0 | if( m_upsmpFactorVer == 2 ) |
203 | 0 | predictionUpsampling1DVer<8,1>( result, verSrc, &m_refSamplesTop[0], m_blockSize.width, verSrcStep ); |
204 | 0 | else if( m_upsmpFactorVer == 4 ) |
205 | 0 | predictionUpsampling1DVer<8,2>( result, verSrc, &m_refSamplesTop[0], m_blockSize.width, verSrcStep ); |
206 | 0 | else |
207 | 0 | predictionUpsampling1DVer<8,3>( result, verSrc, &m_refSamplesTop[0], m_blockSize.width, verSrcStep ); |
208 | 0 | } |
209 | 0 | } |
210 | 0 | } |
211 | 0 | } |
212 | | |
213 | | void MatrixIntraPrediction::initPredBlockParams(const Size& block) |
214 | 0 | { |
215 | 0 | m_blockSize = block; |
216 | | // init size index |
217 | 0 | m_sizeId = getMipSizeId( m_blockSize ); |
218 | | |
219 | | // init reduced boundary size |
220 | 0 | m_reducedBdrySize = (m_sizeId == 0) ? 2 : 4; |
221 | | |
222 | | // init reduced prediction size |
223 | 0 | m_reducedPredSize = ( m_sizeId < 2 ) ? 4 : 8; |
224 | | |
225 | | // init upsampling factors |
226 | 0 | m_upsmpFactorHor = m_blockSize.width / m_reducedPredSize; |
227 | 0 | m_upsmpFactorVer = m_blockSize.height / m_reducedPredSize; |
228 | |
|
229 | 0 | CHECKD( (m_upsmpFactorHor < 1) || ((m_upsmpFactorHor & (m_upsmpFactorHor - 1)) != 0), "Need power of two horizontal upsampling factor." ); |
230 | 0 | CHECKD( (m_upsmpFactorVer < 1) || ((m_upsmpFactorVer & (m_upsmpFactorVer - 1)) != 0), "Need power of two vertical upsampling factor." ); |
231 | 0 | } |
232 | | |
233 | | void MatrixIntraPrediction::boundaryDownsampling1D(Pel* reducedDst, const Pel* const fullSrc, const SizeType srcLen, const SizeType dstLen) |
234 | 0 | { |
235 | 0 | if (dstLen < srcLen) |
236 | 0 | { |
237 | | // Create reduced boundary by downsampling |
238 | 0 | const SizeType downsmpFactor = srcLen / dstLen; |
239 | 0 | const int log2DownsmpFactor = floorLog2(downsmpFactor); |
240 | 0 | const int roundingOffset = (1 << (log2DownsmpFactor - 1)); |
241 | |
|
242 | 0 | SizeType srcIdx = 0; |
243 | 0 | for( SizeType dstIdx = 0; dstIdx < dstLen; dstIdx++ ) |
244 | 0 | { |
245 | 0 | int sum = 0; |
246 | 0 | for( int k = 0; k < downsmpFactor; k++ ) |
247 | 0 | { |
248 | 0 | sum += fullSrc[srcIdx++]; |
249 | 0 | } |
250 | 0 | reducedDst[dstIdx] = (sum + roundingOffset) >> log2DownsmpFactor; |
251 | 0 | } |
252 | 0 | } |
253 | 0 | else |
254 | 0 | { |
255 | | // Copy boundary if no downsampling is needed |
256 | 0 | for (SizeType i = 0; i < dstLen; ++i) |
257 | 0 | { |
258 | 0 | reducedDst[i] = fullSrc[i]; |
259 | 0 | } |
260 | 0 | } |
261 | 0 | } |
262 | | |
263 | | template< SizeType predPredSize, unsigned log2UpsmpFactor> |
264 | | void MatrixIntraPrediction::predictionUpsampling1DHor(Pel* const dst, const Pel* const src, const Pel* const bndry, const SizeType dstStride, const SizeType bndryStep ) |
265 | 0 | { |
266 | 0 | const int roundingOffset = 1 << (log2UpsmpFactor - 1); |
267 | 0 | const SizeType upsmpFactor = 1 << log2UpsmpFactor; |
268 | |
|
269 | 0 | Pel* dstLine = dst; |
270 | 0 | const Pel* srcLine = src; |
271 | 0 | const Pel* bndryLine = bndry + bndryStep - 1; |
272 | |
|
273 | 0 | for( SizeType idxOrthDim = 0; idxOrthDim < predPredSize; idxOrthDim++ ) |
274 | 0 | { |
275 | 0 | const Pel* before = bndryLine; |
276 | 0 | const Pel* behind = srcLine; |
277 | 0 | Pel* currDst = dstLine; |
278 | 0 | for( SizeType idxUpsmpDim = 0; idxUpsmpDim < predPredSize; idxUpsmpDim++ ) |
279 | 0 | { |
280 | 0 | const int valDiff = *behind - *before; |
281 | 0 | int scaledVal = ( ( *before ) << log2UpsmpFactor ) + roundingOffset; |
282 | 0 | for( SizeType pos = 0; pos < upsmpFactor; pos++) |
283 | 0 | { |
284 | 0 | scaledVal += valDiff; |
285 | 0 | *currDst = scaledVal >> log2UpsmpFactor; |
286 | 0 | currDst++; |
287 | 0 | } |
288 | 0 | before = behind; |
289 | 0 | behind ++; |
290 | 0 | } |
291 | |
|
292 | 0 | srcLine += predPredSize; |
293 | 0 | dstLine += dstStride; |
294 | 0 | bndryLine += bndryStep; |
295 | 0 | } |
296 | 0 | } Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DHor<4u, 1u>(short*, short const*, short const*, unsigned int, unsigned int) Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DHor<4u, 2u>(short*, short const*, short const*, unsigned int, unsigned int) Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DHor<4u, 3u>(short*, short const*, short const*, unsigned int, unsigned int) Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DHor<8u, 1u>(short*, short const*, short const*, unsigned int, unsigned int) Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DHor<8u, 2u>(short*, short const*, short const*, unsigned int, unsigned int) Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DHor<8u, 3u>(short*, short const*, short const*, unsigned int, unsigned int) |
297 | | |
298 | | template< SizeType inHeight, unsigned log2UpsmpFactor> |
299 | | void MatrixIntraPrediction::predictionUpsampling1DVer(Pel* const dst, const Pel* const src, const Pel* const bndry, const SizeType outWidth, const SizeType srcStep ) |
300 | 0 | { |
301 | 0 | const int roundingOffset = 1 << (log2UpsmpFactor - 1); |
302 | 0 | const SizeType upsmpFactor = 1 << log2UpsmpFactor; |
303 | |
|
304 | 0 | Pel* dstLine = dst; |
305 | 0 | const Pel* srcLine = src; |
306 | 0 | const Pel* bndryLine = bndry; |
307 | |
|
308 | 0 | for( SizeType idxOrthDim = 0; idxOrthDim < outWidth; idxOrthDim++ ) |
309 | 0 | { |
310 | 0 | const Pel* before = bndryLine; |
311 | 0 | const Pel* behind = srcLine; |
312 | 0 | Pel* currDst = dstLine; |
313 | 0 | for( SizeType idxUpsmpDim = 0; idxUpsmpDim < inHeight; idxUpsmpDim++ ) |
314 | 0 | { |
315 | 0 | const int valDiff = *behind - *before; |
316 | 0 | int scaledVal = ( ( *before ) << log2UpsmpFactor ) + roundingOffset; |
317 | |
|
318 | 0 | for( SizeType pos = 0; pos < upsmpFactor; pos++) |
319 | 0 | { |
320 | 0 | scaledVal += valDiff; |
321 | 0 | *currDst = scaledVal >> log2UpsmpFactor; |
322 | 0 | currDst += outWidth; |
323 | 0 | } |
324 | 0 | before = behind; |
325 | 0 | behind += srcStep; |
326 | 0 | } |
327 | |
|
328 | 0 | srcLine ++; |
329 | 0 | dstLine ++; |
330 | 0 | bndryLine ++; |
331 | 0 | } |
332 | 0 | } Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DVer<4u, 1u>(short*, short const*, short const*, unsigned int, unsigned int) Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DVer<4u, 2u>(short*, short const*, short const*, unsigned int, unsigned int) Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DVer<4u, 3u>(short*, short const*, short const*, unsigned int, unsigned int) Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DVer<8u, 1u>(short*, short const*, short const*, unsigned int, unsigned int) Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DVer<8u, 2u>(short*, short const*, short const*, unsigned int, unsigned int) Unexecuted instantiation: void vvenc::MatrixIntraPrediction::predictionUpsampling1DVer<8u, 3u>(short*, short const*, short const*, unsigned int, unsigned int) |
333 | | |
334 | | |
335 | | } // namespace vvenc |
336 | | |
337 | | //! \} |