/src/vvdec/source/Lib/CommonLib/WeightPrediction.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 WeightPrediction.h |
44 | | \brief weighting prediction class (header) |
45 | | */ |
46 | | |
47 | | // Include files |
48 | | #include "CommonDef.h" |
49 | | #include "Unit.h" |
50 | | #include "InterpolationFilter.h" |
51 | | #include "WeightPrediction.h" |
52 | | #include "CodingStructure.h" |
53 | | |
54 | | namespace vvdec |
55 | | { |
56 | | |
57 | | // ==================================================================================================================== |
58 | | // Class definition |
59 | | // ==================================================================================================================== |
60 | | |
61 | | WeightPrediction::WeightPrediction() |
62 | 0 | { |
63 | 0 | } |
64 | | |
65 | | |
66 | | |
67 | | void WeightPrediction::getWpScaling(const Slice *pcSlice, |
68 | | const int &iRefIdx0, |
69 | | const int &iRefIdx1, |
70 | | WPScalingParam *wp0, |
71 | | WPScalingParam *wp1) |
72 | 0 | { |
73 | 0 | CHECK(iRefIdx0 < 0 && iRefIdx1 < 0, "Both picture reference list indizes smaller than '0'"); |
74 | |
|
75 | 0 | const bool wpBiPred = pcSlice->getPPS()->getWPBiPred(); |
76 | 0 | const bool bBiPred = (iRefIdx0 >= 0 && iRefIdx1 >= 0); |
77 | 0 | const bool bUniPred = !bBiPred; |
78 | |
|
79 | 0 | const WPScalingParam* wp0org; |
80 | 0 | const WPScalingParam* wp1org; |
81 | |
|
82 | 0 | if (bUniPred || wpBiPred) |
83 | 0 | { |
84 | | // explicit -------------------- |
85 | 0 | if (iRefIdx0 >= 0) |
86 | 0 | { |
87 | 0 | pcSlice->getWpScaling(REF_PIC_LIST_0, iRefIdx0, wp0org); |
88 | 0 | } |
89 | 0 | if (iRefIdx1 >= 0) |
90 | 0 | { |
91 | 0 | pcSlice->getWpScaling(REF_PIC_LIST_1, iRefIdx1, wp1org); |
92 | 0 | } |
93 | 0 | } |
94 | 0 | else |
95 | 0 | { |
96 | 0 | THROW_RECOVERABLE( "Unsupported WP configuration" ); |
97 | 0 | } |
98 | | |
99 | 0 | const uint32_t numValidComponent = getNumberValidComponents(pcSlice->getSPS()->getChromaFormatIdc()); |
100 | |
|
101 | 0 | if( iRefIdx0 < 0 ) |
102 | 0 | { |
103 | 0 | for( int yuv = 0; yuv < numValidComponent; yuv++ ) |
104 | 0 | { |
105 | 0 | wp0[yuv].bPresentFlag = false; |
106 | 0 | } |
107 | 0 | } |
108 | 0 | if( iRefIdx1 < 0 ) |
109 | 0 | { |
110 | 0 | for( int yuv = 0; yuv < numValidComponent; yuv++ ) |
111 | 0 | { |
112 | 0 | wp1[yuv].bPresentFlag = false; |
113 | 0 | } |
114 | 0 | } |
115 | |
|
116 | 0 | const bool bUseHighPrecisionPredictionWeighting = false; // pcSlice->getSPS()->getSpsRangeExtension().getHighPrecisionOffsetsEnabledFlag(); |
117 | |
|
118 | 0 | if (bBiPred) |
119 | 0 | { |
120 | | // Bi-predictive case |
121 | 0 | for (int yuv = 0; yuv < numValidComponent; yuv++) |
122 | 0 | { |
123 | 0 | const int bitDepth = pcSlice->getSPS()->getBitDepth(); |
124 | 0 | const int offsetScalingFactor = bUseHighPrecisionPredictionWeighting ? 1 : (1 << (bitDepth - 8)); |
125 | |
|
126 | 0 | wp0[yuv] = wp0org[yuv]; |
127 | 0 | wp1[yuv] = wp1org[yuv]; |
128 | |
|
129 | 0 | wp0[yuv].w = wp0org[yuv].iWeight; |
130 | 0 | wp1[yuv].w = wp1org[yuv].iWeight; |
131 | 0 | wp0[yuv].o = wp0org[yuv].iOffset * offsetScalingFactor; |
132 | 0 | wp1[yuv].o = wp1org[yuv].iOffset * offsetScalingFactor; |
133 | 0 | wp0[yuv].offset = wp1[yuv].offset = wp0[yuv].o + wp1[yuv].o; |
134 | 0 | wp0[yuv].shift = wp1[yuv].shift = wp0org[yuv].uiLog2WeightDenom + 1; |
135 | 0 | wp0[yuv].round = wp1[yuv].round = ( 1 << wp0org[yuv].uiLog2WeightDenom ); |
136 | 0 | } |
137 | 0 | } |
138 | 0 | else |
139 | 0 | { |
140 | | // UniPred |
141 | 0 | const WPScalingParam* const pwporg = ( iRefIdx0 >= 0 ) ? wp0org : wp1org; |
142 | 0 | WPScalingParam* const pwp = ( iRefIdx0 >= 0 ) ? wp0 : wp1; |
143 | |
|
144 | 0 | for (int yuv = 0; yuv < numValidComponent; yuv++) |
145 | 0 | { |
146 | 0 | const int bitDepth = pcSlice->getSPS()->getBitDepth(); |
147 | 0 | const int offsetScalingFactor = bUseHighPrecisionPredictionWeighting ? 1 : (1 << (bitDepth - 8)); |
148 | | |
149 | 0 | pwp[yuv] = pwporg[yuv]; |
150 | |
|
151 | 0 | pwp[yuv].w = pwporg[yuv].iWeight; |
152 | 0 | pwp[yuv].offset = pwporg[yuv].iOffset * offsetScalingFactor; |
153 | 0 | pwp[yuv].shift = pwporg[yuv].uiLog2WeightDenom; |
154 | 0 | pwp[yuv].round = ( pwporg[yuv].uiLog2WeightDenom >= 1 ) ? ( 1 << ( pwporg[yuv].uiLog2WeightDenom - 1 ) ) : ( 0 ); |
155 | 0 | } |
156 | 0 | } |
157 | 0 | } |
158 | | |
159 | | static inline Pel weightBidir( int w0, Pel P0, int w1, Pel P1, int round, int shift, int offset, const ClpRng& clpRng ) |
160 | 0 | { |
161 | 0 | return ClipPel( ( ( w0*( P0 + IF_INTERNAL_OFFS ) + w1 * ( P1 + IF_INTERNAL_OFFS ) + round + ( offset * ( 1 << ( shift - 1 ) ) ) ) >> shift ), clpRng ); |
162 | 0 | } |
163 | | |
164 | | void WeightPrediction::addWeightBi(const PelUnitBuf &pcYuvSrc0, |
165 | | const PelUnitBuf &pcYuvSrc1, |
166 | | const ClpRngs &clpRngs, |
167 | | const WPScalingParam *const wp0, |
168 | | const WPScalingParam *const wp1, |
169 | | PelUnitBuf &rpcYuvDst |
170 | | ) |
171 | 0 | { |
172 | 0 | const uint32_t numValidComponent = (const uint32_t)pcYuvSrc0.bufs.size(); |
173 | |
|
174 | 0 | for (int componentIndex = 0; componentIndex < numValidComponent; componentIndex++) |
175 | 0 | { |
176 | 0 | const ComponentID compID = ComponentID(componentIndex); |
177 | |
|
178 | 0 | const Pel* pSrc0 = pcYuvSrc0.bufs[compID].buf; |
179 | 0 | const Pel* pSrc1 = pcYuvSrc1.bufs[compID].buf; |
180 | 0 | Pel* pDst = rpcYuvDst.bufs[compID].buf; |
181 | |
|
182 | 0 | const ptrdiff_t iSrc0Stride = pcYuvSrc0.bufs[compID].stride; |
183 | 0 | const ptrdiff_t iSrc1Stride = pcYuvSrc1.bufs[compID].stride; |
184 | 0 | const ptrdiff_t iDstStride = rpcYuvDst.bufs[compID].stride; |
185 | |
|
186 | 0 | const ClpRng& clpRng = clpRngs; |
187 | 0 | const int w0 = wp0[compID].w; |
188 | 0 | const int offset = wp0[compID].offset; |
189 | 0 | const int clipBD = clpRng.bd; |
190 | 0 | const int shiftNum = std::max<int>(2, (IF_INTERNAL_PREC - clipBD)); |
191 | 0 | const int shift = wp0[compID].shift + shiftNum; |
192 | 0 | const int round = 1 << shift >> 1; |
193 | 0 | const int w1 = wp1[compID].w; |
194 | |
|
195 | 0 | const int iHeight = rpcYuvDst.bufs[compID].height; |
196 | 0 | const int iWidth = rpcYuvDst.bufs[compID].width; |
197 | 0 | const int applyOffset = round + ( offset * ( 1 << ( shift - 1 ) ) ) + ( w0 + w1 ) * IF_INTERNAL_OFFS; |
198 | |
|
199 | 0 | if( ( iWidth & 7 ) == 0 ) |
200 | 0 | { |
201 | 0 | g_pelBufOP.wghtAvg8( pSrc0, iSrc0Stride, pSrc1, iSrc1Stride, pDst, iDstStride, iWidth, iHeight, shift, applyOffset, w0, w1, clpRngs ); |
202 | 0 | } |
203 | 0 | else if( ( iWidth & 3 ) == 0 ) |
204 | 0 | g_pelBufOP.wghtAvg4( pSrc0, iSrc0Stride, pSrc1, iSrc1Stride, pDst, iDstStride, iWidth, iHeight, shift, applyOffset, w0, w1, clpRngs ); |
205 | 0 | else |
206 | 0 | { |
207 | 0 | CHECK( iWidth != 2, "Should only happen for width '2'" ); |
208 | |
|
209 | 0 | for (int y = iHeight - 1; y >= 0; y--) |
210 | 0 | { |
211 | 0 | pDst[0] = weightBidir(w0, pSrc0[0], w1, pSrc1[0], round, shift, offset, clpRng );; |
212 | 0 | pDst[1] = weightBidir(w0, pSrc0[1], w1, pSrc1[1], round, shift, offset, clpRng );; |
213 | |
|
214 | 0 | pSrc0 += iSrc0Stride; |
215 | 0 | pSrc1 += iSrc1Stride; |
216 | 0 | pDst += iDstStride; |
217 | 0 | } // y loop |
218 | 0 | } |
219 | 0 | } // compID loop |
220 | 0 | } |
221 | | |
222 | | |
223 | | static inline Pel weightUnidir( int w0, Pel P0, int round, int shift, int offset, const ClpRng& clpRng ) |
224 | 0 | { |
225 | 0 | return ClipPel( ( ( w0*( P0 + IF_INTERNAL_OFFS ) + round ) >> shift ) + offset, clpRng ); |
226 | 0 | } |
227 | | |
228 | | static inline Pel noWeightUnidir( Pel P0, int round, int shift, int offset, const ClpRng& clpRng ) |
229 | 0 | { |
230 | 0 | return ClipPel( ( ( ( P0 + IF_INTERNAL_OFFS ) + round ) >> shift ) + offset, clpRng ); |
231 | 0 | } |
232 | | |
233 | | static inline Pel noWeightOffsetUnidir( Pel P0, int round, int shift, const ClpRng& clpRng ) |
234 | 0 | { |
235 | 0 | return ClipPel( ( ( ( P0 + IF_INTERNAL_OFFS ) + round ) >> shift ), clpRng ); |
236 | 0 | } |
237 | | |
238 | | void WeightPrediction::addWeightUni(const PelUnitBuf &pcYuvSrc0, |
239 | | const ClpRngs &clpRngs, |
240 | | const WPScalingParam *const wp0, |
241 | | PelUnitBuf &rpcYuvDst |
242 | | ) |
243 | 0 | { |
244 | 0 | const uint32_t numValidComponent = (const uint32_t)pcYuvSrc0.bufs.size(); |
245 | |
|
246 | 0 | for (int componentIndex = 0; componentIndex < numValidComponent; componentIndex++) |
247 | 0 | { |
248 | 0 | const ComponentID compID = ComponentID(componentIndex); |
249 | |
|
250 | 0 | const Pel* pSrc0 = pcYuvSrc0.bufs[compID].buf; |
251 | 0 | Pel* pDst = rpcYuvDst.bufs[compID].buf; |
252 | | |
253 | | // Luma : -------------------------------------------- |
254 | 0 | const ClpRng& clpRng = clpRngs; |
255 | 0 | const int w0 = wp0[compID].w; |
256 | 0 | const int offset = wp0[compID].offset; |
257 | 0 | const int clipBD = clpRng.bd; |
258 | 0 | const int shiftNum = std::max<int>(2, (IF_INTERNAL_PREC - clipBD)); |
259 | 0 | const int shift = wp0[compID].shift + shiftNum; |
260 | 0 | const ptrdiff_t iSrc0Stride = pcYuvSrc0.bufs[compID].stride; |
261 | 0 | const ptrdiff_t iDstStride = rpcYuvDst.bufs[compID].stride; |
262 | 0 | const int iHeight = rpcYuvDst.bufs[compID].height; |
263 | 0 | const int iWidth = rpcYuvDst.bufs[compID].width; |
264 | |
|
265 | 0 | if (w0 != 1 << wp0[compID].shift) |
266 | 0 | { |
267 | 0 | const int round = (shift > 0) ? (1 << (shift - 1)) : 0; |
268 | 0 | for (int y = iHeight - 1; y >= 0; y--) |
269 | 0 | { |
270 | 0 | int x = iWidth - 1; |
271 | 0 | for (; x >= 3; ) |
272 | 0 | { |
273 | 0 | pDst[x] = weightUnidir(w0, pSrc0[x], round, shift, offset, clpRng); x--; |
274 | 0 | pDst[x] = weightUnidir(w0, pSrc0[x], round, shift, offset, clpRng); x--; |
275 | 0 | pDst[x] = weightUnidir(w0, pSrc0[x], round, shift, offset, clpRng); x--; |
276 | 0 | pDst[x] = weightUnidir(w0, pSrc0[x], round, shift, offset, clpRng); x--; |
277 | 0 | } |
278 | 0 | for (; x >= 0; x--) |
279 | 0 | { |
280 | 0 | pDst[x] = weightUnidir(w0, pSrc0[x], round, shift, offset, clpRng); |
281 | 0 | } |
282 | 0 | pSrc0 += iSrc0Stride; |
283 | 0 | pDst += iDstStride; |
284 | 0 | } |
285 | 0 | } |
286 | 0 | else |
287 | 0 | { |
288 | 0 | const int round = (shiftNum > 0) ? (1 << (shiftNum - 1)) : 0; |
289 | 0 | if (offset == 0) |
290 | 0 | { |
291 | 0 | for (int y = iHeight - 1; y >= 0; y--) |
292 | 0 | { |
293 | 0 | int x = iWidth - 1; |
294 | 0 | for (; x >= 3; ) |
295 | 0 | { |
296 | 0 | pDst[x] = noWeightOffsetUnidir(pSrc0[x], round, shiftNum, clpRng); x--; |
297 | 0 | pDst[x] = noWeightOffsetUnidir(pSrc0[x], round, shiftNum, clpRng); x--; |
298 | 0 | pDst[x] = noWeightOffsetUnidir(pSrc0[x], round, shiftNum, clpRng); x--; |
299 | 0 | pDst[x] = noWeightOffsetUnidir(pSrc0[x], round, shiftNum, clpRng); x--; |
300 | 0 | } |
301 | 0 | for (; x >= 0; x--) |
302 | 0 | { |
303 | 0 | pDst[x] = noWeightOffsetUnidir(pSrc0[x], round, shiftNum, clpRng); |
304 | 0 | } |
305 | 0 | pSrc0 += iSrc0Stride; |
306 | 0 | pDst += iDstStride; |
307 | 0 | } |
308 | 0 | } |
309 | 0 | else |
310 | 0 | { |
311 | 0 | for (int y = iHeight - 1; y >= 0; y--) |
312 | 0 | { |
313 | 0 | int x = iWidth - 1; |
314 | 0 | for (; x >= 3; ) |
315 | 0 | { |
316 | 0 | pDst[x] = noWeightUnidir(pSrc0[x], round, shiftNum, offset, clpRng); x--; |
317 | 0 | pDst[x] = noWeightUnidir(pSrc0[x], round, shiftNum, offset, clpRng); x--; |
318 | 0 | pDst[x] = noWeightUnidir(pSrc0[x], round, shiftNum, offset, clpRng); x--; |
319 | 0 | pDst[x] = noWeightUnidir(pSrc0[x], round, shiftNum, offset, clpRng); x--; |
320 | 0 | } |
321 | 0 | for (; x >= 0; x--) |
322 | 0 | { |
323 | 0 | pDst[x] = noWeightUnidir(pSrc0[x], round, shiftNum, offset, clpRng); |
324 | 0 | } |
325 | 0 | pSrc0 += iSrc0Stride; |
326 | 0 | pDst += iDstStride; |
327 | 0 | } |
328 | 0 | } |
329 | 0 | } |
330 | 0 | } |
331 | 0 | } |
332 | | |
333 | | void WeightPrediction::xWeightedPredictionUni(const CodingUnit &cu, |
334 | | const PelUnitBuf &pcYuvSrc, |
335 | | const RefPicList &eRefPicList, |
336 | | PelUnitBuf &pcYuvPred, |
337 | | const int iRefIdx_input/* = -1*/ |
338 | | ) |
339 | 0 | { |
340 | 0 | WPScalingParam pwp[MAX_NUM_COMPONENT], pwpTmp[MAX_NUM_COMPONENT]; |
341 | |
|
342 | 0 | int iRefIdx = iRefIdx_input; |
343 | 0 | if (iRefIdx < 0) |
344 | 0 | { |
345 | 0 | iRefIdx = cu.refIdx[eRefPicList]; |
346 | 0 | } |
347 | |
|
348 | 0 | CHECK(iRefIdx < 0, "Negative reference picture list index"); |
349 | |
|
350 | 0 | if (eRefPicList == REF_PIC_LIST_0) |
351 | 0 | { |
352 | 0 | getWpScaling(cu.slice, iRefIdx, -1, pwp, pwpTmp); |
353 | 0 | } |
354 | 0 | else |
355 | 0 | { |
356 | 0 | getWpScaling(cu.slice, -1, iRefIdx, pwpTmp, pwp); |
357 | 0 | } |
358 | 0 | addWeightUni(pcYuvSrc, cu.slice->clpRngs(), pwp, pcYuvPred); |
359 | 0 | } |
360 | | |
361 | | void WeightPrediction::xWeightedPredictionBi(const CodingUnit &cu, |
362 | | const PelUnitBuf &pcYuvSrc0, |
363 | | const PelUnitBuf &pcYuvSrc1, |
364 | | PelUnitBuf &rpcYuvDst |
365 | | ) |
366 | 0 | { |
367 | 0 | const int iRefIdx0 = cu.refIdx[0]; |
368 | 0 | const int iRefIdx1 = cu.refIdx[1]; |
369 | 0 | WPScalingParam pwp0[MAX_NUM_COMPONENT]; |
370 | 0 | WPScalingParam pwp1[MAX_NUM_COMPONENT]; |
371 | |
|
372 | 0 | CHECK( !cu.pps->getWPBiPred(), "Weighted Bi-prediction disabled" ); |
373 | |
|
374 | 0 | getWpScaling(cu.slice, iRefIdx0, iRefIdx1, pwp0, pwp1); |
375 | |
|
376 | 0 | if (iRefIdx0 >= 0 && iRefIdx1 >= 0) |
377 | 0 | { |
378 | 0 | addWeightBi(pcYuvSrc0, pcYuvSrc1, cu.slice->clpRngs(), pwp0, pwp1, rpcYuvDst); |
379 | 0 | } |
380 | 0 | else if (iRefIdx0 >= 0 && iRefIdx1 < 0) |
381 | 0 | { |
382 | 0 | addWeightUni(pcYuvSrc0, cu.slice->clpRngs(), pwp0, rpcYuvDst); |
383 | 0 | } |
384 | 0 | else if (iRefIdx0 < 0 && iRefIdx1 >= 0) |
385 | 0 | { |
386 | 0 | addWeightUni(pcYuvSrc1, cu.slice->clpRngs(), pwp1, rpcYuvDst); |
387 | 0 | } |
388 | 0 | else |
389 | 0 | { |
390 | 0 | THROW_RECOVERABLE( "Both reference picture list indices are negative" ); |
391 | 0 | } |
392 | 0 | } |
393 | | |
394 | | } |