pickrst.c 37.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
/*
 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <assert.h>
12
#include <float.h>
13
14
15
#include <limits.h>
#include <math.h>

Yaowu Xu's avatar
Yaowu Xu committed
16
#include "./aom_scale_rtcd.h"
17

18
#include "aom_dsp/psnr.h"
Yaowu Xu's avatar
Yaowu Xu committed
19
20
#include "aom_dsp/aom_dsp_common.h"
#include "aom_mem/aom_mem.h"
21
#include "aom_ports/mem.h"
22

23
24
#include "av1/common/onyxc_int.h"
#include "av1/common/quant_common.h"
25

26
27
28
29
#include "av1/encoder/encoder.h"
#include "av1/encoder/picklpf.h"
#include "av1/encoder/pickrst.h"
#include "av1/encoder/quantize.h"
30

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
const int frame_level_restore_bits[RESTORE_TYPES] = { 2, 2, 2, 2 };

static int64_t sse_restoration_tile(const YV12_BUFFER_CONFIG *src,
                                    AV1_COMMON *const cm, int h_start,
                                    int width, int v_start, int height) {
  int64_t filt_err;
#if CONFIG_AOM_HIGHBITDEPTH
  if (cm->use_highbitdepth) {
    filt_err = aom_highbd_get_y_sse_part(src, cm->frame_to_show, h_start, width,
                                         v_start, height);
  } else {
    filt_err = aom_get_y_sse_part(src, cm->frame_to_show, h_start, width,
                                  v_start, height);
  }
#else
  filt_err = aom_get_y_sse_part(src, cm->frame_to_show, h_start, width, v_start,
                                height);
#endif  // CONFIG_AOM_HIGHBITDEPTH
  return filt_err;
}

static int64_t try_restoration_tile(const YV12_BUFFER_CONFIG *src,
                                    AV1_COMP *const cpi, RestorationInfo *rsi,
                                    int partial_frame, int tile_idx,
                                    int subtile_idx, int subtile_bits) {
  AV1_COMMON *const cm = &cpi->common;
  int64_t filt_err;
  int tile_width, tile_height, nhtiles, nvtiles;
  int h_start, h_end, v_start, v_end;
  const int ntiles = av1_get_rest_ntiles(cm->width, cm->height, &tile_width,
                                         &tile_height, &nhtiles, &nvtiles);
  (void)ntiles;

  av1_loop_restoration_frame(cm->frame_to_show, cm, rsi, 1, partial_frame);
  av1_get_rest_tile_limits(tile_idx, subtile_idx, subtile_bits, nhtiles,
                           nvtiles, tile_width, tile_height, cm->width,
                           cm->height, 0, 0, &h_start, &h_end, &v_start,
                           &v_end);
  filt_err = sse_restoration_tile(src, cm, h_start, h_end - h_start, v_start,
                                  v_end - v_start);

  // Re-instate the unfiltered frame
  aom_yv12_copy_y(&cpi->last_frame_db, cm->frame_to_show);
  return filt_err;
}

static int64_t try_restoration_frame(const YV12_BUFFER_CONFIG *src,
Yaowu Xu's avatar
Yaowu Xu committed
78
                                     AV1_COMP *const cpi, RestorationInfo *rsi,
79
                                     int partial_frame) {
Yaowu Xu's avatar
Yaowu Xu committed
80
  AV1_COMMON *const cm = &cpi->common;
81
  int64_t filt_err;
Yaowu Xu's avatar
Yaowu Xu committed
82
83
  av1_loop_restoration_frame(cm->frame_to_show, cm, rsi, 1, partial_frame);
#if CONFIG_AOM_HIGHBITDEPTH
84
  if (cm->use_highbitdepth) {
85
    filt_err = aom_highbd_get_y_sse(src, cm->frame_to_show);
86
  } else {
87
    filt_err = aom_get_y_sse(src, cm->frame_to_show);
88
89
  }
#else
90
  filt_err = aom_get_y_sse(src, cm->frame_to_show);
Yaowu Xu's avatar
Yaowu Xu committed
91
#endif  // CONFIG_AOM_HIGHBITDEPTH
92
93

  // Re-instate the unfiltered frame
Yaowu Xu's avatar
Yaowu Xu committed
94
  aom_yv12_copy_y(&cpi->last_frame_db, cm->frame_to_show);
95
96
97
  return filt_err;
}

98
static int search_bilateral_level(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
99
                                  int filter_level, int partial_frame,
100
101
                                  int *bilateral_level, double *best_cost_ret,
                                  double *best_tile_cost) {
Yaowu Xu's avatar
Yaowu Xu committed
102
  AV1_COMMON *const cm = &cpi->common;
103
  int i, j, tile_idx;
104
  int64_t err;
105
  int bits;
106
107
  double cost, best_cost, cost_norestore, cost_bilateral,
      cost_norestore_subtile;
Yaowu Xu's avatar
Yaowu Xu committed
108
  const int bilateral_level_bits = av1_bilateral_level_bits(&cpi->common);
109
110
  const int bilateral_levels = 1 << bilateral_level_bits;
  MACROBLOCK *x = &cpi->td.mb;
111
  RestorationInfo rsi;
112
113
114
115
  int tile_width, tile_height, nhtiles, nvtiles;
  int h_start, h_end, v_start, v_end;
  const int ntiles = av1_get_rest_ntiles(cm->width, cm->height, &tile_width,
                                         &tile_height, &nhtiles, &nvtiles);
116
117

  //  Make a copy of the unfiltered / processed recon buffer
Yaowu Xu's avatar
Yaowu Xu committed
118
119
120
121
  aom_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_uf);
  av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filter_level,
                        1, partial_frame);
  aom_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_db);
122

123
  // RD cost associated with no restoration
124
125
126
127
128
129
  rsi.frame_restoration_type = RESTORE_NONE;
  err = try_restoration_frame(src, cpi, &rsi, partial_frame);
  // err = sse_restoration_tile(src, cm, 0, cm->width, 0, cm->height);
  bits = frame_level_restore_bits[rsi.frame_restoration_type]
         << AV1_PROB_COST_SHIFT;
  cost_norestore = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
130
131

  // RD cost associated with bilateral filtering
132
133
134
  rsi.frame_restoration_type = RESTORE_BILATERAL;
  rsi.bilateral_level = (int *)aom_malloc(sizeof(*rsi.bilateral_level) *
                                          ntiles * BILATERAL_SUBTILES);
135
136
  assert(rsi.bilateral_level != NULL);

137
  for (j = 0; j < ntiles * BILATERAL_SUBTILES; ++j) bilateral_level[j] = -1;
138

139
140
  // TODO(debargha): This is a pretty inefficient way to find the best
  // parameters per tile. Needs fixing.
141
142
  // Find best filter for each tile
  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
    int subtile_idx;
    for (subtile_idx = 0; subtile_idx < BILATERAL_SUBTILES; ++subtile_idx) {
      const int fulltile_idx = tile_idx * BILATERAL_SUBTILES + subtile_idx;
      av1_get_rest_tile_limits(tile_idx, subtile_idx, BILATERAL_SUBTILE_BITS,
                               nhtiles, nvtiles, tile_width, tile_height,
                               cm->width, cm->height, 0, 0, &h_start, &h_end,
                               &v_start, &v_end);
      err = sse_restoration_tile(src, cm, h_start, h_end - h_start, v_start,
                                 v_end - v_start);
#if BILATERAL_SUBTILES
      // #bits when a subtile is not restored
      bits = av1_cost_bit(RESTORE_NONE_BILATERAL_PROB, 0);
#else
      bits = 0;
#endif
      cost_norestore_subtile =
          RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
      best_cost = cost_norestore_subtile;
      for (j = 0; j < ntiles * BILATERAL_SUBTILES; ++j)
        rsi.bilateral_level[j] = -1;

      for (i = 0; i < bilateral_levels; ++i) {
        rsi.bilateral_level[fulltile_idx] = i;
        err = try_restoration_tile(src, cpi, &rsi, partial_frame, tile_idx,
                                   subtile_idx, BILATERAL_SUBTILE_BITS);
        bits = bilateral_level_bits << AV1_PROB_COST_SHIFT;
        bits += av1_cost_bit(RESTORE_NONE_BILATERAL_PROB, 1);
        cost = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
        if (cost < best_cost) {
          bilateral_level[fulltile_idx] = i;
          best_cost = cost;
        }
      }
    }
    if (best_tile_cost) {
      bits = 0;
      for (j = 0; j < ntiles * BILATERAL_SUBTILES; ++j)
        rsi.bilateral_level[j] = -1;
      for (subtile_idx = 0; subtile_idx < BILATERAL_SUBTILES; ++subtile_idx) {
        const int fulltile_idx = tile_idx * BILATERAL_SUBTILES + subtile_idx;
        rsi.bilateral_level[fulltile_idx] = bilateral_level[fulltile_idx];
        if (rsi.bilateral_level[fulltile_idx] >= 0)
          bits += bilateral_level_bits << AV1_PROB_COST_SHIFT;
#if BILATERAL_SUBTILES
        bits += av1_cost_bit(RESTORE_NONE_BILATERAL_PROB,
                             rsi.bilateral_level[fulltile_idx] >= 0);
#endif
190
      }
191
192
193
194
      err = try_restoration_tile(src, cpi, &rsi, partial_frame, tile_idx, 0, 0);
      best_tile_cost[tile_idx] = RDCOST_DBL(
          x->rdmult, x->rddiv,
          (bits + cpi->switchable_restore_cost[RESTORE_BILATERAL]) >> 4, err);
195
196
    }
  }
197
  // Find cost for combined configuration
198
199
200
  bits = frame_level_restore_bits[rsi.frame_restoration_type]
         << AV1_PROB_COST_SHIFT;
  for (j = 0; j < ntiles * BILATERAL_SUBTILES; ++j) {
201
202
    rsi.bilateral_level[j] = bilateral_level[j];
    if (rsi.bilateral_level[j] >= 0) {
203
      bits += bilateral_level_bits << AV1_PROB_COST_SHIFT;
204
    }
205
206
207
208
#if BILATERAL_SUBTILES
    bits +=
        av1_cost_bit(RESTORE_NONE_BILATERAL_PROB, rsi.bilateral_level[j] >= 0);
#endif
209
  }
210
211
  err = try_restoration_frame(src, cpi, &rsi, partial_frame);
  cost_bilateral = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
212

Yaowu Xu's avatar
Yaowu Xu committed
213
  aom_free(rsi.bilateral_level);
214

Yaowu Xu's avatar
Yaowu Xu committed
215
  aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
216
217
218
219
220
221
222
  if (cost_bilateral < cost_norestore) {
    if (best_cost_ret) *best_cost_ret = cost_bilateral;
    return 1;
  } else {
    if (best_cost_ret) *best_cost_ret = cost_norestore;
    return 0;
  }
223
224
}

225
static int search_filter_bilateral_level(const YV12_BUFFER_CONFIG *src,
Yaowu Xu's avatar
Yaowu Xu committed
226
                                         AV1_COMP *cpi, int partial_frame,
227
                                         int *filter_best, int *bilateral_level,
228
229
                                         double *best_cost_ret,
                                         double *best_tile_cost) {
Yaowu Xu's avatar
Yaowu Xu committed
230
  const AV1_COMMON *const cm = &cpi->common;
231
232
  const struct loopfilter *const lf = &cm->lf;
  const int min_filter_level = 0;
Yaowu Xu's avatar
Yaowu Xu committed
233
  const int max_filter_level = av1_get_max_filter_level(cpi);
234
  int filt_direction = 0;
235
  int filt_best;
236
  double best_err;
237
238
239
240
241
  int i, j;
  int *tmp_level;
  int bilateral_success[MAX_LOOP_FILTER + 1];

  const int ntiles =
242
243
      av1_get_rest_ntiles(cm->width, cm->height, NULL, NULL, NULL, NULL);
  double *tile_cost = (double *)aom_malloc(sizeof(*tile_cost) * ntiles);
244
245
246
247
248
249
250

  // Start the search at the previous frame filter level unless it is now out of
  // range.
  int filt_mid = clamp(lf->filter_level, min_filter_level, max_filter_level);
  int filter_step = filt_mid < 16 ? 4 : filt_mid / 4;
  double ss_err[MAX_LOOP_FILTER + 1];
  // Set each entry to -1
251
  for (i = 0; i <= MAX_LOOP_FILTER; ++i) ss_err[i] = -1.0;
252

253
254
  tmp_level =
      (int *)aom_malloc(sizeof(*tmp_level) * ntiles * BILATERAL_SUBTILES);
255
256

  bilateral_success[filt_mid] = search_bilateral_level(
257
      src, cpi, filt_mid, partial_frame, tmp_level, &best_err, best_tile_cost);
258
259
  filt_best = filt_mid;
  ss_err[filt_mid] = best_err;
260
  for (j = 0; j < ntiles * BILATERAL_SUBTILES; ++j) {
261
262
    bilateral_level[j] = tmp_level[j];
  }
263
264

  while (filter_step > 0) {
Yaowu Xu's avatar
Yaowu Xu committed
265
266
    const int filt_high = AOMMIN(filt_mid + filter_step, max_filter_level);
    const int filt_low = AOMMAX(filt_mid - filter_step, min_filter_level);
267
268
269
270
271
272
273
274

    // Bias against raising loop filter in favor of lowering it.
    double bias = (best_err / (1 << (15 - (filt_mid / 8)))) * filter_step;

    if ((cpi->oxcf.pass == 2) && (cpi->twopass.section_intra_rating < 20))
      bias = (bias * cpi->twopass.section_intra_rating) / 20;

    // yx, bias less for large block size
275
    if (cm->tx_mode != ONLY_4X4) bias /= 2;
276
277
278
279

    if (filt_direction <= 0 && filt_low != filt_mid) {
      // Get Low filter error score
      if (ss_err[filt_low] < 0) {
280
281
282
        bilateral_success[filt_low] =
            search_bilateral_level(src, cpi, filt_low, partial_frame, tmp_level,
                                   &ss_err[filt_low], tile_cost);
283
284
285
      }
      // If value is close to the best so far then bias towards a lower loop
      // filter value.
286
      if (ss_err[filt_low] < (best_err + bias)) {
287
288
289
290
291
        // Was it actually better than the previous best?
        if (ss_err[filt_low] < best_err) {
          best_err = ss_err[filt_low];
        }
        filt_best = filt_low;
292
        for (j = 0; j < ntiles * BILATERAL_SUBTILES; ++j) {
293
294
          bilateral_level[j] = tmp_level[j];
        }
295
        memcpy(best_tile_cost, tile_cost, sizeof(*tile_cost) * ntiles);
296
297
298
299
300
301
      }
    }

    // Now look at filt_high
    if (filt_direction >= 0 && filt_high != filt_mid) {
      if (ss_err[filt_high] < 0) {
302
303
304
        bilateral_success[filt_high] =
            search_bilateral_level(src, cpi, filt_high, partial_frame,
                                   tmp_level, &ss_err[filt_high], tile_cost);
305
      }
306
307
      // If value is significantly better than previous best, bias added against
      // raising filter value
308
309
310
      if (ss_err[filt_high] < (best_err - bias)) {
        best_err = ss_err[filt_high];
        filt_best = filt_high;
311
        for (j = 0; j < ntiles * BILATERAL_SUBTILES; ++j) {
312
313
          bilateral_level[j] = tmp_level[j];
        }
314
        memcpy(best_tile_cost, tile_cost, sizeof(*tile_cost) * ntiles);
315
316
317
318
319
320
321
322
323
324
325
326
      }
    }

    // Half the step distance if the best filter value was the same as last time
    if (filt_best == filt_mid) {
      filter_step /= 2;
      filt_direction = 0;
    } else {
      filt_direction = (filt_best < filt_mid) ? -1 : 1;
      filt_mid = filt_best;
    }
  }
Yaowu Xu's avatar
Yaowu Xu committed
327
  aom_free(tmp_level);
328
  aom_free(tile_cost);
329

330
331
  // Update best error
  best_err = ss_err[filt_best];
332
  if (best_cost_ret) *best_cost_ret = best_err;
333
334
335
  if (filter_best) *filter_best = filt_best;

  return bilateral_success[filt_best];
336
337
}

338
339
static double find_average(uint8_t *src, int h_start, int h_end, int v_start,
                           int v_end, int stride) {
340
341
342
  uint64_t sum = 0;
  double avg = 0;
  int i, j;
343
344
345
  for (i = v_start; i < v_end; i++)
    for (j = h_start; j < h_end; j++) sum += src[i * stride + j];
  avg = (double)sum / ((v_end - v_start) * (h_end - h_start));
346
347
348
  return avg;
}

349
350
351
static void compute_stats(uint8_t *dgd, uint8_t *src, int h_start, int h_end,
                          int v_start, int v_end, int dgd_stride,
                          int src_stride, double *M, double *H) {
352
353
  int i, j, k, l;
  double Y[RESTORATION_WIN2];
354
355
  const double avg =
      find_average(dgd, h_start, h_end, v_start, v_end, dgd_stride);
356
357
358

  memset(M, 0, sizeof(*M) * RESTORATION_WIN2);
  memset(H, 0, sizeof(*H) * RESTORATION_WIN2 * RESTORATION_WIN2);
359
360
  for (i = v_start; i < v_end; i++) {
    for (j = h_start; j < h_end; j++) {
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
      const double X = (double)src[i * src_stride + j] - avg;
      int idx = 0;
      for (k = -RESTORATION_HALFWIN; k <= RESTORATION_HALFWIN; k++) {
        for (l = -RESTORATION_HALFWIN; l <= RESTORATION_HALFWIN; l++) {
          Y[idx] = (double)dgd[(i + l) * dgd_stride + (j + k)] - avg;
          idx++;
        }
      }
      for (k = 0; k < RESTORATION_WIN2; ++k) {
        M[k] += Y[k] * X;
        H[k * RESTORATION_WIN2 + k] += Y[k] * Y[k];
        for (l = k + 1; l < RESTORATION_WIN2; ++l) {
          double value = Y[k] * Y[l];
          H[k * RESTORATION_WIN2 + l] += value;
          H[l * RESTORATION_WIN2 + k] += value;
        }
      }
    }
  }
}

Yaowu Xu's avatar
Yaowu Xu committed
382
#if CONFIG_AOM_HIGHBITDEPTH
383
384
static double find_average_highbd(uint16_t *src, int h_start, int h_end,
                                  int v_start, int v_end, int stride) {
385
386
387
  uint64_t sum = 0;
  double avg = 0;
  int i, j;
388
389
390
  for (i = v_start; i < v_end; i++)
    for (j = h_start; j < h_end; j++) sum += src[i * stride + j];
  avg = (double)sum / ((v_end - v_start) * (h_end - h_start));
391
392
393
  return avg;
}

394
395
396
397
static void compute_stats_highbd(uint8_t *dgd8, uint8_t *src8, int h_start,
                                 int h_end, int v_start, int v_end,
                                 int dgd_stride, int src_stride, double *M,
                                 double *H) {
398
399
400
401
  int i, j, k, l;
  double Y[RESTORATION_WIN2];
  uint16_t *src = CONVERT_TO_SHORTPTR(src8);
  uint16_t *dgd = CONVERT_TO_SHORTPTR(dgd8);
402
403
  const double avg =
      find_average_highbd(dgd, h_start, h_end, v_start, v_end, dgd_stride);
404
405
406

  memset(M, 0, sizeof(*M) * RESTORATION_WIN2);
  memset(H, 0, sizeof(*H) * RESTORATION_WIN2 * RESTORATION_WIN2);
407
408
  for (i = v_start; i < v_end; i++) {
    for (j = h_start; j < h_end; j++) {
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
      const double X = (double)src[i * src_stride + j] - avg;
      int idx = 0;
      for (k = -RESTORATION_HALFWIN; k <= RESTORATION_HALFWIN; k++) {
        for (l = -RESTORATION_HALFWIN; l <= RESTORATION_HALFWIN; l++) {
          Y[idx] = (double)dgd[(i + l) * dgd_stride + (j + k)] - avg;
          idx++;
        }
      }
      for (k = 0; k < RESTORATION_WIN2; ++k) {
        M[k] += Y[k] * X;
        H[k * RESTORATION_WIN2 + k] += Y[k] * Y[k];
        for (l = k + 1; l < RESTORATION_WIN2; ++l) {
          double value = Y[k] * Y[l];
          H[k * RESTORATION_WIN2 + l] += value;
          H[l * RESTORATION_WIN2 + k] += value;
        }
      }
    }
  }
}
Yaowu Xu's avatar
Yaowu Xu committed
429
#endif  // CONFIG_AOM_HIGHBITDEPTH
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451

// Solves Ax = b, where x and b are column vectors
static int linsolve(int n, double *A, int stride, double *b, double *x) {
  int i, j, k;
  double c;
  // Partial pivoting
  for (i = n - 1; i > 0; i--) {
    if (A[(i - 1) * stride] < A[i * stride]) {
      for (j = 0; j < n; j++) {
        c = A[i * stride + j];
        A[i * stride + j] = A[(i - 1) * stride + j];
        A[(i - 1) * stride + j] = c;
      }
      c = b[i];
      b[i] = b[i - 1];
      b[i - 1] = c;
    }
  }
  // Forward elimination
  for (k = 0; k < n - 1; k++) {
    for (i = k; i < n - 1; i++) {
      c = A[(i + 1) * stride + k] / A[k * stride + k];
452
      for (j = 0; j < n; j++) A[(i + 1) * stride + j] -= c * A[k * stride + j];
453
454
455
456
457
      b[i + 1] -= c * b[k];
    }
  }
  // Backward substitution
  for (i = n - 1; i >= 0; i--) {
458
    if (fabs(A[i * stride + i]) < 1e-10) return 0;
459
    c = 0;
460
    for (j = i + 1; j <= n - 1; j++) c += A[i * stride + j] * x[j];
461
462
463
464
465
466
467
468
469
470
471
472
473
474
    x[i] = (b[i] - c) / A[i * stride + i];
  }
  return 1;
}

static INLINE int wrap_index(int i) {
  return (i >= RESTORATION_HALFWIN1 ? RESTORATION_WIN - 1 - i : i);
}

// Fix vector b, update vector a
static void update_a_sep_sym(double **Mc, double **Hc, double *a, double *b) {
  int i, j;
  double S[RESTORATION_WIN];
  double A[RESTORATION_WIN], B[RESTORATION_WIN2];
Aamir Anis's avatar
Aamir Anis committed
475
  int w, w2;
476
477
  memset(A, 0, sizeof(A));
  memset(B, 0, sizeof(B));
478
  for (i = 0; i < RESTORATION_WIN; i++) {
479
480
481
482
483
484
    int j;
    for (j = 0; j < RESTORATION_WIN; ++j) {
      const int jj = wrap_index(j);
      A[jj] += Mc[i][j] * b[i];
    }
  }
485
486
  for (i = 0; i < RESTORATION_WIN; i++) {
    for (j = 0; j < RESTORATION_WIN; j++) {
487
488
489
490
491
492
      int k, l;
      for (k = 0; k < RESTORATION_WIN; ++k)
        for (l = 0; l < RESTORATION_WIN; ++l) {
          const int kk = wrap_index(k);
          const int ll = wrap_index(l);
          B[ll * RESTORATION_HALFWIN1 + kk] +=
493
494
              Hc[j * RESTORATION_WIN + i][k * RESTORATION_WIN2 + l] * b[i] *
              b[j];
495
496
497
        }
    }
  }
Aamir Anis's avatar
Aamir Anis committed
498
499
500
501
  // Normalization enforcement in the system of equations itself
  w = RESTORATION_WIN;
  w2 = (w >> 1) + 1;
  for (i = 0; i < w2 - 1; ++i)
502
503
    A[i] -=
        A[w2 - 1] * 2 + B[i * w2 + w2 - 1] - 2 * B[(w2 - 1) * w2 + (w2 - 1)];
Aamir Anis's avatar
Aamir Anis committed
504
505
506
507
508
509
510
511
512
  for (i = 0; i < w2 - 1; ++i)
    for (j = 0; j < w2 - 1; ++j)
      B[i * w2 + j] -= 2 * (B[i * w2 + (w2 - 1)] + B[(w2 - 1) * w2 + j] -
                            2 * B[(w2 - 1) * w2 + (w2 - 1)]);
  if (linsolve(w2 - 1, B, w2, A, S)) {
    S[w2 - 1] = 1.0;
    for (i = w2; i < w; ++i) {
      S[i] = S[w - 1 - i];
      S[w2 - 1] -= 2 * S[i];
513
    }
Aamir Anis's avatar
Aamir Anis committed
514
    memcpy(a, S, w * sizeof(*a));
515
516
517
518
519
520
521
522
  }
}

// Fix vector a, update vector b
static void update_b_sep_sym(double **Mc, double **Hc, double *a, double *b) {
  int i, j;
  double S[RESTORATION_WIN];
  double A[RESTORATION_WIN], B[RESTORATION_WIN2];
Aamir Anis's avatar
Aamir Anis committed
523
  int w, w2;
524
525
  memset(A, 0, sizeof(A));
  memset(B, 0, sizeof(B));
526
  for (i = 0; i < RESTORATION_WIN; i++) {
527
528
    int j;
    const int ii = wrap_index(i);
529
    for (j = 0; j < RESTORATION_WIN; j++) A[ii] += Mc[i][j] * a[j];
530
531
532
533
534
535
536
537
538
539
  }

  for (i = 0; i < RESTORATION_WIN; i++) {
    for (j = 0; j < RESTORATION_WIN; j++) {
      const int ii = wrap_index(i);
      const int jj = wrap_index(j);
      int k, l;
      for (k = 0; k < RESTORATION_WIN; ++k)
        for (l = 0; l < RESTORATION_WIN; ++l)
          B[jj * RESTORATION_HALFWIN1 + ii] +=
540
541
              Hc[i * RESTORATION_WIN + j][k * RESTORATION_WIN2 + l] * a[k] *
              a[l];
542
543
    }
  }
Aamir Anis's avatar
Aamir Anis committed
544
545
546
547
  // Normalization enforcement in the system of equations itself
  w = RESTORATION_WIN;
  w2 = RESTORATION_HALFWIN1;
  for (i = 0; i < w2 - 1; ++i)
548
549
    A[i] -=
        A[w2 - 1] * 2 + B[i * w2 + w2 - 1] - 2 * B[(w2 - 1) * w2 + (w2 - 1)];
Aamir Anis's avatar
Aamir Anis committed
550
551
552
553
554
555
556
557
558
  for (i = 0; i < w2 - 1; ++i)
    for (j = 0; j < w2 - 1; ++j)
      B[i * w2 + j] -= 2 * (B[i * w2 + (w2 - 1)] + B[(w2 - 1) * w2 + j] -
                            2 * B[(w2 - 1) * w2 + (w2 - 1)]);
  if (linsolve(w2 - 1, B, w2, A, S)) {
    S[w2 - 1] = 1.0;
    for (i = w2; i < w; ++i) {
      S[i] = S[w - 1 - i];
      S[w2 - 1] -= 2 * S[i];
559
    }
Aamir Anis's avatar
Aamir Anis committed
560
    memcpy(b, S, w * sizeof(*b));
561
562
563
  }
}

564
565
static int wiener_decompose_sep_sym(double *M, double *H, double *a,
                                    double *b) {
566
  static const double init_filt[RESTORATION_WIN] = {
567
    0.035623, -0.127154, 0.211436, 0.760190, 0.211436, -0.127154, 0.035623,
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
  };
  int i, j, iter;
  double *Hc[RESTORATION_WIN2];
  double *Mc[RESTORATION_WIN];
  for (i = 0; i < RESTORATION_WIN; i++) {
    Mc[i] = M + i * RESTORATION_WIN;
    for (j = 0; j < RESTORATION_WIN; j++) {
      Hc[i * RESTORATION_WIN + j] =
          H + i * RESTORATION_WIN * RESTORATION_WIN2 + j * RESTORATION_WIN;
    }
  }
  memcpy(a, init_filt, sizeof(*a) * RESTORATION_WIN);
  memcpy(b, init_filt, sizeof(*b) * RESTORATION_WIN);

  iter = 1;
  while (iter < 10) {
    update_a_sep_sym(Mc, Hc, a, b);
    update_b_sep_sym(Mc, Hc, a, b);
    iter++;
  }
588
  return 1;
589
590
}

Aamir Anis's avatar
Aamir Anis committed
591
592
593
// Computes the function x'*A*x - x'*b for the learned filters, and compares
// against identity filters; Final score is defined as the difference between
// the function values
594
static double compute_score(double *M, double *H, int *vfilt, int *hfilt) {
Aamir Anis's avatar
Aamir Anis committed
595
596
597
598
599
600
601
602
603
604
  double ab[RESTORATION_WIN * RESTORATION_WIN];
  int i, k, l;
  double P = 0, Q = 0;
  double iP = 0, iQ = 0;
  double Score, iScore;
  int w;
  double a[RESTORATION_WIN], b[RESTORATION_WIN];
  w = RESTORATION_WIN;
  a[RESTORATION_HALFWIN] = b[RESTORATION_HALFWIN] = 1.0;
  for (i = 0; i < RESTORATION_HALFWIN; ++i) {
605
606
607
608
    a[i] = a[RESTORATION_WIN - i - 1] =
        (double)vfilt[i] / RESTORATION_FILT_STEP;
    b[i] = b[RESTORATION_WIN - i - 1] =
        (double)hfilt[i] / RESTORATION_FILT_STEP;
Aamir Anis's avatar
Aamir Anis committed
609
610
611
612
613
614
615
616
617
618
    a[RESTORATION_HALFWIN] -= 2 * a[i];
    b[RESTORATION_HALFWIN] -= 2 * b[i];
  }
  for (k = 0; k < w; ++k) {
    for (l = 0; l < w; ++l) {
      ab[k * w + l] = a[l] * b[k];
    }
  }
  for (k = 0; k < w * w; ++k) {
    P += ab[k] * M[k];
619
    for (l = 0; l < w * w; ++l) Q += ab[k] * H[k * w * w + l] * ab[l];
Aamir Anis's avatar
Aamir Anis committed
620
621
622
623
624
625
626
627
628
629
  }
  Score = Q - 2 * P;

  iP = M[(w * w) >> 1];
  iQ = H[((w * w) >> 1) * w * w + ((w * w) >> 1)];
  iScore = iQ - 2 * iP;

  return Score - iScore;
}

630
#define CLIP(x, lo, hi) ((x) < (lo) ? (lo) : (x) > (hi) ? (hi) : (x))
631
#define RINT(x) ((x) < 0 ? (int)((x)-0.5) : (int)((x) + 0.5))
632
633
634
635
636
637
638
639
640
641
642
643

static void quantize_sym_filter(double *f, int *fi) {
  int i;
  for (i = 0; i < RESTORATION_HALFWIN; ++i) {
    fi[i] = RINT(f[i] * RESTORATION_FILT_STEP);
  }
  // Specialize for 7-tap filter
  fi[0] = CLIP(fi[0], WIENER_FILT_TAP0_MINV, WIENER_FILT_TAP0_MAXV);
  fi[1] = CLIP(fi[1], WIENER_FILT_TAP1_MINV, WIENER_FILT_TAP1_MAXV);
  fi[2] = CLIP(fi[2], WIENER_FILT_TAP2_MINV, WIENER_FILT_TAP2_MAXV);
}

Yaowu Xu's avatar
Yaowu Xu committed
644
static int search_wiener_filter(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
645
                                int filter_level, int partial_frame,
646
647
648
649
                                int (*vfilter)[RESTORATION_WIN],
                                int (*hfilter)[RESTORATION_WIN],
                                int *wiener_level, double *best_cost_ret,
                                double *best_tile_cost) {
Yaowu Xu's avatar
Yaowu Xu committed
650
  AV1_COMMON *const cm = &cpi->common;
651
  RestorationInfo rsi;
652
653
  int64_t err;
  int bits;
654
  double cost_wiener, cost_norestore, cost_norestore_tile;
655
656
657
658
659
660
661
662
663
  MACROBLOCK *x = &cpi->td.mb;
  double M[RESTORATION_WIN2];
  double H[RESTORATION_WIN2 * RESTORATION_WIN2];
  double vfilterd[RESTORATION_WIN], hfilterd[RESTORATION_WIN];
  const YV12_BUFFER_CONFIG *dgd = cm->frame_to_show;
  const int width = cm->width;
  const int height = cm->height;
  const int src_stride = src->y_stride;
  const int dgd_stride = dgd->y_stride;
Aamir Anis's avatar
Aamir Anis committed
664
  double score;
665
  int tile_idx, tile_width, tile_height, nhtiles, nvtiles;
666
667
668
  int h_start, h_end, v_start, v_end;
  int i, j;

669
670
  const int ntiles = av1_get_rest_ntiles(width, height, &tile_width,
                                         &tile_height, &nhtiles, &nvtiles);
671
672
673
674
675
676
  assert(width == dgd->y_crop_width);
  assert(height == dgd->y_crop_height);
  assert(width == src->y_crop_width);
  assert(height == src->y_crop_height);

  //  Make a copy of the unfiltered / processed recon buffer
Yaowu Xu's avatar
Yaowu Xu committed
677
678
679
680
  aom_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_uf);
  av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filter_level,
                        1, partial_frame);
  aom_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_db);
681

682
683
684
685
686
  rsi.frame_restoration_type = RESTORE_NONE;
  err = sse_restoration_tile(src, cm, 0, cm->width, 0, cm->height);
  bits = frame_level_restore_bits[rsi.frame_restoration_type]
         << AV1_PROB_COST_SHIFT;
  cost_norestore = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
687

688
  rsi.frame_restoration_type = RESTORE_WIENER;
689
  rsi.vfilter =
690
      (int(*)[RESTORATION_WIN])aom_malloc(sizeof(*rsi.vfilter) * ntiles);
691
692
  assert(rsi.vfilter != NULL);
  rsi.hfilter =
693
      (int(*)[RESTORATION_WIN])aom_malloc(sizeof(*rsi.hfilter) * ntiles);
694
  assert(rsi.hfilter != NULL);
Yaowu Xu's avatar
Yaowu Xu committed
695
  rsi.wiener_level = (int *)aom_malloc(sizeof(*rsi.wiener_level) * ntiles);
696
697
698
699
  assert(rsi.wiener_level != NULL);

  // Compute best Wiener filters for each tile
  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
700
701
702
703
704
705
706
707
708
709
710
711
712
713
    wiener_level[tile_idx] = 0;
    av1_get_rest_tile_limits(tile_idx, 0, 0, nhtiles, nvtiles, tile_width,
                             tile_height, width, height, 0, 0, &h_start, &h_end,
                             &v_start, &v_end);
    err = sse_restoration_tile(src, cm, h_start, h_end - h_start, v_start,
                               v_end - v_start);
    // #bits when a tile is not restored
    bits = av1_cost_bit(RESTORE_NONE_WIENER_PROB, 0);
    cost_norestore_tile = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
    if (best_tile_cost) best_tile_cost[tile_idx] = cost_norestore_tile;

    av1_get_rest_tile_limits(tile_idx, 0, 0, nhtiles, nvtiles, tile_width,
                             tile_height, width, height, 1, 1, &h_start, &h_end,
                             &v_start, &v_end);
Yaowu Xu's avatar
Yaowu Xu committed
714
#if CONFIG_AOM_HIGHBITDEPTH
715
716
717
718
    if (cm->use_highbitdepth)
      compute_stats_highbd(dgd->y_buffer, src->y_buffer, h_start, h_end,
                           v_start, v_end, dgd_stride, src_stride, M, H);
    else
Yaowu Xu's avatar
Yaowu Xu committed
719
#endif  // CONFIG_AOM_HIGHBITDEPTH
720
721
722
723
724
725
      compute_stats(dgd->y_buffer, src->y_buffer, h_start, h_end, v_start,
                    v_end, dgd_stride, src_stride, M, H);

    if (!wiener_decompose_sep_sym(M, H, vfilterd, hfilterd)) {
      for (i = 0; i < RESTORATION_HALFWIN; ++i)
        rsi.vfilter[tile_idx][i] = rsi.hfilter[tile_idx][i] = 0;
726
      wiener_level[tile_idx] = 0;
727
728
729
730
      continue;
    }
    quantize_sym_filter(vfilterd, rsi.vfilter[tile_idx]);
    quantize_sym_filter(hfilterd, rsi.hfilter[tile_idx]);
731
    wiener_level[tile_idx] = 1;
732
733
734
735
736
737
738
739

    // Filter score computes the value of the function x'*A*x - x'*b for the
    // learned filter and compares it against identity filer. If there is no
    // reduction in the function, the filter is reverted back to identity
    score = compute_score(M, H, rsi.vfilter[tile_idx], rsi.hfilter[tile_idx]);
    if (score > 0.0) {
      for (i = 0; i < RESTORATION_HALFWIN; ++i)
        rsi.vfilter[tile_idx][i] = rsi.hfilter[tile_idx][i] = 0;
740
      wiener_level[tile_idx] = 0;
741
742
      continue;
    }
743

744
745
746
    for (j = 0; j < ntiles; ++j) rsi.wiener_level[j] = 0;
    rsi.wiener_level[tile_idx] = 1;

747
748
749
750
751
752
753
754
755
756
757
    err = try_restoration_tile(src, cpi, &rsi, partial_frame, tile_idx, 0, 0);
    bits = WIENER_FILT_BITS << AV1_PROB_COST_SHIFT;
    bits += av1_cost_bit(RESTORE_NONE_WIENER_PROB, 1);
    cost_wiener = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
    if (cost_wiener >= cost_norestore_tile) wiener_level[tile_idx] = 0;
    if (best_tile_cost) {
      bits = WIENER_FILT_BITS << AV1_PROB_COST_SHIFT;
      best_tile_cost[tile_idx] = RDCOST_DBL(
          x->rdmult, x->rddiv,
          (bits + cpi->switchable_restore_cost[RESTORE_WIENER]) >> 4, err);
    }
758
  }
759
  // Cost for Wiener filtering
760
761
  bits = frame_level_restore_bits[rsi.frame_restoration_type]
         << AV1_PROB_COST_SHIFT;
762
  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
763
764
765
766
    bits += av1_cost_bit(RESTORE_NONE_WIENER_PROB, wiener_level[tile_idx]);
    if (wiener_level[tile_idx])
      bits += (WIENER_FILT_BITS << AV1_PROB_COST_SHIFT);
    rsi.wiener_level[tile_idx] = wiener_level[tile_idx];
Aamir Anis's avatar
Aamir Anis committed
767
  }
768
769
  // TODO(debargha): This is a pretty inefficient way to find the error
  // for the whole frame. Specialize for a specific tile.
770
  err = try_restoration_frame(src, cpi, &rsi, partial_frame);
771
  cost_wiener = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
772

773
  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
774
    if (wiener_level[tile_idx] == 0) continue;
775
776
777
778
779
780
    for (i = 0; i < RESTORATION_HALFWIN; ++i) {
      vfilter[tile_idx][i] = rsi.vfilter[tile_idx][i];
      hfilter[tile_idx][i] = rsi.hfilter[tile_idx][i];
    }
  }

Yaowu Xu's avatar
Yaowu Xu committed
781
782
783
  aom_free(rsi.vfilter);
  aom_free(rsi.hfilter);
  aom_free(rsi.wiener_level);
784

Yaowu Xu's avatar
Yaowu Xu committed
785
  aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
786
787
788
789
790
791
792
793
794
  if (cost_wiener < cost_norestore) {
    if (best_cost_ret) *best_cost_ret = cost_wiener;
    return 1;
  } else {
    if (best_cost_ret) *best_cost_ret = cost_norestore;
    return 0;
  }
}

795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
static int search_switchable_restoration(
    const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi, int filter_level,
    int partial_frame, RestorationInfo *rsi, double *tile_cost_bilateral,
    double *tile_cost_wiener, double *best_cost_ret) {
  AV1_COMMON *const cm = &cpi->common;
  const int bilateral_level_bits = av1_bilateral_level_bits(&cpi->common);
  MACROBLOCK *x = &cpi->td.mb;
  double err, cost_norestore, cost_norestore_tile, cost_switchable;
  int bits, tile_idx;
  int tile_width, tile_height, nhtiles, nvtiles;
  int h_start, h_end, v_start, v_end;
  const int ntiles = av1_get_rest_ntiles(cm->width, cm->height, &tile_width,
                                         &tile_height, &nhtiles, &nvtiles);

  //  Make a copy of the unfiltered / processed recon buffer
  aom_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_uf);
  av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filter_level,
                        1, partial_frame);
  aom_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_db);

  // RD cost associated with no restoration
  rsi->frame_restoration_type = RESTORE_NONE;
  err = sse_restoration_tile(src, cm, 0, cm->width, 0, cm->height);
  bits = frame_level_restore_bits[rsi->frame_restoration_type]
         << AV1_PROB_COST_SHIFT;
  cost_norestore = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);

  rsi->frame_restoration_type = RESTORE_SWITCHABLE;
  bits = frame_level_restore_bits[rsi->frame_restoration_type]
         << AV1_PROB_COST_SHIFT;
  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
    av1_get_rest_tile_limits(tile_idx, 0, 0, nhtiles, nvtiles, tile_width,
                             tile_height, cm->width, cm->height, 0, 0, &h_start,
                             &h_end, &v_start, &v_end);
    err = sse_restoration_tile(src, cm, h_start, h_end - h_start, v_start,
                               v_end - v_start);
    cost_norestore_tile =
        RDCOST_DBL(x->rdmult, x->rddiv,
                   (cpi->switchable_restore_cost[RESTORE_NONE] >> 4), err);
    if (tile_cost_wiener[tile_idx] > cost_norestore_tile &&
        tile_cost_bilateral[tile_idx] > cost_norestore_tile) {
      rsi->restoration_type[tile_idx] = RESTORE_NONE;
    } else {
      rsi->restoration_type[tile_idx] =
          tile_cost_wiener[tile_idx] < tile_cost_bilateral[tile_idx]
              ? RESTORE_WIENER
              : RESTORE_BILATERAL;
      if (rsi->restoration_type[tile_idx] == RESTORE_WIENER) {
        if (rsi->wiener_level[tile_idx]) {
          bits += (WIENER_FILT_BITS << AV1_PROB_COST_SHIFT);
        } else {
          rsi->restoration_type[tile_idx] = RESTORE_NONE;
        }
      } else {
        int s;
        for (s = 0; s < BILATERAL_SUBTILES; ++s) {
#if BILATERAL_SUBTILES
          bits += av1_cost_bit(
              RESTORE_NONE_BILATERAL_PROB,
              rsi->bilateral_level[tile_idx * BILATERAL_SUBTILES + s] >= 0);
#endif
          if (rsi->bilateral_level[tile_idx * BILATERAL_SUBTILES + s] >= 0)
            bits += bilateral_level_bits << AV1_PROB_COST_SHIFT;
        }
      }
    }
    bits += cpi->switchable_restore_cost[rsi->restoration_type[tile_idx]];
  }
  err = try_restoration_frame(src, cpi, rsi, partial_frame);
  cost_switchable = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
  aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
  if (cost_switchable < cost_norestore) {
    *best_cost_ret = cost_switchable;
    return 1;
  } else {
    *best_cost_ret = cost_norestore;
    return 0;
  }
}

void av1_pick_filter_restoration(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
Yaowu Xu's avatar
Yaowu Xu committed
876
877
                                 LPF_PICK_METHOD method) {
  AV1_COMMON *const cm = &cpi->common;
878
  struct loopfilter *const lf = &cm->lf;
879
  int wiener_success = 0;
880
  int bilateral_success = 0;
881
  int switchable_success = 0;
882
883
  double cost_bilateral = DBL_MAX;
  double cost_wiener = DBL_MAX;
884
885
886
887
888
889
890
891
892
893
894
  // double cost_norestore = DBL_MAX;
  double cost_switchable = DBL_MAX;
  double *tile_cost_bilateral, *tile_cost_wiener;
  const int ntiles =
      av1_get_rest_ntiles(cm->width, cm->height, NULL, NULL, NULL, NULL);
  cm->rst_info.restoration_type = (RestorationType *)aom_realloc(
      cm->rst_info.restoration_type,
      sizeof(*cm->rst_info.restoration_type) * ntiles);
  cm->rst_info.bilateral_level = (int *)aom_realloc(
      cm->rst_info.bilateral_level,
      sizeof(*cm->rst_info.bilateral_level) * ntiles * BILATERAL_SUBTILES);
895
896
  assert(cm->rst_info.bilateral_level != NULL);

Yaowu Xu's avatar
Yaowu Xu committed
897
  cm->rst_info.wiener_level = (int *)aom_realloc(
898
899
      cm->rst_info.wiener_level, sizeof(*cm->rst_info.wiener_level) * ntiles);
  assert(cm->rst_info.wiener_level != NULL);
900
  cm->rst_info.vfilter = (int(*)[RESTORATION_WIN])aom_realloc(
901
902
      cm->rst_info.vfilter, sizeof(*cm->rst_info.vfilter) * ntiles);
  assert(cm->rst_info.vfilter != NULL);
903
  cm->rst_info.hfilter = (int(*)[RESTORATION_WIN])aom_realloc(
904
905
      cm->rst_info.hfilter, sizeof(*cm->rst_info.hfilter) * ntiles);
  assert(cm->rst_info.hfilter != NULL);
906
907
  tile_cost_wiener = (double *)aom_malloc(sizeof(cost_wiener) * ntiles);
  tile_cost_bilateral = (double *)aom_malloc(sizeof(cost_bilateral) * ntiles);
908

909
  lf->sharpness_level = cm->frame_type == KEY_FRAME ? 0 : cpi->oxcf.sharpness;
910
911

  if (method == LPF_PICK_MINIMAL_LPF && lf->filter_level) {
912
    lf->filter_level = 0;
913
    cm->rst_info.frame_restoration_type = RESTORE_NONE;
914
915
  } else if (method >= LPF_PICK_FROM_Q) {
    const int min_filter_level = 0;
Yaowu Xu's avatar
Yaowu Xu committed
916
917
    const int max_filter_level = av1_get_max_filter_level(cpi);
    const int q = av1_ac_quant(cm->base_qindex, 0, cm->bit_depth);
918
919
// These values were determined by linear fitting the result of the
// searched level, filt_guess = q * 0.316206 + 3.87252
Yaowu Xu's avatar
Yaowu Xu committed
920
#if CONFIG_AOM_HIGHBITDEPTH
921
922
    int filt_guess;
    switch (cm->bit_depth) {
Yaowu Xu's avatar
Yaowu Xu committed
923
      case AOM_BITS_8:
924
925
        filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 1015158, 18);
        break;
Yaowu Xu's avatar
Yaowu Xu committed
926
      case AOM_BITS_10:
927
928
        filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 4060632, 20);
        break;
Yaowu Xu's avatar
Yaowu Xu committed
929
      case AOM_BITS_12:
930
931
932
        filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 16242526, 22);
        break;
      default:
933
        assert(0 &&
Yaowu Xu's avatar
Yaowu Xu committed
934
935
               "bit_depth should be AOM_BITS_8, AOM_BITS_10 "
               "or AOM_BITS_12");
936
937
938
939
        return;
    }
#else
    int filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 1015158, 18);
Yaowu Xu's avatar
Yaowu Xu committed
940
#endif  // CONFIG_AOM_HIGHBITDEPTH
941
    if (cm->frame_type == KEY_FRAME) filt_guess -= 4;
942
    lf->filter_level = clamp(filt_guess, min_filter_level, max_filter_level);
943
    bilateral_success = search_bilateral_level(
944
945
        src, cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE,
        cm->rst_info.bilateral_level, &cost_bilateral, tile_cost_bilateral);
946
    wiener_success = search_wiener_filter(
947
        src, cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE,
948
        cm->rst_info.vfilter, cm->rst_info.hfilter, cm->rst_info.wiener_level,
949
950
951
952
        &cost_wiener, tile_cost_wiener);
    switchable_success = search_switchable_restoration(
        src, cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE,
        &cm->rst_info, tile_cost_bilateral, tile_cost_wiener, &cost_switchable);
953
  } else {
954
955
956
957
958
    // lf->filter_level = av1_search_filter_level(
    //     src, cpi, method == LPF_PICK_FROM_SUBIMAGE, &cost_norestore);
    // bilateral_success = search_bilateral_level(
    //     src, cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE,
    //     cm->rst_info.bilateral_level, &cost_bilateral, tile_cost_bilateral);
959
    bilateral_success = search_filter_bilateral_level(
960
961
        src, cpi, method == LPF_PICK_FROM_SUBIMAGE, &lf->filter_level,
        cm->rst_info.bilateral_level, &cost_bilateral, tile_cost_bilateral);
962
    wiener_success = search_wiener_filter(
963
        src, cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE,
964
        cm->rst_info.vfilter, cm->rst_info.hfilter, cm->rst_info.wiener_level,
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
        &cost_wiener, tile_cost_wiener);
    switchable_success = search_switchable_restoration(
        src, cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE,
        &cm->rst_info, tile_cost_bilateral, tile_cost_wiener, &cost_switchable);
  }
  if (cost_bilateral < AOMMIN(cost_wiener, cost_switchable)) {
    if (bilateral_success)
      cm->rst_info.frame_restoration_type = RESTORE_BILATERAL;
    else
      cm->rst_info.frame_restoration_type = RESTORE_NONE;
  } else if (cost_wiener < AOMMIN(cost_bilateral, cost_switchable)) {
    if (wiener_success)
      cm->rst_info.frame_restoration_type = RESTORE_WIENER;
    else
      cm->rst_info.frame_restoration_type = RESTORE_NONE;
  } else {
    if (switchable_success)
      cm->rst_info.frame_restoration_type = RESTORE_SWITCHABLE;
    else
      cm->rst_info.frame_restoration_type = RESTORE_NONE;
985
  }
986
987
988
989
990
  printf("Frame %d frame_restore_type %d [%d]: %f %f %f\n",
         cm->current_video_frame, cm->rst_info.frame_restoration_type, ntiles,
         cost_bilateral, cost_wiener, cost_switchable);
  aom_free(tile_cost_bilateral);
  aom_free(tile_cost_wiener);
991
}