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;