/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 | 643k | { |
45 | 643k | const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[from]; |
46 | 643k | const int is_split = (from == (int) TX_4X4 || depth > 1) ? 0 : |
47 | 643k | (tx_masks[depth] >> (y_off * 4 + x_off)) & 1; |
48 | | |
49 | 643k | if (is_split) { |
50 | 45.7k | const enum RectTxfmSize sub = t_dim->sub; |
51 | 45.7k | const int htw4 = t_dim->w >> 1, hth4 = t_dim->h >> 1; |
52 | | |
53 | 45.7k | decomp_tx(txa, sub, depth + 1, y_off * 2 + 0, x_off * 2 + 0, tx_masks); |
54 | 45.7k | if (t_dim->w >= t_dim->h) |
55 | 31.5k | decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][0][htw4], |
56 | 31.5k | sub, depth + 1, y_off * 2 + 0, x_off * 2 + 1, tx_masks); |
57 | 45.7k | if (t_dim->h >= t_dim->w) { |
58 | 34.5k | decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][hth4][0], |
59 | 34.5k | sub, depth + 1, y_off * 2 + 1, x_off * 2 + 0, tx_masks); |
60 | 34.5k | if (t_dim->w >= t_dim->h) |
61 | 20.3k | decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][hth4][htw4], |
62 | 20.3k | sub, depth + 1, y_off * 2 + 1, x_off * 2 + 1, tx_masks); |
63 | 34.5k | } |
64 | 597k | } else { |
65 | 597k | const int lw = imin(2, t_dim->lw), lh = imin(2, t_dim->lh); |
66 | | |
67 | 597k | #define set_ctx(rep_macro) \ |
68 | 3.17M | for (int y = 0; y < t_dim->h; y++) { \ |
69 | 2.57M | rep_macro(txa[0][0][y], 0, lw); \ |
70 | 2.57M | rep_macro(txa[1][0][y], 0, lh); \ |
71 | 2.57M | txa[0][1][y][0] = t_dim->w; \ |
72 | 2.57M | } |
73 | 597k | case_set_upto16(t_dim->lw); |
74 | 597k | #undef set_ctx |
75 | 597k | dav1d_memset_pow2[t_dim->lw](txa[1][1][0], t_dim->h); |
76 | 597k | } |
77 | 643k | } |
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 | 468k | { |
86 | 468k | const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[max_tx]; |
87 | 468k | int y, x; |
88 | | |
89 | 468k | ALIGN_STK_16(uint8_t, txa, 2 /* edge */, [2 /* txsz, step */][32 /* y */][32 /* x */]); |
90 | 952k | for (int y_off = 0, y = 0; y < h4; y += t_dim->h, y_off++) |
91 | 994k | for (int x_off = 0, x = 0; x < w4; x += t_dim->w, x_off++) |
92 | 510k | decomp_tx((uint8_t(*)[2][32][32]) &txa[0][0][y][x], |
93 | 510k | max_tx, 0, y_off, x_off, tx_masks); |
94 | | |
95 | | // left block edge |
96 | 468k | unsigned mask = 1U << by4; |
97 | 2.62M | for (y = 0; y < h4; y++, mask <<= 1) { |
98 | 2.16M | const int sidx = mask >= 0x10000; |
99 | 2.16M | const unsigned smask = mask >> (sidx << 4); |
100 | 2.16M | masks[0][bx4][imin(txa[0][0][y][0], l[y])][sidx] |= smask; |
101 | 2.16M | } |
102 | | |
103 | | // top block edge |
104 | 1.79M | for (x = 0, mask = 1U << bx4; x < w4; x++, mask <<= 1) { |
105 | 1.32M | const int sidx = mask >= 0x10000; |
106 | 1.32M | const unsigned smask = mask >> (sidx << 4); |
107 | 1.32M | masks[1][by4][imin(txa[1][0][0][x], a[x])][sidx] |= smask; |
108 | 1.32M | } |
109 | | |
110 | 468k | if (!skip) { |
111 | | // inner (tx) left|right edges |
112 | 1.28M | for (y = 0, mask = 1U << by4; y < h4; y++, mask <<= 1) { |
113 | 1.04M | const int sidx = mask >= 0x10000U; |
114 | 1.04M | const unsigned smask = mask >> (sidx << 4); |
115 | 1.04M | int ltx = txa[0][0][y][0]; |
116 | 1.04M | int step = txa[0][1][y][0]; |
117 | 1.14M | for (x = step; x < w4; x += step) { |
118 | 100k | const int rtx = txa[0][0][y][x]; |
119 | 100k | masks[0][bx4 + x][imin(rtx, ltx)][sidx] |= smask; |
120 | 100k | ltx = rtx; |
121 | 100k | step = txa[0][1][y][x]; |
122 | 100k | } |
123 | 1.04M | } |
124 | | |
125 | | // top |
126 | | // inner (tx) --- edges |
127 | | // bottom |
128 | 945k | for (x = 0, mask = 1U << bx4; x < w4; x++, mask <<= 1) { |
129 | 712k | const int sidx = mask >= 0x10000U; |
130 | 712k | const unsigned smask = mask >> (sidx << 4); |
131 | 712k | int ttx = txa[1][0][0][x]; |
132 | 712k | int step = txa[1][1][0][x]; |
133 | 824k | for (y = step; y < h4; y += step) { |
134 | 111k | const int btx = txa[1][0][y][x]; |
135 | 111k | masks[1][by4 + y][imin(ttx, btx)][sidx] |= smask; |
136 | 111k | ttx = btx; |
137 | 111k | step = txa[1][1][y][x]; |
138 | 111k | } |
139 | 712k | } |
140 | 232k | } |
141 | | |
142 | 2.62M | for (y = 0; y < h4; y++) |
143 | 2.16M | l[y] = txa[0][0][y][w4 - 1]; |
144 | 468k | memcpy(a, txa[1][0][h4 - 1], w4); |
145 | 468k | } |
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 | 403k | { |
153 | 403k | const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[tx]; |
154 | 403k | const int twl4 = t_dim->lw, thl4 = t_dim->lh; |
155 | 403k | const int twl4c = imin(2, twl4), thl4c = imin(2, thl4); |
156 | 403k | int y, x; |
157 | | |
158 | | // left block edge |
159 | 403k | unsigned mask = 1U << by4; |
160 | 2.04M | for (y = 0; y < h4; y++, mask <<= 1) { |
161 | 1.64M | const int sidx = mask >= 0x10000; |
162 | 1.64M | const unsigned smask = mask >> (sidx << 4); |
163 | 1.64M | masks[0][bx4][imin(twl4c, l[y])][sidx] |= smask; |
164 | 1.64M | } |
165 | | |
166 | | // top block edge |
167 | 1.84M | for (x = 0, mask = 1U << bx4; x < w4; x++, mask <<= 1) { |
168 | 1.44M | const int sidx = mask >= 0x10000; |
169 | 1.44M | const unsigned smask = mask >> (sidx << 4); |
170 | 1.44M | masks[1][by4][imin(thl4c, a[x])][sidx] |= smask; |
171 | 1.44M | } |
172 | | |
173 | | // inner (tx) left|right edges |
174 | 403k | const int hstep = t_dim->w; |
175 | 403k | unsigned t = 1U << by4; |
176 | 403k | unsigned inner = (unsigned) ((((uint64_t) t) << h4) - t); |
177 | 403k | unsigned inner1 = inner & 0xffff, inner2 = inner >> 16; |
178 | 506k | for (x = hstep; x < w4; x += hstep) { |
179 | 102k | if (inner1) masks[0][bx4 + x][twl4c][0] |= inner1; |
180 | 102k | if (inner2) masks[0][bx4 + x][twl4c][1] |= inner2; |
181 | 102k | } |
182 | | |
183 | | // top |
184 | | // inner (tx) --- edges |
185 | | // bottom |
186 | 403k | const int vstep = t_dim->h; |
187 | 403k | t = 1U << bx4; |
188 | 403k | inner = (unsigned) ((((uint64_t) t) << w4) - t); |
189 | 403k | inner1 = inner & 0xffff; |
190 | 403k | inner2 = inner >> 16; |
191 | 527k | for (y = vstep; y < h4; y += vstep) { |
192 | 123k | if (inner1) masks[1][by4 + y][thl4c][0] |= inner1; |
193 | 123k | if (inner2) masks[1][by4 + y][thl4c][1] |= inner2; |
194 | 123k | } |
195 | | |
196 | 403k | dav1d_memset_likely_pow2(a, thl4c, w4); |
197 | 403k | dav1d_memset_likely_pow2(l, twl4c, h4); |
198 | 403k | } |
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 | 645k | { |
208 | 645k | const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[tx]; |
209 | 645k | const int twl4 = t_dim->lw, thl4 = t_dim->lh; |
210 | 645k | const int twl4c = !!twl4, thl4c = !!thl4; |
211 | 645k | int y, x; |
212 | 645k | const int vbits = 4 - ss_ver, hbits = 4 - ss_hor; |
213 | 645k | const int vmask = 16 >> ss_ver, hmask = 16 >> ss_hor; |
214 | 645k | const unsigned vmax = 1 << vmask, hmax = 1 << hmask; |
215 | | |
216 | | // left block edge |
217 | 645k | unsigned mask = 1U << cby4; |
218 | 2.85M | for (y = 0; y < ch4; y++, mask <<= 1) { |
219 | 2.21M | const int sidx = mask >= vmax; |
220 | 2.21M | const unsigned smask = mask >> (sidx << vbits); |
221 | 2.21M | masks[0][cbx4][imin(twl4c, l[y])][sidx] |= smask; |
222 | 2.21M | } |
223 | | |
224 | | // top block edge |
225 | 2.42M | for (x = 0, mask = 1U << cbx4; x < cw4; x++, mask <<= 1) { |
226 | 1.78M | const int sidx = mask >= hmax; |
227 | 1.78M | const unsigned smask = mask >> (sidx << hbits); |
228 | 1.78M | masks[1][cby4][imin(thl4c, a[x])][sidx] |= smask; |
229 | 1.78M | } |
230 | | |
231 | 645k | if (!skip_inter) { |
232 | | // inner (tx) left|right edges |
233 | 497k | const int hstep = t_dim->w; |
234 | 497k | unsigned t = 1U << cby4; |
235 | 497k | unsigned inner = (unsigned) ((((uint64_t) t) << ch4) - t); |
236 | 497k | unsigned inner1 = inner & ((1 << vmask) - 1), inner2 = inner >> vmask; |
237 | 551k | for (x = hstep; x < cw4; x += hstep) { |
238 | 54.2k | if (inner1) masks[0][cbx4 + x][twl4c][0] |= inner1; |
239 | 54.2k | if (inner2) masks[0][cbx4 + x][twl4c][1] |= inner2; |
240 | 54.2k | } |
241 | | |
242 | | // top |
243 | | // inner (tx) --- edges |
244 | | // bottom |
245 | 497k | const int vstep = t_dim->h; |
246 | 497k | t = 1U << cbx4; |
247 | 497k | inner = (unsigned) ((((uint64_t) t) << cw4) - t); |
248 | 497k | inner1 = inner & ((1 << hmask) - 1), inner2 = inner >> hmask; |
249 | 560k | for (y = vstep; y < ch4; y += vstep) { |
250 | 63.1k | if (inner1) masks[1][cby4 + y][thl4c][0] |= inner1; |
251 | 63.1k | if (inner2) masks[1][cby4 + y][thl4c][1] |= inner2; |
252 | 63.1k | } |
253 | 497k | } |
254 | | |
255 | 645k | dav1d_memset_likely_pow2(a, thl4c, cw4); |
256 | 645k | dav1d_memset_likely_pow2(l, twl4c, ch4); |
257 | 645k | } |
258 | | |
259 | | static void fill_levelcache_block(uint8_t (*level_cache_ptr)[4], |
260 | | const ptrdiff_t b_stride, |
261 | | const int bw, const int bh, |
262 | | const unsigned v0, |
263 | | const unsigned v1) |
264 | 1.51M | { |
265 | 1.51M | union alias16 v = (union alias16) { .u8 = { v0, v1 }}; |
266 | | |
267 | 7.52M | for (int y = 0; y < bh; y++) { |
268 | 29.7M | for (int x = 0; x < bw; x++) |
269 | 23.7M | ((union alias16 *) &level_cache_ptr[x][0])->u16 = v.u16; |
270 | 6.00M | level_cache_ptr += b_stride; |
271 | 6.00M | } |
272 | 1.51M | } |
273 | | |
274 | | void dav1d_create_lf_mask_intra(Av1Filter *const lflvl, |
275 | | uint8_t (*const level_cache)[4], |
276 | | const ptrdiff_t b4_stride, |
277 | | const uint8_t (*filter_level)[8][2], |
278 | | const int bx, const int by, |
279 | | const int iw, const int ih, |
280 | | const enum BlockSize bs, |
281 | | const enum RectTxfmSize ytx, |
282 | | const enum RectTxfmSize uvtx, |
283 | | const enum Dav1dPixelLayout layout, |
284 | | uint8_t *const ay, uint8_t *const ly, |
285 | | uint8_t *const auv, uint8_t *const luv) |
286 | 504k | { |
287 | 504k | const uint8_t *const b_dim = dav1d_block_dimensions[bs]; |
288 | 504k | const int bw4 = imin(iw - bx, b_dim[0]); |
289 | 504k | const int bh4 = imin(ih - by, b_dim[1]); |
290 | 504k | const int bx4 = bx & 31; |
291 | 504k | const int by4 = by & 31; |
292 | 504k | assert(bw4 >= 0 && bh4 >= 0); |
293 | | |
294 | 504k | if (bw4 && bh4) { |
295 | 403k | uint8_t (*level_cache_ptr)[4] = level_cache + by * b4_stride + bx; |
296 | | |
297 | 403k | fill_levelcache_block(level_cache_ptr, b4_stride, bw4, bh4, |
298 | 403k | filter_level[0][0][0], filter_level[1][0][0]); |
299 | 403k | mask_edges_intra(lflvl->filter_y, by4, bx4, bw4, bh4, ytx, ay, ly); |
300 | 403k | } |
301 | | |
302 | 504k | if (!auv) return; |
303 | | |
304 | 394k | const int ss_ver = layout == DAV1D_PIXEL_LAYOUT_I420; |
305 | 394k | const int ss_hor = layout != DAV1D_PIXEL_LAYOUT_I444; |
306 | 394k | const int cbw4 = imin(((iw + ss_hor) >> ss_hor) - (bx >> ss_hor), |
307 | 394k | (b_dim[0] + ss_hor) >> ss_hor); |
308 | 394k | const int cbh4 = imin(((ih + ss_ver) >> ss_ver) - (by >> ss_ver), |
309 | 394k | (b_dim[1] + ss_ver) >> ss_ver); |
310 | 394k | assert(cbw4 >= 0 && cbh4 >= 0); |
311 | | |
312 | 394k | if (!cbw4 || !cbh4) return; |
313 | | |
314 | 328k | const int cbx4 = bx4 >> ss_hor; |
315 | 328k | const int cby4 = by4 >> ss_ver; |
316 | | |
317 | 328k | uint8_t (*level_cache_ptr)[4] = |
318 | 328k | level_cache + (by >> ss_ver) * b4_stride + (bx >> ss_hor); |
319 | | |
320 | 328k | fill_levelcache_block((uint8_t(*)[4]) &level_cache_ptr[0][2], b4_stride, |
321 | 328k | cbw4, cbh4, filter_level[2][0][0], |
322 | 328k | filter_level[3][0][0]); |
323 | 328k | mask_edges_chroma(lflvl->filter_uv, cby4, cbx4, cbw4, cbh4, 0, uvtx, |
324 | 328k | auv, luv, ss_hor, ss_ver); |
325 | 328k | } |
326 | | |
327 | | void dav1d_create_lf_mask_inter(Av1Filter *const lflvl, |
328 | | uint8_t (*const level_cache)[4], |
329 | | const ptrdiff_t b4_stride, |
330 | | const uint8_t (*filter_level)[8][2], |
331 | | const int bx, const int by, |
332 | | const int iw, const int ih, |
333 | | const int skip, const enum BlockSize bs, |
334 | | const enum RectTxfmSize max_ytx, |
335 | | const uint16_t *const tx_masks, |
336 | | const enum RectTxfmSize uvtx, |
337 | | const enum Dav1dPixelLayout layout, |
338 | | uint8_t *const ay, uint8_t *const ly, |
339 | | uint8_t *const auv, uint8_t *const luv) |
340 | 509k | { |
341 | 509k | const uint8_t *const b_dim = dav1d_block_dimensions[bs]; |
342 | 509k | const int bw4 = imin(iw - bx, b_dim[0]); |
343 | 509k | const int bh4 = imin(ih - by, b_dim[1]); |
344 | 509k | const int bx4 = bx & 31; |
345 | 509k | const int by4 = by & 31; |
346 | 509k | assert(bw4 >= 0 && bh4 >= 0); |
347 | | |
348 | 509k | if (bw4 && bh4) { |
349 | 468k | uint8_t (*level_cache_ptr)[4] = level_cache + by * b4_stride + bx; |
350 | | |
351 | 468k | fill_levelcache_block(level_cache_ptr, b4_stride, bw4, bh4, |
352 | 468k | filter_level[0][0][0], filter_level[1][0][0]); |
353 | 468k | mask_edges_inter(lflvl->filter_y, by4, bx4, bw4, bh4, skip, |
354 | 468k | max_ytx, tx_masks, ay, ly); |
355 | 468k | } |
356 | | |
357 | 509k | if (!auv) return; |
358 | | |
359 | 315k | const int ss_ver = layout == DAV1D_PIXEL_LAYOUT_I420; |
360 | 315k | const int ss_hor = layout != DAV1D_PIXEL_LAYOUT_I444; |
361 | 315k | const int cbw4 = imin(((iw + ss_hor) >> ss_hor) - (bx >> ss_hor), |
362 | 315k | (b_dim[0] + ss_hor) >> ss_hor); |
363 | 315k | const int cbh4 = imin(((ih + ss_ver) >> ss_ver) - (by >> ss_ver), |
364 | 315k | (b_dim[1] + ss_ver) >> ss_ver); |
365 | 315k | assert(cbw4 >= 0 && cbh4 >= 0); |
366 | | |
367 | 315k | if (!cbw4 || !cbh4) return; |
368 | | |
369 | 314k | const int cbx4 = bx4 >> ss_hor; |
370 | 314k | const int cby4 = by4 >> ss_ver; |
371 | | |
372 | 314k | uint8_t (*level_cache_ptr)[4] = |
373 | 314k | level_cache + (by >> ss_ver) * b4_stride + (bx >> ss_hor); |
374 | | |
375 | 314k | fill_levelcache_block((uint8_t(*)[4]) &level_cache_ptr[0][2], b4_stride, |
376 | 314k | cbw4, cbh4, filter_level[2][0][0], |
377 | 314k | filter_level[3][0][0]); |
378 | 314k | mask_edges_chroma(lflvl->filter_uv, cby4, cbx4, cbw4, cbh4, skip, uvtx, |
379 | 314k | auv, luv, ss_hor, ss_ver); |
380 | 314k | } |
381 | | |
382 | 62.6k | void dav1d_calc_eih(Av1FilterLUT *const lim_lut, const int filter_sharpness) { |
383 | | // set E/I/H values from loopfilter level |
384 | 62.6k | const int sharp = filter_sharpness; |
385 | 4.07M | for (int level = 0; level < 64; level++) { |
386 | 4.00M | int limit = level; |
387 | | |
388 | 4.00M | if (sharp > 0) { |
389 | 2.41M | limit >>= (sharp + 3) >> 2; |
390 | 2.41M | limit = imin(limit, 9 - sharp); |
391 | 2.41M | } |
392 | 4.00M | limit = imax(limit, 1); |
393 | | |
394 | 4.00M | lim_lut->i[level] = limit; |
395 | 4.00M | lim_lut->e[level] = 2 * (level + 2) + limit; |
396 | 4.00M | } |
397 | 62.6k | lim_lut->sharp[0] = (sharp + 3) >> 2; |
398 | 62.6k | lim_lut->sharp[1] = sharp ? 9 - sharp : 0xff; |
399 | 62.6k | } |
400 | | |
401 | | static void calc_lf_value(uint8_t (*const lflvl_values)[2], |
402 | | const int base_lvl, const int lf_delta, |
403 | | const int seg_delta, |
404 | | const Dav1dLoopfilterModeRefDeltas *const mr_delta) |
405 | 1.82M | { |
406 | 1.82M | const int base = iclip(iclip(base_lvl + lf_delta, 0, 63) + seg_delta, 0, 63); |
407 | | |
408 | 1.82M | if (!mr_delta) { |
409 | 1.57M | memset(lflvl_values, base, sizeof(*lflvl_values) * 8); |
410 | 1.57M | } else { |
411 | 256k | const int sh = base >= 32; |
412 | 256k | lflvl_values[0][0] = lflvl_values[0][1] = |
413 | 256k | iclip(base + (mr_delta->ref_delta[0] * (1 << sh)), 0, 63); |
414 | 2.05M | for (int r = 1; r < 8; r++) { |
415 | 5.39M | for (int m = 0; m < 2; m++) { |
416 | 3.59M | const int delta = |
417 | 3.59M | mr_delta->mode_delta[m] + mr_delta->ref_delta[r]; |
418 | 3.59M | lflvl_values[r][m] = iclip(base + (delta * (1 << sh)), 0, 63); |
419 | 3.59M | } |
420 | 1.79M | } |
421 | 256k | } |
422 | 1.82M | } |
423 | | |
424 | | static inline void calc_lf_value_chroma(uint8_t (*const lflvl_values)[2], |
425 | | const int base_lvl, const int lf_delta, |
426 | | const int seg_delta, |
427 | | const Dav1dLoopfilterModeRefDeltas *const mr_delta) |
428 | 1.05M | { |
429 | 1.05M | if (!base_lvl) |
430 | 285k | memset(lflvl_values, 0, sizeof(*lflvl_values) * 8); |
431 | 772k | else |
432 | 772k | calc_lf_value(lflvl_values, base_lvl, lf_delta, seg_delta, mr_delta); |
433 | 1.05M | } |
434 | | |
435 | | void dav1d_calc_lf_values(uint8_t (*const lflvl_values)[4][8][2], |
436 | | const Dav1dFrameHeader *const hdr, |
437 | | const int8_t lf_delta[4]) |
438 | 139k | { |
439 | 139k | const int n_seg = hdr->segmentation.enabled ? 8 : 1; |
440 | | |
441 | 139k | if (!hdr->loopfilter.level_y[0] && !hdr->loopfilter.level_y[1]) { |
442 | 16.5k | memset(lflvl_values, 0, sizeof(*lflvl_values) * n_seg); |
443 | 16.5k | return; |
444 | 16.5k | } |
445 | | |
446 | 123k | const Dav1dLoopfilterModeRefDeltas *const mr_deltas = |
447 | 123k | hdr->loopfilter.mode_ref_delta_enabled ? |
448 | 123k | &hdr->loopfilter.mode_ref_deltas : NULL; |
449 | 652k | for (int s = 0; s < n_seg; s++) { |
450 | 528k | const Dav1dSegmentationData *const segd = |
451 | 528k | hdr->segmentation.enabled ? &hdr->segmentation.seg_data.d[s] : NULL; |
452 | | |
453 | 528k | calc_lf_value(lflvl_values[s][0], hdr->loopfilter.level_y[0], |
454 | 528k | lf_delta[0], segd ? segd->delta_lf_y_v : 0, mr_deltas); |
455 | 528k | calc_lf_value(lflvl_values[s][1], hdr->loopfilter.level_y[1], |
456 | 528k | lf_delta[hdr->delta.lf.multi ? 1 : 0], |
457 | 528k | segd ? segd->delta_lf_y_h : 0, mr_deltas); |
458 | 528k | calc_lf_value_chroma(lflvl_values[s][2], hdr->loopfilter.level_u, |
459 | 528k | lf_delta[hdr->delta.lf.multi ? 2 : 0], |
460 | 528k | segd ? segd->delta_lf_u : 0, mr_deltas); |
461 | 528k | calc_lf_value_chroma(lflvl_values[s][3], hdr->loopfilter.level_v, |
462 | 528k | lf_delta[hdr->delta.lf.multi ? 3 : 0], |
463 | 528k | segd ? segd->delta_lf_v : 0, mr_deltas); |
464 | 528k | } |
465 | 123k | } |