blob: a4aad7b9d704cca1b2a7b4b194c36bd7f1e7810d [file] [log] [blame]
Yaowu Xuc27fc142016-08-22 16:08:15 -07001/*
Yaowu Xu2ab7ff02016-09-02 12:04:54 -07002 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
Yaowu Xuc27fc142016-08-22 16:08:15 -07003 *
Yaowu Xu2ab7ff02016-09-02 12:04:54 -07004 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10 *
Yaowu Xuc27fc142016-08-22 16:08:15 -070011 */
12
13#include <math.h>
14
Yaowu Xuf883b422016-08-30 14:01:10 -070015#include "./aom_config.h"
16#include "./aom_dsp_rtcd.h"
Yaowu Xuc27fc142016-08-22 16:08:15 -070017#include "av1/common/onyxc_int.h"
18#include "av1/common/restoration.h"
Yaowu Xuf883b422016-08-30 14:01:10 -070019#include "aom_dsp/aom_dsp_common.h"
20#include "aom_mem/aom_mem.h"
Yaowu Xuc27fc142016-08-22 16:08:15 -070021#include "aom_ports/mem.h"
22
23#define BILATERAL_PARAM_PRECISION 16
24#define BILATERAL_AMP_RANGE 256
25#define BILATERAL_AMP_RANGE_SYM (2 * BILATERAL_AMP_RANGE + 1)
26
27static uint8_t
28 bilateral_filter_coeffs_r_kf[BILATERAL_LEVELS_KF][BILATERAL_AMP_RANGE_SYM];
29static uint8_t
30 bilateral_filter_coeffs_r[BILATERAL_LEVELS][BILATERAL_AMP_RANGE_SYM];
31static uint8_t bilateral_filter_coeffs_s_kf[BILATERAL_LEVELS_KF]
32 [RESTORATION_WIN][RESTORATION_WIN];
33static uint8_t bilateral_filter_coeffs_s[BILATERAL_LEVELS][RESTORATION_WIN]
34 [RESTORATION_WIN];
35
36typedef struct bilateral_params {
37 int sigma_x; // spatial variance x
38 int sigma_y; // spatial variance y
39 int sigma_r; // range variance
40} BilateralParamsType;
41
42static BilateralParamsType bilateral_level_to_params_arr[BILATERAL_LEVELS] = {
43 // Values are rounded to 1/16 th precision
44 { 8, 9, 30 }, { 9, 8, 30 }, { 9, 11, 32 }, { 11, 9, 32 },
45 { 14, 14, 32 }, { 18, 18, 36 }, { 24, 24, 40 }, { 32, 32, 40 },
46};
47
48static BilateralParamsType
49 bilateral_level_to_params_arr_kf[BILATERAL_LEVELS_KF] = {
50 // Values are rounded to 1/16 th precision
51 { 8, 8, 30 }, { 9, 9, 32 }, { 10, 10, 32 }, { 12, 12, 32 },
52 { 14, 14, 32 }, { 18, 18, 36 }, { 24, 24, 40 }, { 30, 30, 44 },
53 { 36, 36, 48 }, { 42, 42, 48 }, { 48, 48, 48 }, { 48, 48, 56 },
54 { 56, 56, 48 }, { 56, 56, 56 }, { 56, 56, 64 }, { 64, 64, 48 },
55 };
56
57typedef void (*restore_func_type)(uint8_t *data8, int width, int height,
58 int stride, RestorationInternal *rst,
59 uint8_t *tmpdata8, int tmpstride);
Yaowu Xuf883b422016-08-30 14:01:10 -070060#if CONFIG_AOM_HIGHBITDEPTH
Yaowu Xuc27fc142016-08-22 16:08:15 -070061typedef void (*restore_func_highbd_type)(uint8_t *data8, int width, int height,
62 int stride, RestorationInternal *rst,
63 uint8_t *tmpdata8, int tmpstride,
64 int bit_depth);
Yaowu Xuf883b422016-08-30 14:01:10 -070065#endif // CONFIG_AOM_HIGHBITDEPTH
Yaowu Xuc27fc142016-08-22 16:08:15 -070066
Yaowu Xuf883b422016-08-30 14:01:10 -070067static INLINE BilateralParamsType av1_bilateral_level_to_params(int index,
68 int kf) {
Yaowu Xuc27fc142016-08-22 16:08:15 -070069 return kf ? bilateral_level_to_params_arr_kf[index]
70 : bilateral_level_to_params_arr[index];
71}
72
73typedef struct TileParams {
74 int width;
75 int height;
76} TileParams;
77
78static TileParams restoration_tile_sizes[RESTORATION_TILESIZES] = {
79 { 64, 64 }, { 128, 128 }, { 256, 256 }
80};
81
Yaowu Xuf883b422016-08-30 14:01:10 -070082void av1_get_restoration_tile_size(int tilesize, int width, int height,
83 int *tile_width, int *tile_height,
84 int *nhtiles, int *nvtiles) {
Yaowu Xuc27fc142016-08-22 16:08:15 -070085 *tile_width = (tilesize < 0)
86 ? width
Yaowu Xuf883b422016-08-30 14:01:10 -070087 : AOMMIN(restoration_tile_sizes[tilesize].width, width);
Yaowu Xuc27fc142016-08-22 16:08:15 -070088 *tile_height = (tilesize < 0)
89 ? height
Yaowu Xuf883b422016-08-30 14:01:10 -070090 : AOMMIN(restoration_tile_sizes[tilesize].height, height);
Yaowu Xuc27fc142016-08-22 16:08:15 -070091 *nhtiles = (width + (*tile_width >> 1)) / *tile_width;
92 *nvtiles = (height + (*tile_height >> 1)) / *tile_height;
93}
94
Yaowu Xuf883b422016-08-30 14:01:10 -070095int av1_get_restoration_ntiles(int tilesize, int width, int height) {
Yaowu Xuc27fc142016-08-22 16:08:15 -070096 int nhtiles, nvtiles;
97 int tile_width, tile_height;
Yaowu Xuf883b422016-08-30 14:01:10 -070098 av1_get_restoration_tile_size(tilesize, width, height, &tile_width,
99 &tile_height, &nhtiles, &nvtiles);
Yaowu Xuc27fc142016-08-22 16:08:15 -0700100 return (nhtiles * nvtiles);
101}
102
Yaowu Xuf883b422016-08-30 14:01:10 -0700103void av1_loop_restoration_precal() {
Yaowu Xuc27fc142016-08-22 16:08:15 -0700104 int i;
105 for (i = 0; i < BILATERAL_LEVELS_KF; i++) {
Yaowu Xuf883b422016-08-30 14:01:10 -0700106 const BilateralParamsType param = av1_bilateral_level_to_params(i, 1);
Yaowu Xuc27fc142016-08-22 16:08:15 -0700107 const int sigma_x = param.sigma_x;
108 const int sigma_y = param.sigma_y;
109 const int sigma_r = param.sigma_r;
110 const double sigma_r_d = (double)sigma_r / BILATERAL_PARAM_PRECISION;
111 const double sigma_x_d = (double)sigma_x / BILATERAL_PARAM_PRECISION;
112 const double sigma_y_d = (double)sigma_y / BILATERAL_PARAM_PRECISION;
113
114 uint8_t *fr = bilateral_filter_coeffs_r_kf[i] + BILATERAL_AMP_RANGE;
115 int j, x, y;
116 for (j = 0; j <= BILATERAL_AMP_RANGE; j++) {
117 fr[j] = (uint8_t)(0.5 +
118 RESTORATION_FILT_STEP *
119 exp(-(j * j) / (2 * sigma_r_d * sigma_r_d)));
120 fr[-j] = fr[j];
121 }
122 for (y = -RESTORATION_HALFWIN; y <= RESTORATION_HALFWIN; y++) {
123 for (x = -RESTORATION_HALFWIN; x <= RESTORATION_HALFWIN; x++) {
124 bilateral_filter_coeffs_s_kf
125 [i][y + RESTORATION_HALFWIN][x + RESTORATION_HALFWIN] =
126 (uint8_t)(0.5 +
127 RESTORATION_FILT_STEP *
128 exp(-(x * x) / (2 * sigma_x_d * sigma_x_d) -
129 (y * y) / (2 * sigma_y_d * sigma_y_d)));
130 }
131 }
132 }
133 for (i = 0; i < BILATERAL_LEVELS; i++) {
Yaowu Xuf883b422016-08-30 14:01:10 -0700134 const BilateralParamsType param = av1_bilateral_level_to_params(i, 0);
Yaowu Xuc27fc142016-08-22 16:08:15 -0700135 const int sigma_x = param.sigma_x;
136 const int sigma_y = param.sigma_y;
137 const int sigma_r = param.sigma_r;
138 const double sigma_r_d = (double)sigma_r / BILATERAL_PARAM_PRECISION;
139 const double sigma_x_d = (double)sigma_x / BILATERAL_PARAM_PRECISION;
140 const double sigma_y_d = (double)sigma_y / BILATERAL_PARAM_PRECISION;
141
142 uint8_t *fr = bilateral_filter_coeffs_r[i] + BILATERAL_AMP_RANGE;
143 int j, x, y;
144 for (j = 0; j <= BILATERAL_AMP_RANGE; j++) {
145 fr[j] = (uint8_t)(0.5 +
146 RESTORATION_FILT_STEP *
147 exp(-(j * j) / (2 * sigma_r_d * sigma_r_d)));
148 fr[-j] = fr[j];
149 }
150 for (y = -RESTORATION_HALFWIN; y <= RESTORATION_HALFWIN; y++) {
151 for (x = -RESTORATION_HALFWIN; x <= RESTORATION_HALFWIN; x++) {
152 bilateral_filter_coeffs_s[i][y +
153 RESTORATION_HALFWIN][x +
154 RESTORATION_HALFWIN] =
155 (uint8_t)(0.5 +
156 RESTORATION_FILT_STEP *
157 exp(-(x * x) / (2 * sigma_x_d * sigma_x_d) -
158 (y * y) / (2 * sigma_y_d * sigma_y_d)));
159 }
160 }
161 }
162}
163
Yaowu Xuf883b422016-08-30 14:01:10 -0700164int av1_bilateral_level_bits(const AV1_COMMON *const cm) {
Yaowu Xuc27fc142016-08-22 16:08:15 -0700165 return cm->frame_type == KEY_FRAME ? BILATERAL_LEVEL_BITS_KF
166 : BILATERAL_LEVEL_BITS;
167}
168
Yaowu Xuf883b422016-08-30 14:01:10 -0700169void av1_loop_restoration_init(RestorationInternal *rst, RestorationInfo *rsi,
170 int kf, int width, int height) {
Yaowu Xuc27fc142016-08-22 16:08:15 -0700171 int i, tile_idx;
172 rst->restoration_type = rsi->restoration_type;
173 rst->subsampling_x = 0;
174 rst->subsampling_y = 0;
175 if (rsi->restoration_type == RESTORE_BILATERAL) {
176 rst->tilesize_index = BILATERAL_TILESIZE;
177 rst->ntiles =
Yaowu Xuf883b422016-08-30 14:01:10 -0700178 av1_get_restoration_ntiles(rst->tilesize_index, width, height);
179 av1_get_restoration_tile_size(rst->tilesize_index, width, height,
180 &rst->tile_width, &rst->tile_height,
181 &rst->nhtiles, &rst->nvtiles);
Yaowu Xuc27fc142016-08-22 16:08:15 -0700182 rst->bilateral_level = rsi->bilateral_level;
183 rst->wr_lut = (uint8_t **)malloc(sizeof(*rst->wr_lut) * rst->ntiles);
184 assert(rst->wr_lut != NULL);
185 rst->wx_lut = (uint8_t(**)[RESTORATION_WIN])malloc(sizeof(*rst->wx_lut) *
186 rst->ntiles);
187 assert(rst->wx_lut != NULL);
188 for (tile_idx = 0; tile_idx < rst->ntiles; ++tile_idx) {
189 const int level = rsi->bilateral_level[tile_idx];
190 if (level >= 0) {
191 rst->wr_lut[tile_idx] = kf ? bilateral_filter_coeffs_r_kf[level]
192 : bilateral_filter_coeffs_r[level];
193 rst->wx_lut[tile_idx] = kf ? bilateral_filter_coeffs_s_kf[level]
194 : bilateral_filter_coeffs_s[level];
195 }
196 }
197 } else if (rsi->restoration_type == RESTORE_WIENER) {
198 rst->tilesize_index = WIENER_TILESIZE;
199 rst->ntiles =
Yaowu Xuf883b422016-08-30 14:01:10 -0700200 av1_get_restoration_ntiles(rst->tilesize_index, width, height);
201 av1_get_restoration_tile_size(rst->tilesize_index, width, height,
202 &rst->tile_width, &rst->tile_height,
203 &rst->nhtiles, &rst->nvtiles);
Yaowu Xuc27fc142016-08-22 16:08:15 -0700204 rst->wiener_level = rsi->wiener_level;
205 rst->vfilter =
206 (int(*)[RESTORATION_WIN])malloc(sizeof(*rst->vfilter) * rst->ntiles);
207 assert(rst->vfilter != NULL);
208 rst->hfilter =
209 (int(*)[RESTORATION_WIN])malloc(sizeof(*rst->hfilter) * rst->ntiles);
210 assert(rst->hfilter != NULL);
211 for (tile_idx = 0; tile_idx < rst->ntiles; ++tile_idx) {
212 rst->vfilter[tile_idx][RESTORATION_HALFWIN] =
213 rst->hfilter[tile_idx][RESTORATION_HALFWIN] = RESTORATION_FILT_STEP;
214 for (i = 0; i < RESTORATION_HALFWIN; ++i) {
215 rst->vfilter[tile_idx][i] =
216 rst->vfilter[tile_idx][RESTORATION_WIN - 1 - i] =
217 rsi->vfilter[tile_idx][i];
218 rst->hfilter[tile_idx][i] =
219 rst->hfilter[tile_idx][RESTORATION_WIN - 1 - i] =
220 rsi->hfilter[tile_idx][i];
221 rst->vfilter[tile_idx][RESTORATION_HALFWIN] -=
222 2 * rsi->vfilter[tile_idx][i];
223 rst->hfilter[tile_idx][RESTORATION_HALFWIN] -=
224 2 * rsi->hfilter[tile_idx][i];
225 }
226 }
227 }
228}
229
230static void loop_bilateral_filter(uint8_t *data, int width, int height,
231 int stride, RestorationInternal *rst,
232 uint8_t *tmpdata, int tmpstride) {
233 int i, j, tile_idx, htile_idx, vtile_idx;
234 int h_start, h_end, v_start, v_end;
235 int tile_width, tile_height;
236
237 tile_width = rst->tile_width >> rst->subsampling_x;
238 tile_height = rst->tile_height >> rst->subsampling_y;
239
240 for (tile_idx = 0; tile_idx < rst->ntiles; ++tile_idx) {
241 uint8_t *data_p, *tmpdata_p;
242 const uint8_t *wr_lut_ = rst->wr_lut[tile_idx] + BILATERAL_AMP_RANGE;
243
244 if (rst->bilateral_level[tile_idx] < 0) continue;
245
246 htile_idx = tile_idx % rst->nhtiles;
247 vtile_idx = tile_idx / rst->nhtiles;
248 h_start =
249 htile_idx * tile_width + ((htile_idx > 0) ? 0 : RESTORATION_HALFWIN);
250 h_end = (htile_idx < rst->nhtiles - 1) ? ((htile_idx + 1) * tile_width)
251 : (width - RESTORATION_HALFWIN);
252 v_start =
253 vtile_idx * tile_height + ((vtile_idx > 0) ? 0 : RESTORATION_HALFWIN);
254 v_end = (vtile_idx < rst->nvtiles - 1) ? ((vtile_idx + 1) * tile_height)
255 : (height - RESTORATION_HALFWIN);
256
257 data_p = data + h_start + v_start * stride;
258 tmpdata_p = tmpdata + h_start + v_start * tmpstride;
259
260 for (i = 0; i < (v_end - v_start); ++i) {
261 for (j = 0; j < (h_end - h_start); ++j) {
262 int x, y;
263 int flsum = 0, wtsum = 0, wt;
264 uint8_t *data_p2 = data_p + j - RESTORATION_HALFWIN * stride;
265 for (y = -RESTORATION_HALFWIN; y <= RESTORATION_HALFWIN; ++y) {
266 for (x = -RESTORATION_HALFWIN; x <= RESTORATION_HALFWIN; ++x) {
267 wt = (int)rst->wx_lut[tile_idx][y + RESTORATION_HALFWIN]
268 [x + RESTORATION_HALFWIN] *
269 (int)wr_lut_[data_p2[x] - data_p[j]];
270 wtsum += wt;
271 flsum += wt * data_p2[x];
272 }
273 data_p2 += stride;
274 }
275 if (wtsum > 0)
276 tmpdata_p[j] = clip_pixel((int)((flsum + wtsum / 2) / wtsum));
277 else
278 tmpdata_p[j] = data_p[j];
279 }
280 tmpdata_p += tmpstride;
281 data_p += stride;
282 }
283 for (i = v_start; i < v_end; ++i) {
284 memcpy(data + i * stride + h_start, tmpdata + i * tmpstride + h_start,
285 (h_end - h_start) * sizeof(*data));
286 }
287 }
288}
289
290uint8_t hor_sym_filter(uint8_t *d, int *hfilter) {
291 int32_t s =
292 (1 << (RESTORATION_FILT_BITS - 1)) + d[0] * hfilter[RESTORATION_HALFWIN];
293 int i;
294 for (i = 1; i <= RESTORATION_HALFWIN; ++i)
295 s += (d[i] + d[-i]) * hfilter[RESTORATION_HALFWIN + i];
296 return clip_pixel(s >> RESTORATION_FILT_BITS);
297}
298
299uint8_t ver_sym_filter(uint8_t *d, int stride, int *vfilter) {
300 int32_t s =
301 (1 << (RESTORATION_FILT_BITS - 1)) + d[0] * vfilter[RESTORATION_HALFWIN];
302 int i;
303 for (i = 1; i <= RESTORATION_HALFWIN; ++i)
304 s += (d[i * stride] + d[-i * stride]) * vfilter[RESTORATION_HALFWIN + i];
305 return clip_pixel(s >> RESTORATION_FILT_BITS);
306}
307
308static void loop_wiener_filter(uint8_t *data, int width, int height, int stride,
309 RestorationInternal *rst, uint8_t *tmpdata,
310 int tmpstride) {
311 int i, j, tile_idx, htile_idx, vtile_idx;
312 int h_start, h_end, v_start, v_end;
313 int tile_width, tile_height;
314 uint8_t *data_p, *tmpdata_p;
315
316 tile_width = rst->tile_width >> rst->subsampling_x;
317 tile_height = rst->tile_height >> rst->subsampling_y;
318
319 // Initialize tmp buffer
320 data_p = data;
321 tmpdata_p = tmpdata;
322 for (i = 0; i < height; ++i) {
323 memcpy(tmpdata_p, data_p, sizeof(*data_p) * width);
324 data_p += stride;
325 tmpdata_p += tmpstride;
326 }
327
328 // Filter row-wise tile-by-tile
329 for (tile_idx = 0; tile_idx < rst->ntiles; ++tile_idx) {
330 if (rst->wiener_level[tile_idx] == 0) continue;
331 htile_idx = tile_idx % rst->nhtiles;
332 vtile_idx = tile_idx / rst->nhtiles;
333 h_start =
334 htile_idx * tile_width + ((htile_idx > 0) ? 0 : RESTORATION_HALFWIN);
335 h_end = (htile_idx < rst->nhtiles - 1) ? ((htile_idx + 1) * tile_width)
336 : (width - RESTORATION_HALFWIN);
337 v_start = vtile_idx * tile_height;
338 v_end = (vtile_idx < rst->nvtiles - 1) ? ((vtile_idx + 1) * tile_height)
339 : height;
340 data_p = data + h_start + v_start * stride;
341 tmpdata_p = tmpdata + h_start + v_start * tmpstride;
342 for (i = 0; i < (v_end - v_start); ++i) {
343 for (j = 0; j < (h_end - h_start); ++j) {
344 *tmpdata_p++ = hor_sym_filter(data_p++, rst->hfilter[tile_idx]);
345 }
346 data_p += stride - (h_end - h_start);
347 tmpdata_p += tmpstride - (h_end - h_start);
348 }
349 }
350
351 // Filter column-wise tile-by-tile (bands of thickness RESTORATION_HALFWIN
352 // at top and bottom of tiles allow filtering overlap, and are not optimally
353 // filtered)
354 for (tile_idx = 0; tile_idx < rst->ntiles; ++tile_idx) {
355 if (rst->wiener_level[tile_idx] == 0) continue;
356 htile_idx = tile_idx % rst->nhtiles;
357 vtile_idx = tile_idx / rst->nhtiles;
358 h_start = htile_idx * tile_width;
359 h_end =
360 (htile_idx < rst->nhtiles - 1) ? ((htile_idx + 1) * tile_width) : width;
361 v_start =
362 vtile_idx * tile_height + ((vtile_idx > 0) ? 0 : RESTORATION_HALFWIN);
363 v_end = (vtile_idx < rst->nvtiles - 1) ? ((vtile_idx + 1) * tile_height)
364 : (height - RESTORATION_HALFWIN);
365 data_p = data + h_start + v_start * stride;
366 tmpdata_p = tmpdata + h_start + v_start * tmpstride;
367 for (i = 0; i < (v_end - v_start); ++i) {
368 for (j = 0; j < (h_end - h_start); ++j) {
369 *data_p++ =
370 ver_sym_filter(tmpdata_p++, tmpstride, rst->vfilter[tile_idx]);
371 }
372 data_p += stride - (h_end - h_start);
373 tmpdata_p += tmpstride - (h_end - h_start);
374 }
375 }
376}
377
Yaowu Xuf883b422016-08-30 14:01:10 -0700378#if CONFIG_AOM_HIGHBITDEPTH
Yaowu Xuc27fc142016-08-22 16:08:15 -0700379static void loop_bilateral_filter_highbd(uint8_t *data8, int width, int height,
380 int stride, RestorationInternal *rst,
381 uint8_t *tmpdata8, int tmpstride,
382 int bit_depth) {
383 int i, j, tile_idx, htile_idx, vtile_idx;
384 int h_start, h_end, v_start, v_end;
385 int tile_width, tile_height;
386
387 uint16_t *data = CONVERT_TO_SHORTPTR(data8);
388 uint16_t *tmpdata = CONVERT_TO_SHORTPTR(tmpdata8);
389
390 tile_width = rst->tile_width >> rst->subsampling_x;
391 tile_height = rst->tile_height >> rst->subsampling_y;
392
393 for (tile_idx = 0; tile_idx < rst->ntiles; ++tile_idx) {
394 uint16_t *data_p, *tmpdata_p;
395 const uint8_t *wr_lut_ = rst->wr_lut[tile_idx] + BILATERAL_AMP_RANGE;
396
397 if (rst->bilateral_level[tile_idx] < 0) continue;
398
399 htile_idx = tile_idx % rst->nhtiles;
400 vtile_idx = tile_idx / rst->nhtiles;
401 h_start =
402 htile_idx * tile_width + ((htile_idx > 0) ? 0 : RESTORATION_HALFWIN);
403 h_end = (htile_idx < rst->nhtiles - 1) ? ((htile_idx + 1) * tile_width)
404 : (width - RESTORATION_HALFWIN);
405 v_start =
406 vtile_idx * tile_height + ((vtile_idx > 0) ? 0 : RESTORATION_HALFWIN);
407 v_end = (vtile_idx < rst->nvtiles - 1) ? ((vtile_idx + 1) * tile_height)
408 : (height - RESTORATION_HALFWIN);
409
410 data_p = data + h_start + v_start * stride;
411 tmpdata_p = tmpdata + h_start + v_start * tmpstride;
412
413 for (i = 0; i < (v_end - v_start); ++i) {
414 for (j = 0; j < (h_end - h_start); ++j) {
415 int x, y;
416 int flsum = 0, wtsum = 0, wt;
417 uint16_t *data_p2 = data_p + j - RESTORATION_HALFWIN * stride;
418 for (y = -RESTORATION_HALFWIN; y <= RESTORATION_HALFWIN; ++y) {
419 for (x = -RESTORATION_HALFWIN; x <= RESTORATION_HALFWIN; ++x) {
420 wt = (int)rst->wx_lut[tile_idx][y + RESTORATION_HALFWIN]
421 [x + RESTORATION_HALFWIN] *
422 (int)wr_lut_[data_p2[x] - data_p[j]];
423 wtsum += wt;
424 flsum += wt * data_p2[x];
425 }
426 data_p2 += stride;
427 }
428 if (wtsum > 0)
429 tmpdata_p[j] =
430 clip_pixel_highbd((int)((flsum + wtsum / 2) / wtsum), bit_depth);
431 else
432 tmpdata_p[j] = data_p[j];
433 }
434 tmpdata_p += tmpstride;
435 data_p += stride;
436 }
437 for (i = v_start; i < v_end; ++i) {
438 memcpy(data + i * stride + h_start, tmpdata + i * tmpstride + h_start,
439 (h_end - h_start) * sizeof(*data));
440 }
441 }
442}
443
444uint16_t hor_sym_filter_highbd(uint16_t *d, int *hfilter, int bd) {
445 int32_t s =
446 (1 << (RESTORATION_FILT_BITS - 1)) + d[0] * hfilter[RESTORATION_HALFWIN];
447 int i;
448 for (i = 1; i <= RESTORATION_HALFWIN; ++i)
449 s += (d[i] + d[-i]) * hfilter[RESTORATION_HALFWIN + i];
450 return clip_pixel_highbd(s >> RESTORATION_FILT_BITS, bd);
451}
452
453uint16_t ver_sym_filter_highbd(uint16_t *d, int stride, int *vfilter, int bd) {
454 int32_t s =
455 (1 << (RESTORATION_FILT_BITS - 1)) + d[0] * vfilter[RESTORATION_HALFWIN];
456 int i;
457 for (i = 1; i <= RESTORATION_HALFWIN; ++i)
458 s += (d[i * stride] + d[-i * stride]) * vfilter[RESTORATION_HALFWIN + i];
459 return clip_pixel_highbd(s >> RESTORATION_FILT_BITS, bd);
460}
461
462static void loop_wiener_filter_highbd(uint8_t *data8, int width, int height,
463 int stride, RestorationInternal *rst,
464 uint8_t *tmpdata8, int tmpstride,
465 int bit_depth) {
466 uint16_t *data = CONVERT_TO_SHORTPTR(data8);
467 uint16_t *tmpdata = CONVERT_TO_SHORTPTR(tmpdata8);
468 int i, j, tile_idx, htile_idx, vtile_idx;
469 int h_start, h_end, v_start, v_end;
470 int tile_width, tile_height;
471 uint16_t *data_p, *tmpdata_p;
472
473 tile_width = rst->tile_width >> rst->subsampling_x;
474 tile_height = rst->tile_height >> rst->subsampling_y;
475
476 // Initialize tmp buffer
477 data_p = data;
478 tmpdata_p = tmpdata;
479 for (i = 0; i < height; ++i) {
480 memcpy(tmpdata_p, data_p, sizeof(*data_p) * width);
481 data_p += stride;
482 tmpdata_p += tmpstride;
483 }
484
485 // Filter row-wise tile-by-tile
486 for (tile_idx = 0; tile_idx < rst->ntiles; ++tile_idx) {
487 if (rst->wiener_level[tile_idx] == 0) continue;
488 htile_idx = tile_idx % rst->nhtiles;
489 vtile_idx = tile_idx / rst->nhtiles;
490 h_start =
491 htile_idx * tile_width + ((htile_idx > 0) ? 0 : RESTORATION_HALFWIN);
492 h_end = (htile_idx < rst->nhtiles - 1) ? ((htile_idx + 1) * tile_width)
493 : (width - RESTORATION_HALFWIN);
494 v_start = vtile_idx * tile_height;
495 v_end = (vtile_idx < rst->nvtiles - 1) ? ((vtile_idx + 1) * tile_height)
496 : height;
497 data_p = data + h_start + v_start * stride;
498 tmpdata_p = tmpdata + h_start + v_start * tmpstride;
499 for (i = 0; i < (v_end - v_start); ++i) {
500 for (j = 0; j < (h_end - h_start); ++j) {
501 *tmpdata_p++ =
502 hor_sym_filter_highbd(data_p++, rst->hfilter[tile_idx], bit_depth);
503 }
504 data_p += stride - (h_end - h_start);
505 tmpdata_p += tmpstride - (h_end - h_start);
506 }
507 }
508
509 // Filter column-wise tile-by-tile (bands of thickness RESTORATION_HALFWIN
510 // at top and bottom of tiles allow filtering overlap, and are not optimally
511 // filtered)
512 for (tile_idx = 0; tile_idx < rst->ntiles; ++tile_idx) {
513 if (rst->wiener_level[tile_idx] == 0) continue;
514 htile_idx = tile_idx % rst->nhtiles;
515 vtile_idx = tile_idx / rst->nhtiles;
516 h_start = htile_idx * tile_width;
517 h_end =
518 (htile_idx < rst->nhtiles - 1) ? ((htile_idx + 1) * tile_width) : width;
519 v_start =
520 vtile_idx * tile_height + ((vtile_idx > 0) ? 0 : RESTORATION_HALFWIN);
521 v_end = (vtile_idx < rst->nvtiles - 1) ? ((vtile_idx + 1) * tile_height)
522 : (height - RESTORATION_HALFWIN);
523 data_p = data + h_start + v_start * stride;
524 tmpdata_p = tmpdata + h_start + v_start * tmpstride;
525 for (i = 0; i < (v_end - v_start); ++i) {
526 for (j = 0; j < (h_end - h_start); ++j) {
527 *data_p++ = ver_sym_filter_highbd(tmpdata_p++, tmpstride,
528 rst->vfilter[tile_idx], bit_depth);
529 }
530 data_p += stride - (h_end - h_start);
531 tmpdata_p += tmpstride - (h_end - h_start);
532 }
533 }
534}
Yaowu Xuf883b422016-08-30 14:01:10 -0700535#endif // CONFIG_AOM_HIGHBITDEPTH
Yaowu Xuc27fc142016-08-22 16:08:15 -0700536
Yaowu Xuf883b422016-08-30 14:01:10 -0700537void av1_loop_restoration_rows(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm,
538 int start_mi_row, int end_mi_row, int y_only) {
Yaowu Xuc27fc142016-08-22 16:08:15 -0700539 const int ywidth = frame->y_crop_width;
540 const int ystride = frame->y_stride;
541 const int uvwidth = frame->uv_crop_width;
542 const int uvstride = frame->uv_stride;
543 const int ystart = start_mi_row << MI_SIZE_LOG2;
544 const int uvstart = ystart >> cm->subsampling_y;
545 int yend = end_mi_row << MI_SIZE_LOG2;
546 int uvend = yend >> cm->subsampling_y;
547 restore_func_type restore_func =
548 cm->rst_internal.restoration_type == RESTORE_BILATERAL
549 ? loop_bilateral_filter
550 : loop_wiener_filter;
Yaowu Xuf883b422016-08-30 14:01:10 -0700551#if CONFIG_AOM_HIGHBITDEPTH
Yaowu Xuc27fc142016-08-22 16:08:15 -0700552 restore_func_highbd_type restore_func_highbd =
553 cm->rst_internal.restoration_type == RESTORE_BILATERAL
554 ? loop_bilateral_filter_highbd
555 : loop_wiener_filter_highbd;
Yaowu Xuf883b422016-08-30 14:01:10 -0700556#endif // CONFIG_AOM_HIGHBITDEPTH
Yaowu Xuc27fc142016-08-22 16:08:15 -0700557 YV12_BUFFER_CONFIG tmp_buf;
558 memset(&tmp_buf, 0, sizeof(YV12_BUFFER_CONFIG));
559
Yaowu Xuf883b422016-08-30 14:01:10 -0700560 yend = AOMMIN(yend, cm->height);
561 uvend = AOMMIN(uvend, cm->subsampling_y ? (cm->height + 1) >> 1 : cm->height);
Yaowu Xuc27fc142016-08-22 16:08:15 -0700562
Yaowu Xuf883b422016-08-30 14:01:10 -0700563 if (aom_realloc_frame_buffer(
Yaowu Xuc27fc142016-08-22 16:08:15 -0700564 &tmp_buf, cm->width, cm->height, cm->subsampling_x, cm->subsampling_y,
Yaowu Xuf883b422016-08-30 14:01:10 -0700565#if CONFIG_AOM_HIGHBITDEPTH
Yaowu Xuc27fc142016-08-22 16:08:15 -0700566 cm->use_highbitdepth,
567#endif
Yaowu Xuf883b422016-08-30 14:01:10 -0700568 AOM_DEC_BORDER_IN_PIXELS, cm->byte_alignment, NULL, NULL, NULL) < 0)
569 aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
Yaowu Xuc27fc142016-08-22 16:08:15 -0700570 "Failed to allocate tmp restoration buffer");
571
Yaowu Xuf883b422016-08-30 14:01:10 -0700572#if CONFIG_AOM_HIGHBITDEPTH
Yaowu Xuc27fc142016-08-22 16:08:15 -0700573 if (cm->use_highbitdepth)
574 restore_func_highbd(frame->y_buffer + ystart * ystride, ywidth,
575 yend - ystart, ystride, &cm->rst_internal,
576 tmp_buf.y_buffer + ystart * tmp_buf.y_stride,
577 tmp_buf.y_stride, cm->bit_depth);
578 else
Yaowu Xuf883b422016-08-30 14:01:10 -0700579#endif // CONFIG_AOM_HIGHBITDEPTH
Yaowu Xuc27fc142016-08-22 16:08:15 -0700580 restore_func(frame->y_buffer + ystart * ystride, ywidth, yend - ystart,
581 ystride, &cm->rst_internal,
582 tmp_buf.y_buffer + ystart * tmp_buf.y_stride,
583 tmp_buf.y_stride);
584 if (!y_only) {
585 cm->rst_internal.subsampling_x = cm->subsampling_x;
586 cm->rst_internal.subsampling_y = cm->subsampling_y;
Yaowu Xuf883b422016-08-30 14:01:10 -0700587#if CONFIG_AOM_HIGHBITDEPTH
Yaowu Xuc27fc142016-08-22 16:08:15 -0700588 if (cm->use_highbitdepth) {
589 restore_func_highbd(frame->u_buffer + uvstart * uvstride, uvwidth,
590 uvend - uvstart, uvstride, &cm->rst_internal,
591 tmp_buf.u_buffer + uvstart * tmp_buf.uv_stride,
592 tmp_buf.uv_stride, cm->bit_depth);
593 restore_func_highbd(frame->v_buffer + uvstart * uvstride, uvwidth,
594 uvend - uvstart, uvstride, &cm->rst_internal,
595 tmp_buf.v_buffer + uvstart * tmp_buf.uv_stride,
596 tmp_buf.uv_stride, cm->bit_depth);
597 } else {
Yaowu Xuf883b422016-08-30 14:01:10 -0700598#endif // CONFIG_AOM_HIGHBITDEPTH
Yaowu Xuc27fc142016-08-22 16:08:15 -0700599 restore_func(frame->u_buffer + uvstart * uvstride, uvwidth,
600 uvend - uvstart, uvstride, &cm->rst_internal,
601 tmp_buf.u_buffer + uvstart * tmp_buf.uv_stride,
602 tmp_buf.uv_stride);
603 restore_func(frame->v_buffer + uvstart * uvstride, uvwidth,
604 uvend - uvstart, uvstride, &cm->rst_internal,
605 tmp_buf.v_buffer + uvstart * tmp_buf.uv_stride,
606 tmp_buf.uv_stride);
Yaowu Xuf883b422016-08-30 14:01:10 -0700607#if CONFIG_AOM_HIGHBITDEPTH
Yaowu Xuc27fc142016-08-22 16:08:15 -0700608 }
Yaowu Xuf883b422016-08-30 14:01:10 -0700609#endif // CONFIG_AOM_HIGHBITDEPTH
Yaowu Xuc27fc142016-08-22 16:08:15 -0700610 }
Yaowu Xuf883b422016-08-30 14:01:10 -0700611 aom_free_frame_buffer(&tmp_buf);
Yaowu Xuc27fc142016-08-22 16:08:15 -0700612 if (cm->rst_internal.restoration_type == RESTORE_BILATERAL) {
613 free(cm->rst_internal.wr_lut);
614 cm->rst_internal.wr_lut = NULL;
615 free(cm->rst_internal.wx_lut);
616 cm->rst_internal.wx_lut = NULL;
617 }
618 if (cm->rst_internal.restoration_type == RESTORE_WIENER) {
619 free(cm->rst_internal.vfilter);
620 cm->rst_internal.vfilter = NULL;
621 free(cm->rst_internal.hfilter);
622 cm->rst_internal.hfilter = NULL;
623 }
624}
625
Yaowu Xuf883b422016-08-30 14:01:10 -0700626void av1_loop_restoration_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm,
627 RestorationInfo *rsi, int y_only,
628 int partial_frame) {
Yaowu Xuc27fc142016-08-22 16:08:15 -0700629 int start_mi_row, end_mi_row, mi_rows_to_filter;
630 if (rsi->restoration_type != RESTORE_NONE) {
631 start_mi_row = 0;
632 mi_rows_to_filter = cm->mi_rows;
633 if (partial_frame && cm->mi_rows > 8) {
634 start_mi_row = cm->mi_rows >> 1;
635 start_mi_row &= 0xfffffff8;
Yaowu Xuf883b422016-08-30 14:01:10 -0700636 mi_rows_to_filter = AOMMAX(cm->mi_rows / 8, 8);
Yaowu Xuc27fc142016-08-22 16:08:15 -0700637 }
638 end_mi_row = start_mi_row + mi_rows_to_filter;
Yaowu Xuf883b422016-08-30 14:01:10 -0700639 av1_loop_restoration_init(&cm->rst_internal, rsi,
640 cm->frame_type == KEY_FRAME, cm->width,
641 cm->height);
642 av1_loop_restoration_rows(frame, cm, start_mi_row, end_mi_row, y_only);
Yaowu Xuc27fc142016-08-22 16:08:15 -0700643 }
644}