]> granicus.if.org Git - libvpx/commitdiff
Misc. refactoring of loop restoration
authorDebargha Mukherjee <debargha@google.com>
Sat, 17 Sep 2016 20:16:58 +0000 (13:16 -0700)
committerDebargha Mukherjee <debargha@google.com>
Wed, 21 Sep 2016 03:46:36 +0000 (20:46 -0700)
Streamilines the functions and data structures to make it
easy to add new restore options.

Change-Id: Ib00638a5749e6c38c2455f3e3142b1025e6e0624

av1/common/alloccommon.c
av1/common/entropymode.c
av1/common/restoration.c
av1/common/restoration.h
av1/decoder/decodeframe.c
av1/encoder/bitstream.c
av1/encoder/pickrst.c

index db4fbf71e76c775171ebc4057e2931220648629b..7c5b358aa2a775f287d8b829ee57beb382908092 100644 (file)
@@ -85,14 +85,10 @@ void av1_free_ref_frame_buffers(BufferPool *pool) {
 void av1_free_restoration_buffers(AV1_COMMON *cm) {
   aom_free(cm->rst_info.restoration_type);
   cm->rst_info.restoration_type = NULL;
-  aom_free(cm->rst_info.bilateral_level);
-  cm->rst_info.bilateral_level = NULL;
-  aom_free(cm->rst_info.vfilter);
-  cm->rst_info.vfilter = NULL;
-  aom_free(cm->rst_info.hfilter);
-  cm->rst_info.hfilter = NULL;
-  aom_free(cm->rst_info.wiener_level);
-  cm->rst_info.wiener_level = NULL;
+  aom_free(cm->rst_info.bilateral_info);
+  cm->rst_info.bilateral_info = NULL;
+  aom_free(cm->rst_info.wiener_info);
+  cm->rst_info.wiener_info = NULL;
 }
 #endif  // CONFIG_LOOP_RESTORATION
 
index a999950f6895831652fa8cda72203a830352c15b..b65b6dffabf503e0bcec176b999ac2b7b566e2a0 100644 (file)
@@ -1655,9 +1655,11 @@ void av1_setup_past_independence(AV1_COMMON *cm) {
   // To force update of the sharpness
   lf->last_sharpness_level = -1;
 #if CONFIG_LOOP_RESTORATION
-  if (cm->rst_info.bilateral_level) {
+  if (cm->rst_info.bilateral_info) {
+    int s;
     for (i = 0; i < cm->rst_internal.ntiles; ++i)
-      cm->rst_info.bilateral_level[i] = -1;
+      for (s = 0; s < BILATERAL_SUBTILES; ++s)
+        cm->rst_info.bilateral_info[i].level[s] = -1;
   }
 #endif  // CONFIG_LOOP_RESTORATION
 
index 1baa5b4fcb7be1c0016fe3d24a03f413f934eb22..f58d91a917ca04ecd86ad508456e8608735acf6c 100644 (file)
@@ -40,14 +40,14 @@ typedef struct bilateral_params {
 } BilateralParamsType;
 
 static BilateralParamsType bilateral_level_to_params_arr[BILATERAL_LEVELS] = {
-  // Values are rounded to 1/16 th precision
+  //  Values are rounded to 1/16 th precision
   { 8, 9, 30 },   { 9, 8, 30 },   { 9, 11, 32 },  { 11, 9, 32 },
   { 14, 14, 36 }, { 18, 18, 36 }, { 24, 24, 40 }, { 32, 32, 40 },
 };
 
 static BilateralParamsType
     bilateral_level_to_params_arr_kf[BILATERAL_LEVELS_KF] = {
-      // Values are rounded to 1/16 th precision
+      //  Values are rounded to 1/16 th precision
       { 8, 8, 30 },   { 9, 9, 32 },   { 10, 10, 32 }, { 12, 12, 32 },
       { 14, 14, 32 }, { 18, 18, 36 }, { 24, 24, 40 }, { 30, 30, 44 },
       { 36, 36, 48 }, { 42, 42, 48 }, { 48, 48, 48 }, { 48, 48, 56 },
@@ -151,33 +151,35 @@ void av1_loop_restoration_init(RestorationInternal *rst, RestorationInfo *rsi,
                           &rst->nhtiles, &rst->nvtiles);
   if (rsi->frame_restoration_type == RESTORE_WIENER) {
     for (tile_idx = 0; tile_idx < rst->ntiles; ++tile_idx) {
-      rsi->vfilter[tile_idx][RESTORATION_HALFWIN] =
-          rsi->hfilter[tile_idx][RESTORATION_HALFWIN] = RESTORATION_FILT_STEP;
+      rsi->wiener_info[tile_idx].vfilter[RESTORATION_HALFWIN] =
+          rsi->wiener_info[tile_idx].hfilter[RESTORATION_HALFWIN] =
+              RESTORATION_FILT_STEP;
       for (i = 0; i < RESTORATION_HALFWIN; ++i) {
-        rsi->vfilter[tile_idx][RESTORATION_WIN - 1 - i] =
-            rsi->vfilter[tile_idx][i];
-        rsi->hfilter[tile_idx][RESTORATION_WIN - 1 - i] =
-            rsi->hfilter[tile_idx][i];
-        rsi->vfilter[tile_idx][RESTORATION_HALFWIN] -=
-            2 * rsi->vfilter[tile_idx][i];
-        rsi->hfilter[tile_idx][RESTORATION_HALFWIN] -=
-            2 * rsi->hfilter[tile_idx][i];
+        rsi->wiener_info[tile_idx].vfilter[RESTORATION_WIN - 1 - i] =
+            rsi->wiener_info[tile_idx].vfilter[i];
+        rsi->wiener_info[tile_idx].hfilter[RESTORATION_WIN - 1 - i] =
+            rsi->wiener_info[tile_idx].hfilter[i];
+        rsi->wiener_info[tile_idx].vfilter[RESTORATION_HALFWIN] -=
+            2 * rsi->wiener_info[tile_idx].vfilter[i];
+        rsi->wiener_info[tile_idx].hfilter[RESTORATION_HALFWIN] -=
+            2 * rsi->wiener_info[tile_idx].hfilter[i];
       }
     }
   } else if (rsi->frame_restoration_type == RESTORE_SWITCHABLE) {
     for (tile_idx = 0; tile_idx < rst->ntiles; ++tile_idx) {
       if (rsi->restoration_type[tile_idx] == RESTORE_WIENER) {
-        rsi->vfilter[tile_idx][RESTORATION_HALFWIN] =
-            rsi->hfilter[tile_idx][RESTORATION_HALFWIN] = RESTORATION_FILT_STEP;
+        rsi->wiener_info[tile_idx].vfilter[RESTORATION_HALFWIN] =
+            rsi->wiener_info[tile_idx].hfilter[RESTORATION_HALFWIN] =
+                RESTORATION_FILT_STEP;
         for (i = 0; i < RESTORATION_HALFWIN; ++i) {
-          rsi->vfilter[tile_idx][RESTORATION_WIN - 1 - i] =
-              rsi->vfilter[tile_idx][i];
-          rsi->hfilter[tile_idx][RESTORATION_WIN - 1 - i] =
-              rsi->hfilter[tile_idx][i];
-          rsi->vfilter[tile_idx][RESTORATION_HALFWIN] -=
-              2 * rsi->vfilter[tile_idx][i];
-          rsi->hfilter[tile_idx][RESTORATION_HALFWIN] -=
-              2 * rsi->hfilter[tile_idx][i];
+          rsi->wiener_info[tile_idx].vfilter[RESTORATION_WIN - 1 - i] =
+              rsi->wiener_info[tile_idx].vfilter[i];
+          rsi->wiener_info[tile_idx].hfilter[RESTORATION_WIN - 1 - i] =
+              rsi->wiener_info[tile_idx].hfilter[i];
+          rsi->wiener_info[tile_idx].vfilter[RESTORATION_HALFWIN] -=
+              2 * rsi->wiener_info[tile_idx].vfilter[i];
+          rsi->wiener_info[tile_idx].hfilter[RESTORATION_HALFWIN] -=
+              2 * rsi->wiener_info[tile_idx].hfilter[i];
         }
       }
     }
@@ -195,8 +197,7 @@ static void loop_bilateral_filter_tile(uint8_t *data, int tile_idx, int width,
 
   for (subtile_idx = 0; subtile_idx < BILATERAL_SUBTILES; ++subtile_idx) {
     uint8_t *data_p, *tmpdata_p;
-    const int level =
-        rst->rsi->bilateral_level[tile_idx * BILATERAL_SUBTILES + subtile_idx];
+    const int level = rst->rsi->bilateral_info[tile_idx].level[subtile_idx];
     uint8_t(*wx_lut)[RESTORATION_WIN];
     uint8_t *wr_lut_;
 
@@ -282,7 +283,7 @@ static void loop_wiener_filter_tile(uint8_t *data, int tile_idx, int width,
   int h_start, h_end, v_start, v_end;
   uint8_t *data_p, *tmpdata_p;
 
-  if (rst->rsi->wiener_level[tile_idx] == 0) return;
+  if (rst->rsi->wiener_info[tile_idx].level == 0) return;
   // Filter row-wise
   av1_get_rest_tile_limits(tile_idx, 0, 0, rst->nhtiles, rst->nvtiles,
                            tile_width, tile_height, width, height, 1, 0,
@@ -291,7 +292,8 @@ static void loop_wiener_filter_tile(uint8_t *data, int tile_idx, int width,
   tmpdata_p = tmpdata + h_start + v_start * tmpstride;
   for (i = 0; i < (v_end - v_start); ++i) {
     for (j = 0; j < (h_end - h_start); ++j) {
-      *tmpdata_p++ = hor_sym_filter(data_p++, rst->rsi->hfilter[tile_idx]);
+      *tmpdata_p++ =
+          hor_sym_filter(data_p++, rst->rsi->wiener_info[tile_idx].hfilter);
     }
     data_p += stride - (h_end - h_start);
     tmpdata_p += tmpstride - (h_end - h_start);
@@ -304,8 +306,8 @@ static void loop_wiener_filter_tile(uint8_t *data, int tile_idx, int width,
   tmpdata_p = tmpdata + h_start + v_start * tmpstride;
   for (i = 0; i < (v_end - v_start); ++i) {
     for (j = 0; j < (h_end - h_start); ++j) {
-      *data_p++ =
-          ver_sym_filter(tmpdata_p++, tmpstride, rst->rsi->vfilter[tile_idx]);
+      *data_p++ = ver_sym_filter(tmpdata_p++, tmpstride,
+                                 rst->rsi->wiener_info[tile_idx].vfilter);
     }
     data_p += stride - (h_end - h_start);
     tmpdata_p += tmpstride - (h_end - h_start);
@@ -370,8 +372,7 @@ static void loop_bilateral_filter_tile_highbd(uint16_t *data, int tile_idx,
 
   for (subtile_idx = 0; subtile_idx < BILATERAL_SUBTILES; ++subtile_idx) {
     uint16_t *data_p, *tmpdata_p;
-    const int level =
-        rst->rsi->bilateral_level[tile_idx * BILATERAL_SUBTILES + subtile_idx];
+    const int level = rst->rsi->bilateral_info[tile_idx].level[subtile_idx];
     uint8_t(*wx_lut)[RESTORATION_WIN];
     uint8_t *wr_lut_;
 
@@ -462,7 +463,7 @@ static void loop_wiener_filter_tile_highbd(uint16_t *data, int tile_idx,
   int i, j;
   uint16_t *data_p, *tmpdata_p;
 
-  if (rst->rsi->wiener_level[tile_idx] == 0) return;
+  if (rst->rsi->wiener_info[tile_idx].level == 0) return;
   // Filter row-wise
   av1_get_rest_tile_limits(tile_idx, 0, 0, rst->nhtiles, rst->nvtiles,
                            tile_width, tile_height, width, height, 1, 0,
@@ -472,7 +473,7 @@ static void loop_wiener_filter_tile_highbd(uint16_t *data, int tile_idx,
   for (i = 0; i < (v_end - v_start); ++i) {
     for (j = 0; j < (h_end - h_start); ++j) {
       *tmpdata_p++ = hor_sym_filter_highbd(
-          data_p++, rst->rsi->hfilter[tile_idx], bit_depth);
+          data_p++, rst->rsi->wiener_info[tile_idx].hfilter, bit_depth);
     }
     data_p += stride - (h_end - h_start);
     tmpdata_p += tmpstride - (h_end - h_start);
@@ -486,7 +487,8 @@ static void loop_wiener_filter_tile_highbd(uint16_t *data, int tile_idx,
   for (i = 0; i < (v_end - v_start); ++i) {
     for (j = 0; j < (h_end - h_start); ++j) {
       *data_p++ = ver_sym_filter_highbd(tmpdata_p++, tmpstride,
-                                        rst->rsi->vfilter[tile_idx], bit_depth);
+                                        rst->rsi->wiener_info[tile_idx].vfilter,
+                                        bit_depth);
     }
     data_p += stride - (h_end - h_start);
     tmpdata_p += tmpstride - (h_end - h_start);
index b478bb8452da83dab2b95a6d1c133ffb93547b24..a5150ad3804577bdf631d1c89d707c5b79512266 100644 (file)
@@ -57,14 +57,20 @@ extern "C" {
 #define WIENER_FILT_TAP2_MAXV \
   (WIENER_FILT_TAP2_MINV - 1 + (1 << WIENER_FILT_TAP2_BITS))
 
+typedef struct { int level[BILATERAL_SUBTILES]; } BilateralInfo;
+
+typedef struct {
+  int level;
+  int vfilter[RESTORATION_WIN], hfilter[RESTORATION_WIN];
+} WienerInfo;
+
 typedef struct {
   RestorationType frame_restoration_type;
   RestorationType *restoration_type;
   // Bilateral filter
-  int *bilateral_level;
+  BilateralInfo *bilateral_info;
   // Wiener filter
-  int *wiener_level;
-  int (*vfilter)[RESTORATION_WIN], (*hfilter)[RESTORATION_WIN];
+  WienerInfo *wiener_info;
 } RestorationInfo;
 
 typedef struct {
index 9efe01652c4a58f6b6f20879b5291125a38b5450..c2f187036beea569c32356d2761e0dc9603f8081 100644 (file)
@@ -1920,101 +1920,96 @@ static void decode_restoration(AV1_COMMON *cm, aom_reader *rb) {
     rsi->restoration_type = (RestorationType *)aom_realloc(
         rsi->restoration_type, sizeof(*rsi->restoration_type) * ntiles);
     if (rsi->frame_restoration_type == RESTORE_SWITCHABLE) {
-      rsi->bilateral_level = (int *)aom_realloc(
-          rsi->bilateral_level,
-          sizeof(*rsi->bilateral_level) * ntiles * BILATERAL_SUBTILES);
-      assert(rsi->bilateral_level != NULL);
-      rsi->wiener_level = (int *)aom_realloc(
-          rsi->wiener_level, sizeof(*rsi->wiener_level) * ntiles);
-      assert(rsi->wiener_level != NULL);
-      rsi->vfilter = (int(*)[RESTORATION_WIN])aom_realloc(
-          rsi->vfilter, sizeof(*rsi->vfilter) * ntiles);
-      assert(rsi->vfilter != NULL);
-      rsi->hfilter = (int(*)[RESTORATION_WIN])aom_realloc(
-          rsi->hfilter, sizeof(*rsi->hfilter) * ntiles);
-      assert(rsi->hfilter != NULL);
+      rsi->bilateral_info = (BilateralInfo *)aom_realloc(
+          rsi->bilateral_info, sizeof(*rsi->bilateral_info) * ntiles);
+      assert(rsi->bilateral_info != NULL);
+      rsi->wiener_info = (WienerInfo *)aom_realloc(
+          rsi->wiener_info, sizeof(*rsi->wiener_info) * ntiles);
+      assert(rsi->wiener_info != NULL);
       for (i = 0; i < ntiles; ++i) {
         rsi->restoration_type[i] = aom_read_tree(
             rb, av1_switchable_restore_tree, cm->fc->switchable_restore_prob);
         if (rsi->restoration_type[i] == RESTORE_WIENER) {
-          rsi->wiener_level[i] = 1;
-          rsi->vfilter[i][0] = aom_read_literal(rb, WIENER_FILT_TAP0_BITS) +
-                               WIENER_FILT_TAP0_MINV;
-          rsi->vfilter[i][1] = aom_read_literal(rb, WIENER_FILT_TAP1_BITS) +
-                               WIENER_FILT_TAP1_MINV;
-          rsi->vfilter[i][2] = aom_read_literal(rb, WIENER_FILT_TAP2_BITS) +
-                               WIENER_FILT_TAP2_MINV;
-          rsi->hfilter[i][0] = aom_read_literal(rb, WIENER_FILT_TAP0_BITS) +
-                               WIENER_FILT_TAP0_MINV;
-          rsi->hfilter[i][1] = aom_read_literal(rb, WIENER_FILT_TAP1_BITS) +
-                               WIENER_FILT_TAP1_MINV;
-          rsi->hfilter[i][2] = aom_read_literal(rb, WIENER_FILT_TAP2_BITS) +
-                               WIENER_FILT_TAP2_MINV;
+          rsi->wiener_info[i].level = 1;
+          rsi->wiener_info[i].vfilter[0] =
+              aom_read_literal(rb, WIENER_FILT_TAP0_BITS) +
+              WIENER_FILT_TAP0_MINV;
+          rsi->wiener_info[i].vfilter[1] =
+              aom_read_literal(rb, WIENER_FILT_TAP1_BITS) +
+              WIENER_FILT_TAP1_MINV;
+          rsi->wiener_info[i].vfilter[2] =
+              aom_read_literal(rb, WIENER_FILT_TAP2_BITS) +
+              WIENER_FILT_TAP2_MINV;
+          rsi->wiener_info[i].hfilter[0] =
+              aom_read_literal(rb, WIENER_FILT_TAP0_BITS) +
+              WIENER_FILT_TAP0_MINV;
+          rsi->wiener_info[i].hfilter[1] =
+              aom_read_literal(rb, WIENER_FILT_TAP1_BITS) +
+              WIENER_FILT_TAP1_MINV;
+          rsi->wiener_info[i].hfilter[2] =
+              aom_read_literal(rb, WIENER_FILT_TAP2_BITS) +
+              WIENER_FILT_TAP2_MINV;
         } else if (rsi->restoration_type[i] == RESTORE_BILATERAL) {
           int s;
           for (s = 0; s < BILATERAL_SUBTILES; ++s) {
-            const int j = i * BILATERAL_SUBTILES + s;
 #if BILATERAL_SUBTILES == 0
-            rsi->bilateral_level[j] =
+            rsi->bilateral_info[i].level[s] =
                 aom_read_literal(rb, av1_bilateral_level_bits(cm));
 #else
             if (aom_read(rb, RESTORE_NONE_BILATERAL_PROB)) {
-              rsi->bilateral_level[j] =
+              rsi->bilateral_info[i].level[s] =
                   aom_read_literal(rb, av1_bilateral_level_bits(cm));
             } else {
-              rsi->bilateral_level[j] = -1;
+              rsi->bilateral_info[i].level[s] = -1;
             }
 #endif
           }
         }
       }
     } else if (rsi->frame_restoration_type == RESTORE_WIENER) {
-      rsi->wiener_level = (int *)aom_realloc(
-          rsi->wiener_level, sizeof(*rsi->wiener_level) * ntiles);
-      assert(rsi->wiener_level != NULL);
-      rsi->vfilter = (int(*)[RESTORATION_WIN])aom_realloc(
-          rsi->vfilter, sizeof(*rsi->vfilter) * ntiles);
-      assert(rsi->vfilter != NULL);
-      rsi->hfilter = (int(*)[RESTORATION_WIN])aom_realloc(
-          rsi->hfilter, sizeof(*rsi->hfilter) * ntiles);
-      assert(rsi->hfilter != NULL);
+      rsi->wiener_info = (WienerInfo *)aom_realloc(
+          rsi->wiener_info, sizeof(*rsi->wiener_info) * ntiles);
+      assert(rsi->wiener_info != NULL);
       for (i = 0; i < ntiles; ++i) {
         if (aom_read(rb, RESTORE_NONE_WIENER_PROB)) {
-          rsi->wiener_level[i] = 1;
+          rsi->wiener_info[i].level = 1;
           rsi->restoration_type[i] = RESTORE_WIENER;
-          rsi->vfilter[i][0] = aom_read_literal(rb, WIENER_FILT_TAP0_BITS) +
-                               WIENER_FILT_TAP0_MINV;
-          rsi->vfilter[i][1] = aom_read_literal(rb, WIENER_FILT_TAP1_BITS) +
-                               WIENER_FILT_TAP1_MINV;
-          rsi->vfilter[i][2] = aom_read_literal(rb, WIENER_FILT_TAP2_BITS) +
-                               WIENER_FILT_TAP2_MINV;
-          rsi->hfilter[i][0] = aom_read_literal(rb, WIENER_FILT_TAP0_BITS) +
-                               WIENER_FILT_TAP0_MINV;
-          rsi->hfilter[i][1] = aom_read_literal(rb, WIENER_FILT_TAP1_BITS) +
-                               WIENER_FILT_TAP1_MINV;
-          rsi->hfilter[i][2] = aom_read_literal(rb, WIENER_FILT_TAP2_BITS) +
-                               WIENER_FILT_TAP2_MINV;
+          rsi->wiener_info[i].vfilter[0] =
+              aom_read_literal(rb, WIENER_FILT_TAP0_BITS) +
+              WIENER_FILT_TAP0_MINV;
+          rsi->wiener_info[i].vfilter[1] =
+              aom_read_literal(rb, WIENER_FILT_TAP1_BITS) +
+              WIENER_FILT_TAP1_MINV;
+          rsi->wiener_info[i].vfilter[2] =
+              aom_read_literal(rb, WIENER_FILT_TAP2_BITS) +
+              WIENER_FILT_TAP2_MINV;
+          rsi->wiener_info[i].hfilter[0] =
+              aom_read_literal(rb, WIENER_FILT_TAP0_BITS) +
+              WIENER_FILT_TAP0_MINV;
+          rsi->wiener_info[i].hfilter[1] =
+              aom_read_literal(rb, WIENER_FILT_TAP1_BITS) +
+              WIENER_FILT_TAP1_MINV;
+          rsi->wiener_info[i].hfilter[2] =
+              aom_read_literal(rb, WIENER_FILT_TAP2_BITS) +
+              WIENER_FILT_TAP2_MINV;
         } else {
-          rsi->wiener_level[i] = 0;
+          rsi->wiener_info[i].level = 0;
           rsi->restoration_type[i] = RESTORE_NONE;
         }
       }
     } else {
-      rsi->frame_restoration_type = RESTORE_BILATERAL;
-      rsi->bilateral_level = (int *)aom_realloc(
-          rsi->bilateral_level,
-          sizeof(*rsi->bilateral_level) * ntiles * BILATERAL_SUBTILES);
-      assert(rsi->bilateral_level != NULL);
+      rsi->bilateral_info = (BilateralInfo *)aom_realloc(
+          rsi->bilateral_info, sizeof(*rsi->bilateral_info) * ntiles);
+      assert(rsi->bilateral_info != NULL);
       for (i = 0; i < ntiles; ++i) {
         int s;
         rsi->restoration_type[i] = RESTORE_BILATERAL;
         for (s = 0; s < BILATERAL_SUBTILES; ++s) {
-          const int j = i * BILATERAL_SUBTILES + s;
           if (aom_read(rb, RESTORE_NONE_BILATERAL_PROB)) {
-            rsi->bilateral_level[j] =
+            rsi->bilateral_info[i].level[s] =
                 aom_read_literal(rb, av1_bilateral_level_bits(cm));
           } else {
-            rsi->bilateral_level[j] = -1;
+            rsi->bilateral_info[i].level[s] = -1;
           }
         }
       }
index 1033a3acb2c9a7c1b92e2ba93d1dc505376087f8..ec933cb5c19120cdd9c3df189a860a3f0b88e1e7 100644 (file)
@@ -2455,75 +2455,84 @@ static void encode_restoration_mode(AV1_COMMON *cm,
 
 static void encode_restoration(AV1_COMMON *cm, aom_writer *wb) {
   int i;
-  RestorationInfo *rst = &cm->rst_info;
-  if (rst->frame_restoration_type != RESTORE_NONE) {
-    if (rst->frame_restoration_type == RESTORE_SWITCHABLE) {
+  RestorationInfo *rsi = &cm->rst_info;
+  if (rsi->frame_restoration_type != RESTORE_NONE) {
+    if (rsi->frame_restoration_type == RESTORE_SWITCHABLE) {
       // RESTORE_SWITCHABLE
       for (i = 0; i < cm->rst_internal.ntiles; ++i) {
         av1_write_token(
             wb, av1_switchable_restore_tree, cm->fc->switchable_restore_prob,
-            &switchable_restore_encodings[rst->restoration_type[i]]);
-        if (rst->restoration_type[i] == RESTORE_NONE) {
-        } else if (rst->restoration_type[i] == RESTORE_BILATERAL) {
+            &switchable_restore_encodings[rsi->restoration_type[i]]);
+        if (rsi->restoration_type[i] == RESTORE_BILATERAL) {
           int s;
           for (s = 0; s < BILATERAL_SUBTILES; ++s) {
-            const int j = i * BILATERAL_SUBTILES + s;
 #if BILATERAL_SUBTILES == 0
-            aom_write_literal(wb, rst->bilateral_level[j],
+            aom_write_literal(wb, rsi->bilateral_info[i].level[s],
                               av1_bilateral_level_bits(cm));
 #else
-            aom_write(wb, rst->bilateral_level[j] >= 0,
+            aom_write(wb, rsi->bilateral_info[i].level[s] >= 0,
                       RESTORE_NONE_BILATERAL_PROB);
-            if (rst->bilateral_level[j] >= 0) {
-              aom_write_literal(wb, rst->bilateral_level[j],
+            if (rsi->bilateral_info[i].level[s] >= 0) {
+              aom_write_literal(wb, rsi->bilateral_info[i].level[s],
                                 av1_bilateral_level_bits(cm));
             }
 #endif
           }
-        } else {
-          aom_write_literal(wb, rst->vfilter[i][0] - WIENER_FILT_TAP0_MINV,
-                            WIENER_FILT_TAP0_BITS);
-          aom_write_literal(wb, rst->vfilter[i][1] - WIENER_FILT_TAP1_MINV,
-                            WIENER_FILT_TAP1_BITS);
-          aom_write_literal(wb, rst->vfilter[i][2] - WIENER_FILT_TAP2_MINV,
-                            WIENER_FILT_TAP2_BITS);
-          aom_write_literal(wb, rst->hfilter[i][0] - WIENER_FILT_TAP0_MINV,
-                            WIENER_FILT_TAP0_BITS);
-          aom_write_literal(wb, rst->hfilter[i][1] - WIENER_FILT_TAP1_MINV,
-                            WIENER_FILT_TAP1_BITS);
-          aom_write_literal(wb, rst->hfilter[i][2] - WIENER_FILT_TAP2_MINV,
-                            WIENER_FILT_TAP2_BITS);
+        } else if (rsi->restoration_type[i] == RESTORE_WIENER) {
+          aom_write_literal(
+              wb, rsi->wiener_info[i].vfilter[0] - WIENER_FILT_TAP0_MINV,
+              WIENER_FILT_TAP0_BITS);
+          aom_write_literal(
+              wb, rsi->wiener_info[i].vfilter[1] - WIENER_FILT_TAP1_MINV,
+              WIENER_FILT_TAP1_BITS);
+          aom_write_literal(
+              wb, rsi->wiener_info[i].vfilter[2] - WIENER_FILT_TAP2_MINV,
+              WIENER_FILT_TAP2_BITS);
+          aom_write_literal(
+              wb, rsi->wiener_info[i].hfilter[0] - WIENER_FILT_TAP0_MINV,
+              WIENER_FILT_TAP0_BITS);
+          aom_write_literal(
+              wb, rsi->wiener_info[i].hfilter[1] - WIENER_FILT_TAP1_MINV,
+              WIENER_FILT_TAP1_BITS);
+          aom_write_literal(
+              wb, rsi->wiener_info[i].hfilter[2] - WIENER_FILT_TAP2_MINV,
+              WIENER_FILT_TAP2_BITS);
         }
       }
-    } else if (rst->frame_restoration_type == RESTORE_BILATERAL) {
+    } else if (rsi->frame_restoration_type == RESTORE_BILATERAL) {
       for (i = 0; i < cm->rst_internal.ntiles; ++i) {
         int s;
         for (s = 0; s < BILATERAL_SUBTILES; ++s) {
-          const int j = i * BILATERAL_SUBTILES + s;
-          aom_write(wb, rst->bilateral_level[j] >= 0,
+          aom_write(wb, rsi->bilateral_info[i].level[s] >= 0,
                     RESTORE_NONE_BILATERAL_PROB);
-          if (rst->bilateral_level[j] >= 0) {
-            aom_write_literal(wb, rst->bilateral_level[j],
+          if (rsi->bilateral_info[i].level[s] >= 0) {
+            aom_write_literal(wb, rsi->bilateral_info[i].level[s],
                               av1_bilateral_level_bits(cm));
           }
         }
       }
-    } else if (rst->frame_restoration_type == RESTORE_WIENER) {
+    } else if (rsi->frame_restoration_type == RESTORE_WIENER) {
       for (i = 0; i < cm->rst_internal.ntiles; ++i) {
-        aom_write(wb, rst->wiener_level[i] != 0, RESTORE_NONE_WIENER_PROB);
-        if (rst->wiener_level[i]) {
-          aom_write_literal(wb, rst->vfilter[i][0] - WIENER_FILT_TAP0_MINV,
-                            WIENER_FILT_TAP0_BITS);
-          aom_write_literal(wb, rst->vfilter[i][1] - WIENER_FILT_TAP1_MINV,
-                            WIENER_FILT_TAP1_BITS);
-          aom_write_literal(wb, rst->vfilter[i][2] - WIENER_FILT_TAP2_MINV,
-                            WIENER_FILT_TAP2_BITS);
-          aom_write_literal(wb, rst->hfilter[i][0] - WIENER_FILT_TAP0_MINV,
-                            WIENER_FILT_TAP0_BITS);
-          aom_write_literal(wb, rst->hfilter[i][1] - WIENER_FILT_TAP1_MINV,
-                            WIENER_FILT_TAP1_BITS);
-          aom_write_literal(wb, rst->hfilter[i][2] - WIENER_FILT_TAP2_MINV,
-                            WIENER_FILT_TAP2_BITS);
+        aom_write(wb, rsi->wiener_info[i].level != 0, RESTORE_NONE_WIENER_PROB);
+        if (rsi->wiener_info[i].level) {
+          aom_write_literal(
+              wb, rsi->wiener_info[i].vfilter[0] - WIENER_FILT_TAP0_MINV,
+              WIENER_FILT_TAP0_BITS);
+          aom_write_literal(
+              wb, rsi->wiener_info[i].vfilter[1] - WIENER_FILT_TAP1_MINV,
+              WIENER_FILT_TAP1_BITS);
+          aom_write_literal(
+              wb, rsi->wiener_info[i].vfilter[2] - WIENER_FILT_TAP2_MINV,
+              WIENER_FILT_TAP2_BITS);
+          aom_write_literal(
+              wb, rsi->wiener_info[i].hfilter[0] - WIENER_FILT_TAP0_MINV,
+              WIENER_FILT_TAP0_BITS);
+          aom_write_literal(
+              wb, rsi->wiener_info[i].hfilter[1] - WIENER_FILT_TAP1_MINV,
+              WIENER_FILT_TAP1_BITS);
+          aom_write_literal(
+              wb, rsi->wiener_info[i].hfilter[2] - WIENER_FILT_TAP2_MINV,
+              WIENER_FILT_TAP2_BITS);
         }
       }
     }
index 00e46a689562cc4afb5e19931b11850ecd2180fe..28bdcc3e77b9758a6f0ad707378aa2c50068d4b7 100644 (file)
 #include "av1/encoder/pickrst.h"
 #include "av1/encoder/quantize.h"
 
+typedef double (*search_restore_type)(const YV12_BUFFER_CONFIG *src,
+                                      AV1_COMP *cpi, int filter_level,
+                                      int partial_frame, RestorationInfo *info,
+                                      double *best_tile_cost);
+
 const int frame_level_restore_bits[RESTORE_TYPES] = { 2, 2, 2, 2 };
 
 static int64_t sse_restoration_tile(const YV12_BUFFER_CONFIG *src,
@@ -95,16 +100,15 @@ static int64_t try_restoration_frame(const YV12_BUFFER_CONFIG *src,
   return filt_err;
 }
 
-static int search_bilateral_level(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
-                                  int filter_level, int partial_frame,
-                                  int *bilateral_level, double *best_cost_ret,
-                                  double *best_tile_cost) {
+static double search_bilateral(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
+                               int filter_level, int partial_frame,
+                               RestorationInfo *info, double *best_tile_cost) {
+  BilateralInfo *bilateral_info = info->bilateral_info;
   AV1_COMMON *const cm = &cpi->common;
-  int i, j, tile_idx;
+  int i, tile_idx, subtile_idx;
   int64_t err;
   int bits;
-  double cost, best_cost, cost_norestore, cost_bilateral,
-      cost_norestore_subtile;
+  double cost, best_cost, cost_bilateral, cost_norestore_subtile;
   const int bilateral_level_bits = av1_bilateral_level_bits(&cpi->common);
   const int bilateral_levels = 1 << bilateral_level_bits;
   MACROBLOCK *x = &cpi->td.mb;
@@ -120,29 +124,19 @@ static int search_bilateral_level(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
                         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 = 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);
-
-  // RD cost associated with bilateral filtering
   rsi.frame_restoration_type = RESTORE_BILATERAL;
-  rsi.bilateral_level = (int *)aom_malloc(sizeof(*rsi.bilateral_level) *
-                                          ntiles * BILATERAL_SUBTILES);
-  assert(rsi.bilateral_level != NULL);
+  rsi.bilateral_info =
+      (BilateralInfo *)aom_malloc(sizeof(*rsi.bilateral_info) * ntiles);
+  assert(rsi.bilateral_info != NULL);
 
-  for (j = 0; j < ntiles * BILATERAL_SUBTILES; ++j) bilateral_level[j] = -1;
+  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx)
+    for (subtile_idx = 0; subtile_idx < BILATERAL_SUBTILES; ++subtile_idx)
+      bilateral_info[tile_idx].level[subtile_idx] =
+          rsi.bilateral_info[tile_idx].level[subtile_idx] = -1;
 
-  // TODO(debargha): This is a pretty inefficient way to find the best
-  // parameters per tile. Needs fixing.
   // Find best filter for each tile
   for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
-    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,
@@ -158,181 +152,62 @@ static int search_bilateral_level(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
       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;
+        rsi.bilateral_info[tile_idx].level[subtile_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;
+          bilateral_info[tile_idx].level[subtile_idx] = i;
           best_cost = cost;
         }
+        rsi.bilateral_info[tile_idx].level[subtile_idx] = -1;
       }
     }
-    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;
+    bits = 0;
+    for (subtile_idx = 0; subtile_idx < BILATERAL_SUBTILES; ++subtile_idx) {
+      rsi.bilateral_info[tile_idx].level[subtile_idx] =
+          bilateral_info[tile_idx].level[subtile_idx];
+      if (rsi.bilateral_info[tile_idx].level[subtile_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);
+      bits +=
+          av1_cost_bit(RESTORE_NONE_BILATERAL_PROB,
+                       rsi.bilateral_info[tile_idx].level[subtile_idx] >= 0);
 #endif
-      }
-      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);
     }
+    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);
   }
   // Find cost for combined configuration
   bits = frame_level_restore_bits[rsi.frame_restoration_type]
          << AV1_PROB_COST_SHIFT;
-  for (j = 0; j < ntiles * BILATERAL_SUBTILES; ++j) {
-    rsi.bilateral_level[j] = bilateral_level[j];
-    if (rsi.bilateral_level[j] >= 0) {
-      bits += bilateral_level_bits << AV1_PROB_COST_SHIFT;
-    }
+  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
+    for (subtile_idx = 0; subtile_idx < BILATERAL_SUBTILES; ++subtile_idx) {
+      rsi.bilateral_info[tile_idx].level[subtile_idx] =
+          bilateral_info[tile_idx].level[subtile_idx];
+      if (rsi.bilateral_info[tile_idx].level[subtile_idx] >= 0) {
+        bits += bilateral_level_bits << AV1_PROB_COST_SHIFT;
+      }
 #if BILATERAL_SUBTILES
-    bits +=
-        av1_cost_bit(RESTORE_NONE_BILATERAL_PROB, rsi.bilateral_level[j] >= 0);
+      bits +=
+          av1_cost_bit(RESTORE_NONE_BILATERAL_PROB,
+                       rsi.bilateral_info[tile_idx].level[subtile_idx] >= 0);
 #endif
+    }
   }
   err = try_restoration_frame(src, cpi, &rsi, partial_frame);
   cost_bilateral = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
 
-  aom_free(rsi.bilateral_level);
+  aom_free(rsi.bilateral_info);
 
   aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
-  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;
-  }
-}
-
-static int search_filter_bilateral_level(const YV12_BUFFER_CONFIG *src,
-                                         AV1_COMP *cpi, int partial_frame,
-                                         int *filter_best, int *bilateral_level,
-                                         double *best_cost_ret,
-                                         double *best_tile_cost) {
-  const AV1_COMMON *const cm = &cpi->common;
-  const struct loopfilter *const lf = &cm->lf;
-  const int min_filter_level = 0;
-  const int max_filter_level = av1_get_max_filter_level(cpi);
-  int filt_direction = 0;
-  int filt_best;
-  double best_err;
-  int i, j;
-  int *tmp_level;
-  int bilateral_success[MAX_LOOP_FILTER + 1];
-
-  const int ntiles =
-      av1_get_rest_ntiles(cm->width, cm->height, NULL, NULL, NULL, NULL);
-  double *tile_cost = (double *)aom_malloc(sizeof(*tile_cost) * ntiles);
-
-  // 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
-  for (i = 0; i <= MAX_LOOP_FILTER; ++i) ss_err[i] = -1.0;
-
-  tmp_level =
-      (int *)aom_malloc(sizeof(*tmp_level) * ntiles * BILATERAL_SUBTILES);
-
-  bilateral_success[filt_mid] = search_bilateral_level(
-      src, cpi, filt_mid, partial_frame, tmp_level, &best_err, best_tile_cost);
-  filt_best = filt_mid;
-  ss_err[filt_mid] = best_err;
-  for (j = 0; j < ntiles * BILATERAL_SUBTILES; ++j) {
-    bilateral_level[j] = tmp_level[j];
-  }
-
-  while (filter_step > 0) {
-    const int filt_high = AOMMIN(filt_mid + filter_step, max_filter_level);
-    const int filt_low = AOMMAX(filt_mid - filter_step, min_filter_level);
-
-    // 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
-    if (cm->tx_mode != ONLY_4X4) bias /= 2;
-
-    if (filt_direction <= 0 && filt_low != filt_mid) {
-      // Get Low filter error score
-      if (ss_err[filt_low] < 0) {
-        bilateral_success[filt_low] =
-            search_bilateral_level(src, cpi, filt_low, partial_frame, tmp_level,
-                                   &ss_err[filt_low], tile_cost);
-      }
-      // If value is close to the best so far then bias towards a lower loop
-      // filter value.
-      if (ss_err[filt_low] < (best_err + bias)) {
-        // 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;
-        for (j = 0; j < ntiles * BILATERAL_SUBTILES; ++j) {
-          bilateral_level[j] = tmp_level[j];
-        }
-        memcpy(best_tile_cost, tile_cost, sizeof(*tile_cost) * ntiles);
-      }
-    }
-
-    // Now look at filt_high
-    if (filt_direction >= 0 && filt_high != filt_mid) {
-      if (ss_err[filt_high] < 0) {
-        bilateral_success[filt_high] =
-            search_bilateral_level(src, cpi, filt_high, partial_frame,
-                                   tmp_level, &ss_err[filt_high], tile_cost);
-      }
-      // If value is significantly better than previous best, bias added against
-      // raising filter value
-      if (ss_err[filt_high] < (best_err - bias)) {
-        best_err = ss_err[filt_high];
-        filt_best = filt_high;
-        for (j = 0; j < ntiles * BILATERAL_SUBTILES; ++j) {
-          bilateral_level[j] = tmp_level[j];
-        }
-        memcpy(best_tile_cost, tile_cost, sizeof(*tile_cost) * ntiles);
-      }
-    }
-
-    // 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;
-    }
-  }
-  aom_free(tmp_level);
-  aom_free(tile_cost);
-
-  // Update best error
-  best_err = ss_err[filt_best];
-  if (best_cost_ret) *best_cost_ret = best_err;
-  if (filter_best) *filter_best = filt_best;
-
-  return bilateral_success[filt_best];
+  return cost_bilateral;
 }
 
 static double find_average(uint8_t *src, int h_start, int h_end, int v_start,
@@ -610,9 +485,7 @@ static double compute_score(double *M, double *H, int *vfilt, int *hfilt) {
     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 (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];
@@ -641,17 +514,15 @@ static void quantize_sym_filter(double *f, int *fi) {
   fi[2] = CLIP(fi[2], WIENER_FILT_TAP2_MINV, WIENER_FILT_TAP2_MAXV);
 }
 
-static int search_wiener_filter(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
-                                int filter_level, int partial_frame,
-                                int (*vfilter)[RESTORATION_WIN],
-                                int (*hfilter)[RESTORATION_WIN],
-                                int *wiener_level, double *best_cost_ret,
-                                double *best_tile_cost) {
+static double search_wiener(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
+                            int filter_level, int partial_frame,
+                            RestorationInfo *info, double *best_tile_cost) {
+  WienerInfo *wiener_info = info->wiener_info;
   AV1_COMMON *const cm = &cpi->common;
   RestorationInfo rsi;
   int64_t err;
   int bits;
-  double cost_wiener, cost_norestore, cost_norestore_tile;
+  double cost_wiener, cost_norestore_tile;
   MACROBLOCK *x = &cpi->td.mb;
   double M[RESTORATION_WIN2];
   double H[RESTORATION_WIN2 * RESTORATION_WIN2];
@@ -679,25 +550,14 @@ static int search_wiener_filter(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
                         1, partial_frame);
   aom_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_db);
 
-  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_WIENER;
-  rsi.vfilter =
-      (int(*)[RESTORATION_WIN])aom_malloc(sizeof(*rsi.vfilter) * ntiles);
-  assert(rsi.vfilter != NULL);
-  rsi.hfilter =
-      (int(*)[RESTORATION_WIN])aom_malloc(sizeof(*rsi.hfilter) * ntiles);
-  assert(rsi.hfilter != NULL);
-  rsi.wiener_level = (int *)aom_malloc(sizeof(*rsi.wiener_level) * ntiles);
-  assert(rsi.wiener_level != NULL);
+  rsi.wiener_info = (WienerInfo *)aom_malloc(sizeof(*rsi.wiener_info) * ntiles);
+  assert(rsi.wiener_info != NULL);
+
+  for (j = 0; j < ntiles; ++j) rsi.wiener_info[j].level = 0;
 
   // Compute best Wiener filters for each tile
   for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
-    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);
@@ -706,7 +566,7 @@ static int search_wiener_filter(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
     // #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;
+    best_tile_cost[tile_idx] = DBL_MAX;
 
     av1_get_rest_tile_limits(tile_idx, 0, 0, nhtiles, nvtiles, tile_width,
                              tile_height, width, height, 1, 1, &h_start, &h_end,
@@ -720,91 +580,78 @@ static int search_wiener_filter(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
       compute_stats(dgd->y_buffer, src->y_buffer, h_start, h_end, v_start,
                     v_end, dgd_stride, src_stride, M, H);
 
+    wiener_info[tile_idx].level = 1;
     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;
-      wiener_level[tile_idx] = 0;
+      wiener_info[tile_idx].level = 0;
       continue;
     }
-    quantize_sym_filter(vfilterd, rsi.vfilter[tile_idx]);
-    quantize_sym_filter(hfilterd, rsi.hfilter[tile_idx]);
-    wiener_level[tile_idx] = 1;
+    quantize_sym_filter(vfilterd, rsi.wiener_info[tile_idx].vfilter);
+    quantize_sym_filter(hfilterd, rsi.wiener_info[tile_idx].hfilter);
 
     // 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]);
+    score = compute_score(M, H, rsi.wiener_info[tile_idx].vfilter,
+                          rsi.wiener_info[tile_idx].hfilter);
     if (score > 0.0) {
-      for (i = 0; i < RESTORATION_HALFWIN; ++i)
-        rsi.vfilter[tile_idx][i] = rsi.hfilter[tile_idx][i] = 0;
-      wiener_level[tile_idx] = 0;
+      wiener_info[tile_idx].level = 0;
       continue;
     }
 
-    for (j = 0; j < ntiles; ++j) rsi.wiener_level[j] = 0;
-    rsi.wiener_level[tile_idx] = 1;
-
+    rsi.wiener_info[tile_idx].level = 1;
     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) {
+    if (cost_wiener >= cost_norestore_tile) {
+      wiener_info[tile_idx].level = 0;
+    } else {
+      wiener_info[tile_idx].level = 1;
+      for (i = 0; i < RESTORATION_HALFWIN; ++i) {
+        wiener_info[tile_idx].vfilter[i] = rsi.wiener_info[tile_idx].vfilter[i];
+        wiener_info[tile_idx].hfilter[i] = rsi.wiener_info[tile_idx].hfilter[i];
+      }
       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);
     }
+    rsi.wiener_info[tile_idx].level = 0;
   }
   // Cost for Wiener filtering
   bits = frame_level_restore_bits[rsi.frame_restoration_type]
          << AV1_PROB_COST_SHIFT;
   for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
-    bits += av1_cost_bit(RESTORE_NONE_WIENER_PROB, wiener_level[tile_idx]);
-    if (wiener_level[tile_idx])
+    bits += av1_cost_bit(RESTORE_NONE_WIENER_PROB, wiener_info[tile_idx].level);
+    rsi.wiener_info[tile_idx].level = wiener_info[tile_idx].level;
+    if (wiener_info[tile_idx].level) {
       bits += (WIENER_FILT_BITS << AV1_PROB_COST_SHIFT);
-    rsi.wiener_level[tile_idx] = wiener_level[tile_idx];
+      for (i = 0; i < RESTORATION_HALFWIN; ++i) {
+        rsi.wiener_info[tile_idx].vfilter[i] = wiener_info[tile_idx].vfilter[i];
+        rsi.wiener_info[tile_idx].hfilter[i] = wiener_info[tile_idx].hfilter[i];
+      }
+    }
   }
-  // TODO(debargha): This is a pretty inefficient way to find the error
-  // for the whole frame. Specialize for a specific tile.
   err = try_restoration_frame(src, cpi, &rsi, partial_frame);
   cost_wiener = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
-
-  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
-    if (wiener_level[tile_idx] == 0) continue;
-    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];
-    }
-  }
-
-  aom_free(rsi.vfilter);
-  aom_free(rsi.hfilter);
-  aom_free(rsi.wiener_level);
+  aom_free(rsi.wiener_info);
 
   aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
-  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;
-  }
+  return cost_wiener;
 }
 
-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);
+static double search_norestore(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
+                               int filter_level, int partial_frame,
+                               RestorationInfo *info, double *best_tile_cost) {
+  double err, cost_norestore;
+  int bits;
   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;
+  AV1_COMMON *const cm = &cpi->common;
+  int tile_idx, 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)info;
 
   //  Make a copy of the unfiltered / processed recon buffer
   aom_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_uf);
@@ -812,99 +659,86 @@ static int search_switchable_restoration(
                         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 =
+    best_tile_cost[tile_idx] =
         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;
-        }
+  }
+  // RD cost associated with no restoration
+  err = sse_restoration_tile(src, cm, 0, cm->width, 0, cm->height);
+  bits = frame_level_restore_bits[RESTORE_NONE] << AV1_PROB_COST_SHIFT;
+  cost_norestore = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
+  aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
+  return cost_norestore;
+}
+
+static double search_switchable_restoration(
+    AV1_COMP *cpi, int filter_level, int partial_frame, RestorationInfo *rsi,
+    double *tile_cost[RESTORE_SWITCHABLE_TYPES]) {
+  AV1_COMMON *const cm = &cpi->common;
+  MACROBLOCK *x = &cpi->td.mb;
+  double cost_switchable = 0;
+  int r, bits, tile_idx;
+  const int ntiles =
+      av1_get_rest_ntiles(cm->width, cm->height, NULL, NULL, NULL, NULL);
+
+  //  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);
+
+  rsi->frame_restoration_type = RESTORE_SWITCHABLE;
+  bits = frame_level_restore_bits[rsi->frame_restoration_type]
+         << AV1_PROB_COST_SHIFT;
+  cost_switchable = RDCOST_DBL(x->rdmult, x->rddiv, bits >> 4, 0);
+  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
+    double best_cost = tile_cost[RESTORE_NONE][tile_idx];
+    rsi->restoration_type[tile_idx] = RESTORE_NONE;
+    for (r = 1; r < RESTORE_SWITCHABLE_TYPES; r++) {
+      if (tile_cost[r][tile_idx] < best_cost) {
+        rsi->restoration_type[tile_idx] = r;
+        best_cost = tile_cost[r][tile_idx];
       }
     }
-    bits += cpi->switchable_restore_cost[rsi->restoration_type[tile_idx]];
+    cost_switchable += best_cost;
   }
-  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;
-  }
+  return cost_switchable;
 }
 
 void av1_pick_filter_restoration(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
                                  LPF_PICK_METHOD method) {
+  static search_restore_type search_restore_fun[RESTORE_SWITCHABLE_TYPES] = {
+    search_norestore, search_bilateral, search_wiener,
+  };
   AV1_COMMON *const cm = &cpi->common;
   struct loopfilter *const lf = &cm->lf;
-  int wiener_success = 0;
-  int bilateral_success = 0;
-  int switchable_success = 0;
-  double cost_bilateral = DBL_MAX;
-  double cost_wiener = DBL_MAX;
-  // double cost_norestore = DBL_MAX;
-  double cost_switchable = DBL_MAX;
-  double *tile_cost_bilateral, *tile_cost_wiener;
+  double cost_restore[RESTORE_TYPES];
+  double *tile_cost[RESTORE_SWITCHABLE_TYPES];
+  double best_cost_restore;
+  RestorationType r, best_restore;
+
   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);
-  assert(cm->rst_info.bilateral_level != NULL);
-
-  cm->rst_info.wiener_level = (int *)aom_realloc(
-      cm->rst_info.wiener_level, sizeof(*cm->rst_info.wiener_level) * ntiles);
-  assert(cm->rst_info.wiener_level != NULL);
-  cm->rst_info.vfilter = (int(*)[RESTORATION_WIN])aom_realloc(
-      cm->rst_info.vfilter, sizeof(*cm->rst_info.vfilter) * ntiles);
-  assert(cm->rst_info.vfilter != NULL);
-  cm->rst_info.hfilter = (int(*)[RESTORATION_WIN])aom_realloc(
-      cm->rst_info.hfilter, sizeof(*cm->rst_info.hfilter) * ntiles);
-  assert(cm->rst_info.hfilter != NULL);
-  tile_cost_wiener = (double *)aom_malloc(sizeof(cost_wiener) * ntiles);
-  tile_cost_bilateral = (double *)aom_malloc(sizeof(cost_bilateral) * ntiles);
+  cm->rst_info.bilateral_info = (BilateralInfo *)aom_realloc(
+      cm->rst_info.bilateral_info,
+      sizeof(*cm->rst_info.bilateral_info) * ntiles);
+  assert(cm->rst_info.bilateral_info != NULL);
+  cm->rst_info.wiener_info = (WienerInfo *)aom_realloc(
+      cm->rst_info.wiener_info, sizeof(*cm->rst_info.wiener_info) * ntiles);
+  assert(cm->rst_info.wiener_info != NULL);
+
+  for (r = 0; r < RESTORE_SWITCHABLE_TYPES; r++)
+    tile_cost[r] = (double *)aom_malloc(sizeof(*tile_cost[0]) * ntiles);
 
   lf->sharpness_level = cm->frame_type == KEY_FRAME ? 0 : cpi->oxcf.sharpness;
 
@@ -940,52 +774,34 @@ void av1_pick_filter_restoration(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
 #endif  // CONFIG_AOM_HIGHBITDEPTH
     if (cm->frame_type == KEY_FRAME) filt_guess -= 4;
     lf->filter_level = clamp(filt_guess, min_filter_level, max_filter_level);
-    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);
-    wiener_success = search_wiener_filter(
-        src, cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE,
-        cm->rst_info.vfilter, cm->rst_info.hfilter, cm->rst_info.wiener_level,
-        &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);
   } else {
-    // 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);
-    bilateral_success = search_filter_bilateral_level(
-        src, cpi, method == LPF_PICK_FROM_SUBIMAGE, &lf->filter_level,
-        cm->rst_info.bilateral_level, &cost_bilateral, tile_cost_bilateral);
-    wiener_success = search_wiener_filter(
-        src, cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE,
-        cm->rst_info.vfilter, cm->rst_info.hfilter, cm->rst_info.wiener_level,
-        &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;
+    lf->filter_level =
+        av1_search_filter_level(src, cpi, method == LPF_PICK_FROM_SUBIMAGE,
+                                &cost_restore[RESTORE_NONE]);
+  }
+  for (r = 0; r < RESTORE_SWITCHABLE_TYPES; ++r) {
+    cost_restore[r] = search_restore_fun[r](src, cpi, lf->filter_level,
+                                            method == LPF_PICK_FROM_SUBIMAGE,
+                                            &cm->rst_info, tile_cost[r]);
+  }
+  cost_restore[RESTORE_SWITCHABLE] = search_switchable_restoration(
+      cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE, &cm->rst_info,
+      tile_cost);
+
+  best_cost_restore = DBL_MAX;
+  best_restore = 0;
+  for (r = 0; r < RESTORE_TYPES; ++r) {
+    if (cost_restore[r] < best_cost_restore) {
+      best_restore = r;
+      best_cost_restore = cost_restore[r];
+    }
   }
-  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);
+  cm->rst_info.frame_restoration_type = best_restore;
+  /*
+  printf("Frame %d/%d frame_restore_type %d : %f %f %f %f\n",
+         cm->current_video_frame, cm->show_frame,
+         cm->rst_info.frame_restoration_type,
+         cost_restore[0], cost_restore[1], cost_restore[2], cost_restore[3]);
+         */
+  for (r = 0; r < RESTORE_SWITCHABLE_TYPES; r++) aom_free(tile_cost[r]);
 }