/work/dav1d/src/lf_mask.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright © 2018, VideoLAN and dav1d authors |
3 | | * Copyright © 2018, Two Orioles, LLC |
4 | | * All rights reserved. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions are met: |
8 | | * |
9 | | * 1. Redistributions of source code must retain the above copyright notice, this |
10 | | * list of conditions and the following disclaimer. |
11 | | * |
12 | | * 2. Redistributions in binary form must reproduce the above copyright notice, |
13 | | * this list of conditions and the following disclaimer in the documentation |
14 | | * and/or other materials provided with the distribution. |
15 | | * |
16 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
20 | | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | | */ |
27 | | |
28 | | #include "config.h" |
29 | | |
30 | | #include <string.h> |
31 | | |
32 | | #include "common/intops.h" |
33 | | |
34 | | #include "src/ctx.h" |
35 | | #include "src/levels.h" |
36 | | #include "src/lf_mask.h" |
37 | | #include "src/tables.h" |
38 | | |
39 | | static void decomp_tx(uint8_t (*const txa)[2 /* txsz, step */][32 /* y */][32 /* x */], |
40 | | const enum RectTxfmSize from, |
41 | | const int depth, |
42 | | const int y_off, const int x_off, |
43 | | const uint16_t *const tx_masks) |
44 | 0 | { |
45 | 0 | const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[from]; |
46 | 0 | const int is_split = (from == (int) TX_4X4 || depth > 1) ? 0 : |
47 | 0 | (tx_masks[depth] >> (y_off * 4 + x_off)) & 1; |
48 | |
|
49 | 0 | if (is_split) { |
50 | 0 | const enum RectTxfmSize sub = t_dim->sub; |
51 | 0 | const int htw4 = t_dim->w >> 1, hth4 = t_dim->h >> 1; |
52 | |
|
53 | 0 | decomp_tx(txa, sub, depth + 1, y_off * 2 + 0, x_off * 2 + 0, tx_masks); |
54 | 0 | if (t_dim->w >= t_dim->h) |
55 | 0 | decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][0][htw4], |
56 | 0 | sub, depth + 1, y_off * 2 + 0, x_off * 2 + 1, tx_masks); |
57 | 0 | if (t_dim->h >= t_dim->w) { |
58 | 0 | decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][hth4][0], |
59 | 0 | sub, depth + 1, y_off * 2 + 1, x_off * 2 + 0, tx_masks); |
60 | 0 | if (t_dim->w >= t_dim->h) |
61 | 0 | decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][hth4][htw4], |
62 | 0 | sub, depth + 1, y_off * 2 + 1, x_off * 2 + 1, tx_masks); |
63 | 0 | } |
64 | 0 | } else { |
65 | 0 | const int lw = imin(2, t_dim->lw), lh = imin(2, t_dim->lh); |
66 | |
|
67 | 0 | #define set_ctx(rep_macro) \ |
68 | 0 | for (int y = 0; y < t_dim->h; y++) { \ |
69 | 0 | rep_macro(txa[0][0][y], 0, lw); \ |
70 | 0 | rep_macro(txa[1][0][y], 0, lh); \ |
71 | 0 | txa[0][1][y][0] = t_dim->w; \ |
72 | 0 | } |
73 | 0 | case_set_upto16(t_dim->lw); |
74 | 0 | #undef set_ctx |
75 | 0 | dav1d_memset_pow2[t_dim->lw](txa[1][1][0], t_dim->h); |
76 | 0 | } |
77 | 0 | } |
78 | | |
79 | | static inline void mask_edges_inter(uint16_t (*const masks)[32][3][2], |
80 | | const int by4, const int bx4, |
81 | | const int w4, const int h4, const int skip, |
82 | | const enum RectTxfmSize max_tx, |
83 | | const uint16_t *const tx_masks, |
84 | | uint8_t *const a, uint8_t *const l) |
85 | 0 | { |
86 | 0 | const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[max_tx]; |
87 | 0 | int y, x; |
88 | |
|
89 | 0 | ALIGN_STK_16(uint8_t, txa, 2 /* edge */, [2 /* txsz, step */][32 /* y */][32 /* x */]); |
90 | 0 | for (int y_off = 0, y = 0; y < h4; y += t_dim->h, y_off++) |
91 | 0 | for (int x_off = 0, x = 0; x < w4; x += t_dim->w, x_off++) |
92 | 0 | decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][y][x], |
93 | 0 | max_tx, 0, y_off, x_off, tx_masks); |
94 | | |
95 | | // left block edge |
96 | 0 | unsigned mask = 1U << by4; |
97 | 0 | for (y = 0; y < h4; y++, mask <<= 1) { |
98 | 0 | const int sidx = mask >= 0x10000; |
99 | 0 | const unsigned smask = mask >> (sidx << 4); |
100 | 0 | masks[0][bx4][imin(txa[0][0][y][0], l[y])][sidx] |= smask; |
101 | 0 | } |
102 | | |
103 | | // top block edge |
104 | 0 | for (x = 0, mask = 1U << bx4; x < w4; x++, mask <<= 1) { |
105 | 0 | const int sidx = mask >= 0x10000; |
106 | 0 | const unsigned smask = mask >> (sidx << 4); |
107 | 0 | masks[1][by4][imin(txa[1][0][0][x], a[x])][sidx] |= smask; |
108 | 0 | } |
109 | |
|
110 | 0 | if (!skip) { |
111 | | // inner (tx) left|right edges |
112 | 0 | for (y = 0, mask = 1U << by4; y < h4; y++, mask <<= 1) { |
113 | 0 | const int sidx = mask >= 0x10000U; |
114 | 0 | const unsigned smask = mask >> (sidx << 4); |
115 | 0 | int ltx = txa[0][0][y][0]; |
116 | 0 | int step = txa[0][1][y][0]; |
117 | 0 | for (x = step; x < w4; x += step) { |
118 | 0 | const int rtx = txa[0][0][y][x]; |
119 | 0 | masks[0][bx4 + x][imin(rtx, ltx)][sidx] |= smask; |
120 | 0 | ltx = rtx; |
121 | 0 | step = txa[0][1][y][x]; |
122 | 0 | } |
123 | 0 | } |
124 | | |
125 | | // top |
126 | | // inner (tx) --- edges |
127 | | // bottom |
128 | 0 | for (x = 0, mask = 1U << bx4; x < w4; x++, mask <<= 1) { |
129 | 0 | const int sidx = mask >= 0x10000U; |
130 | 0 | const unsigned smask = mask >> (sidx << 4); |
131 | 0 | int ttx = txa[1][0][0][x]; |
132 | 0 | int step = txa[1][1][0][x]; |
133 | 0 | for (y = step; y < h4; y += step) { |
134 | 0 | const int btx = txa[1][0][y][x]; |
135 | 0 | masks[1][by4 + y][imin(ttx, btx)][sidx] |= smask; |
136 | 0 | ttx = btx; |
137 | 0 | step = txa[1][1][y][x]; |
138 | 0 | } |
139 | 0 | } |
140 | 0 | } |
141 | |
|
142 | 0 | for (y = 0; y < h4; y++) |
143 | 0 | l[y] = txa[0][0][y][w4 - 1]; |
144 | 0 | memcpy(a, txa[1][0][h4 - 1], w4); |
145 | 0 | } |
146 | | |
147 | | static inline void mask_edges_intra(uint16_t (*const masks)[32][3][2], |
148 | | const int by4, const int bx4, |
149 | | const int w4, const int h4, |
150 | | const enum RectTxfmSize tx, |
151 | | uint8_t *const a, uint8_t *const l) |
152 | 0 | { |
153 | 0 | const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[tx]; |
154 | 0 | const int twl4 = t_dim->lw, thl4 = t_dim->lh; |
155 | 0 | const int twl4c = imin(2, twl4), thl4c = imin(2, thl4); |
156 | 0 | int y, x; |
157 | | |
158 | | // left block edge |
159 | 0 | unsigned mask = 1U << by4; |
160 | 0 | for (y = 0; y < h4; y++, mask <<= 1) { |
161 | 0 | const int sidx = mask >= 0x10000; |
162 | 0 | const unsigned smask = mask >> (sidx << 4); |
163 | 0 | masks[0][bx4][imin(twl4c, l[y])][sidx] |= smask; |
164 | 0 | } |
165 | | |
166 | | // top block edge |
167 | 0 | for (x = 0, mask = 1U << bx4; x < w4; x++, mask <<= 1) { |
168 | 0 | const int sidx = mask >= 0x10000; |
169 | 0 | const unsigned smask = mask >> (sidx << 4); |
170 | 0 | masks[1][by4][imin(thl4c, a[x])][sidx] |= smask; |
171 | 0 | } |
172 | | |
173 | | // inner (tx) left|right edges |
174 | 0 | const int hstep = t_dim->w; |
175 | 0 | unsigned t = 1U << by4; |
176 | 0 | unsigned inner = (unsigned) ((((uint64_t) t) << h4) - t); |
177 | 0 | unsigned inner1 = inner & 0xffff, inner2 = inner >> 16; |
178 | 0 | for (x = hstep; x < w4; x += hstep) { |
179 | 0 | if (inner1) masks[0][bx4 + x][twl4c][0] |= inner1; |
180 | 0 | if (inner2) masks[0][bx4 + x][twl4c][1] |= inner2; |
181 | 0 | } |
182 | | |
183 | | // top |
184 | | // inner (tx) --- edges |
185 | | // bottom |
186 | 0 | const int vstep = t_dim->h; |
187 | 0 | t = 1U << bx4; |
188 | 0 | inner = (unsigned) ((((uint64_t) t) << w4) - t); |
189 | 0 | inner1 = inner & 0xffff; |
190 | 0 | inner2 = inner >> 16; |
191 | 0 | for (y = vstep; y < h4; y += vstep) { |
192 | 0 | if (inner1) masks[1][by4 + y][thl4c][0] |= inner1; |
193 | 0 | if (inner2) masks[1][by4 + y][thl4c][1] |= inner2; |
194 | 0 | } |
195 | |
|
196 | 0 | dav1d_memset_likely_pow2(a, thl4c, w4); |
197 | 0 | dav1d_memset_likely_pow2(l, twl4c, h4); |
198 | 0 | } |
199 | | |
200 | | static void mask_edges_chroma(uint16_t (*const masks)[32][2][2], |
201 | | const int cby4, const int cbx4, |
202 | | const int cw4, const int ch4, |
203 | | const int skip_inter, |
204 | | const enum RectTxfmSize tx, |
205 | | uint8_t *const a, uint8_t *const l, |
206 | | const int ss_hor, const int ss_ver) |
207 | 0 | { |
208 | 0 | const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[tx]; |
209 | 0 | const int twl4 = t_dim->lw, thl4 = t_dim->lh; |
210 | 0 | const int twl4c = !!twl4, thl4c = !!thl4; |
211 | 0 | int y, x; |
212 | 0 | const int vbits = 4 - ss_ver, hbits = 4 - ss_hor; |
213 | 0 | const int vmask = 16 >> ss_ver, hmask = 16 >> ss_hor; |
214 | 0 | const unsigned vmax = 1 << vmask, hmax = 1 << hmask; |
215 | | |
216 | | // left block edge |
217 | 0 | unsigned mask = 1U << cby4; |
218 | 0 | for (y = 0; y < ch4; y++, mask <<= 1) { |
219 | 0 | const int sidx = mask >= vmax; |
220 | 0 | const unsigned smask = mask >> (sidx << vbits); |
221 | 0 | masks[0][cbx4][imin(twl4c, l[y])][sidx] |= smask; |
222 | 0 | } |
223 | | |
224 | | // top block edge |
225 | 0 | for (x = 0, mask = 1U << cbx4; x < cw4; x++, mask <<= 1) { |
226 | 0 | const int sidx = mask >= hmax; |
227 | 0 | const unsigned smask = mask >> (sidx << hbits); |
228 | 0 | masks[1][cby4][imin(thl4c, a[x])][sidx] |= smask; |
229 | 0 | } |
230 | |
|
231 | 0 | if (!skip_inter) { |
232 | | // inner (tx) left|right edges |
233 | 0 | const int hstep = t_dim->w; |
234 | 0 | unsigned t = 1U << cby4; |
235 | 0 | unsigned inner = (unsigned) ((((uint64_t) t) << ch4) - t); |
236 | 0 | unsigned inner1 = inner & ((1 << vmask) - 1), inner2 = inner >> vmask; |
237 | 0 | for (x = hstep; x < cw4; x += hstep) { |
238 | 0 | if (inner1) masks[0][cbx4 + x][twl4c][0] |= inner1; |
239 | 0 | if (inner2) masks[0][cbx4 + x][twl4c][1] |= inner2; |
240 | 0 | } |
241 | | |
242 | | // top |
243 | | // inner (tx) --- edges |
244 | | // bottom |
245 | 0 | const int vstep = t_dim->h; |
246 | 0 | t = 1U << cbx4; |
247 | 0 | inner = (unsigned) ((((uint64_t) t) << cw4) - t); |
248 | 0 | inner1 = inner & ((1 << hmask) - 1), inner2 = inner >> hmask; |
249 | 0 | for (y = vstep; y < ch4; y += vstep) { |
250 | 0 | if (inner1) masks[1][cby4 + y][thl4c][0] |= inner1; |
251 | 0 | if (inner2) masks[1][cby4 + y][thl4c][1] |= inner2; |
252 | 0 | } |
253 | 0 | } |
254 | |
|
255 | 0 | dav1d_memset_likely_pow2(a, thl4c, cw4); |
256 | 0 | dav1d_memset_likely_pow2(l, twl4c, ch4); |
257 | 0 | } |
258 | | |
259 | | void dav1d_create_lf_mask_intra(Av1Filter *const lflvl, |
260 | | uint8_t (*const level_cache)[4], |
261 | | const ptrdiff_t b4_stride, |
262 | | const uint8_t (*filter_level)[8][2], |
263 | | const int bx, const int by, |
264 | | const int iw, const int ih, |
265 | | const enum BlockSize bs, |
266 | | const enum RectTxfmSize ytx, |
267 | | const enum RectTxfmSize uvtx, |
268 | | const enum Dav1dPixelLayout layout, |
269 | | uint8_t *const ay, uint8_t *const ly, |
270 | | uint8_t *const auv, uint8_t *const luv) |
271 | 0 | { |
272 | 0 | const uint8_t *const b_dim = dav1d_block_dimensions[bs]; |
273 | 0 | const int bw4 = imin(iw - bx, b_dim[0]); |
274 | 0 | const int bh4 = imin(ih - by, b_dim[1]); |
275 | 0 | const int bx4 = bx & 31; |
276 | 0 | const int by4 = by & 31; |
277 | 0 | assert(bw4 >= 0 && bh4 >= 0); |
278 | | |
279 | 0 | if (bw4 && bh4) { |
280 | 0 | uint8_t (*level_cache_ptr)[4] = level_cache + by * b4_stride + bx; |
281 | 0 | for (int y = 0; y < bh4; y++) { |
282 | 0 | for (int x = 0; x < bw4; x++) { |
283 | 0 | level_cache_ptr[x][0] = filter_level[0][0][0]; |
284 | 0 | level_cache_ptr[x][1] = filter_level[1][0][0]; |
285 | 0 | } |
286 | 0 | level_cache_ptr += b4_stride; |
287 | 0 | } |
288 | |
|
289 | 0 | mask_edges_intra(lflvl->filter_y, by4, bx4, bw4, bh4, ytx, ay, ly); |
290 | 0 | } |
291 | |
|
292 | 0 | if (!auv) return; |
293 | | |
294 | 0 | const int ss_ver = layout == DAV1D_PIXEL_LAYOUT_I420; |
295 | 0 | const int ss_hor = layout != DAV1D_PIXEL_LAYOUT_I444; |
296 | 0 | const int cbw4 = imin(((iw + ss_hor) >> ss_hor) - (bx >> ss_hor), |
297 | 0 | (b_dim[0] + ss_hor) >> ss_hor); |
298 | 0 | const int cbh4 = imin(((ih + ss_ver) >> ss_ver) - (by >> ss_ver), |
299 | 0 | (b_dim[1] + ss_ver) >> ss_ver); |
300 | 0 | assert(cbw4 >= 0 && cbh4 >= 0); |
301 | | |
302 | 0 | if (!cbw4 || !cbh4) return; |
303 | | |
304 | 0 | const int cbx4 = bx4 >> ss_hor; |
305 | 0 | const int cby4 = by4 >> ss_ver; |
306 | |
|
307 | 0 | uint8_t (*level_cache_ptr)[4] = |
308 | 0 | level_cache + (by >> ss_ver) * b4_stride + (bx >> ss_hor); |
309 | 0 | for (int y = 0; y < cbh4; y++) { |
310 | 0 | for (int x = 0; x < cbw4; x++) { |
311 | 0 | level_cache_ptr[x][2] = filter_level[2][0][0]; |
312 | 0 | level_cache_ptr[x][3] = filter_level[3][0][0]; |
313 | 0 | } |
314 | 0 | level_cache_ptr += b4_stride; |
315 | 0 | } |
316 | |
|
317 | 0 | mask_edges_chroma(lflvl->filter_uv, cby4, cbx4, cbw4, cbh4, 0, uvtx, |
318 | 0 | auv, luv, ss_hor, ss_ver); |
319 | 0 | } |
320 | | |
321 | | void dav1d_create_lf_mask_inter(Av1Filter *const lflvl, |
322 | | uint8_t (*const level_cache)[4], |
323 | | const ptrdiff_t b4_stride, |
324 | | const uint8_t (*filter_level)[8][2], |
325 | | const int bx, const int by, |
326 | | const int iw, const int ih, |
327 | | const int skip, const enum BlockSize bs, |
328 | | const enum RectTxfmSize max_ytx, |
329 | | const uint16_t *const tx_masks, |
330 | | const enum RectTxfmSize uvtx, |
331 | | const enum Dav1dPixelLayout layout, |
332 | | uint8_t *const ay, uint8_t *const ly, |
333 | | uint8_t *const auv, uint8_t *const luv) |
334 | 0 | { |
335 | 0 | const uint8_t *const b_dim = dav1d_block_dimensions[bs]; |
336 | 0 | const int bw4 = imin(iw - bx, b_dim[0]); |
337 | 0 | const int bh4 = imin(ih - by, b_dim[1]); |
338 | 0 | const int bx4 = bx & 31; |
339 | 0 | const int by4 = by & 31; |
340 | 0 | assert(bw4 >= 0 && bh4 >= 0); |
341 | | |
342 | 0 | if (bw4 && bh4) { |
343 | 0 | uint8_t (*level_cache_ptr)[4] = level_cache + by * b4_stride + bx; |
344 | 0 | for (int y = 0; y < bh4; y++) { |
345 | 0 | for (int x = 0; x < bw4; x++) { |
346 | 0 | level_cache_ptr[x][0] = filter_level[0][0][0]; |
347 | 0 | level_cache_ptr[x][1] = filter_level[1][0][0]; |
348 | 0 | } |
349 | 0 | level_cache_ptr += b4_stride; |
350 | 0 | } |
351 | |
|
352 | 0 | mask_edges_inter(lflvl->filter_y, by4, bx4, bw4, bh4, skip, |
353 | 0 | max_ytx, tx_masks, ay, ly); |
354 | 0 | } |
355 | |
|
356 | 0 | if (!auv) return; |
357 | | |
358 | 0 | const int ss_ver = layout == DAV1D_PIXEL_LAYOUT_I420; |
359 | 0 | const int ss_hor = layout != DAV1D_PIXEL_LAYOUT_I444; |
360 | 0 | const int cbw4 = imin(((iw + ss_hor) >> ss_hor) - (bx >> ss_hor), |
361 | 0 | (b_dim[0] + ss_hor) >> ss_hor); |
362 | 0 | const int cbh4 = imin(((ih + ss_ver) >> ss_ver) - (by >> ss_ver), |
363 | 0 | (b_dim[1] + ss_ver) >> ss_ver); |
364 | 0 | assert(cbw4 >= 0 && cbh4 >= 0); |
365 | | |
366 | 0 | if (!cbw4 || !cbh4) return; |
367 | | |
368 | 0 | const int cbx4 = bx4 >> ss_hor; |
369 | 0 | const int cby4 = by4 >> ss_ver; |
370 | |
|
371 | 0 | uint8_t (*level_cache_ptr)[4] = |
372 | 0 | level_cache + (by >> ss_ver) * b4_stride + (bx >> ss_hor); |
373 | 0 | for (int y = 0; y < cbh4; y++) { |
374 | 0 | for (int x = 0; x < cbw4; x++) { |
375 | 0 | level_cache_ptr[x][2] = filter_level[2][0][0]; |
376 | 0 | level_cache_ptr[x][3] = filter_level[3][0][0]; |
377 | 0 | } |
378 | 0 | level_cache_ptr += b4_stride; |
379 | 0 | } |
380 | |
|
381 | 0 | mask_edges_chroma(lflvl->filter_uv, cby4, cbx4, cbw4, cbh4, skip, uvtx, |
382 | 0 | auv, luv, ss_hor, ss_ver); |
383 | 0 | } |
384 | | |
385 | 0 | void dav1d_calc_eih(Av1FilterLUT *const lim_lut, const int filter_sharpness) { |
386 | | // set E/I/H values from loopfilter level |
387 | 0 | const int sharp = filter_sharpness; |
388 | 0 | for (int level = 0; level < 64; level++) { |
389 | 0 | int limit = level; |
390 | |
|
391 | 0 | if (sharp > 0) { |
392 | 0 | limit >>= (sharp + 3) >> 2; |
393 | 0 | limit = imin(limit, 9 - sharp); |
394 | 0 | } |
395 | 0 | limit = imax(limit, 1); |
396 | |
|
397 | 0 | lim_lut->i[level] = limit; |
398 | 0 | lim_lut->e[level] = 2 * (level + 2) + limit; |
399 | 0 | } |
400 | 0 | lim_lut->sharp[0] = (sharp + 3) >> 2; |
401 | 0 | lim_lut->sharp[1] = sharp ? 9 - sharp : 0xff; |
402 | 0 | } |
403 | | |
404 | | static void calc_lf_value(uint8_t (*const lflvl_values)[2], |
405 | | const int base_lvl, const int lf_delta, |
406 | | const int seg_delta, |
407 | | const Dav1dLoopfilterModeRefDeltas *const mr_delta) |
408 | 0 | { |
409 | 0 | const int base = iclip(iclip(base_lvl + lf_delta, 0, 63) + seg_delta, 0, 63); |
410 | |
|
411 | 0 | if (!mr_delta) { |
412 | 0 | memset(lflvl_values, base, sizeof(*lflvl_values) * 8); |
413 | 0 | } else { |
414 | 0 | const int sh = base >= 32; |
415 | 0 | lflvl_values[0][0] = lflvl_values[0][1] = |
416 | 0 | iclip(base + (mr_delta->ref_delta[0] * (1 << sh)), 0, 63); |
417 | 0 | for (int r = 1; r < 8; r++) { |
418 | 0 | for (int m = 0; m < 2; m++) { |
419 | 0 | const int delta = |
420 | 0 | mr_delta->mode_delta[m] + mr_delta->ref_delta[r]; |
421 | 0 | lflvl_values[r][m] = iclip(base + (delta * (1 << sh)), 0, 63); |
422 | 0 | } |
423 | 0 | } |
424 | 0 | } |
425 | 0 | } |
426 | | |
427 | | static inline void calc_lf_value_chroma(uint8_t (*const lflvl_values)[2], |
428 | | const int base_lvl, const int lf_delta, |
429 | | const int seg_delta, |
430 | | const Dav1dLoopfilterModeRefDeltas *const mr_delta) |
431 | 0 | { |
432 | 0 | if (!base_lvl) |
433 | 0 | memset(lflvl_values, 0, sizeof(*lflvl_values) * 8); |
434 | 0 | else |
435 | 0 | calc_lf_value(lflvl_values, base_lvl, lf_delta, seg_delta, mr_delta); |
436 | 0 | } |
437 | | |
438 | | void dav1d_calc_lf_values(uint8_t (*const lflvl_values)[4][8][2], |
439 | | const Dav1dFrameHeader *const hdr, |
440 | | const int8_t lf_delta[4]) |
441 | 0 | { |
442 | 0 | const int n_seg = hdr->segmentation.enabled ? 8 : 1; |
443 | |
|
444 | 0 | if (!hdr->loopfilter.level_y[0] && !hdr->loopfilter.level_y[1]) { |
445 | 0 | memset(lflvl_values, 0, sizeof(*lflvl_values) * n_seg); |
446 | 0 | return; |
447 | 0 | } |
448 | | |
449 | 0 | const Dav1dLoopfilterModeRefDeltas *const mr_deltas = |
450 | 0 | hdr->loopfilter.mode_ref_delta_enabled ? |
451 | 0 | &hdr->loopfilter.mode_ref_deltas : NULL; |
452 | 0 | for (int s = 0; s < n_seg; s++) { |
453 | 0 | const Dav1dSegmentationData *const segd = |
454 | 0 | hdr->segmentation.enabled ? &hdr->segmentation.seg_data.d[s] : NULL; |
455 | |
|
456 | 0 | calc_lf_value(lflvl_values[s][0], hdr->loopfilter.level_y[0], |
457 | 0 | lf_delta[0], segd ? segd->delta_lf_y_v : 0, mr_deltas); |
458 | 0 | calc_lf_value(lflvl_values[s][1], hdr->loopfilter.level_y[1], |
459 | 0 | lf_delta[hdr->delta.lf.multi ? 1 : 0], |
460 | 0 | segd ? segd->delta_lf_y_h : 0, mr_deltas); |
461 | 0 | calc_lf_value_chroma(lflvl_values[s][2], hdr->loopfilter.level_u, |
462 | 0 | lf_delta[hdr->delta.lf.multi ? 2 : 0], |
463 | 0 | segd ? segd->delta_lf_u : 0, mr_deltas); |
464 | 0 | calc_lf_value_chroma(lflvl_values[s][3], hdr->loopfilter.level_v, |
465 | 0 | lf_delta[hdr->delta.lf.multi ? 3 : 0], |
466 | 0 | segd ? segd->delta_lf_v : 0, mr_deltas); |
467 | 0 | } |
468 | 0 | } |