Dual deblocking filter strength thresholds

A new experiment for deblocking filter that separates vertical
and horizontal filter strengths. This experiment is based on the
assumption that non-flatness characteristics of vertical and
horizontal direction may differ. Therefore selecting different
filter strengths for vertical and horizontal can improve deblocking
performance.

The process of finding proper filter strength:
1. Search through the filter level under the constraint that
   (vertical == horizontal), and find the best solution.
2. Fix vertical level as the best solution found in step 1 and vary
   horizontal level to find the best value.
3. Fix the selected horizontal level, vary vertical level to find
   its best value.

The experiment is working with UV_LVL, sharing the same config flag.
The searching for horizontal and vertical filter strength only applies
on Y plane for now.

The experimental flag should be changed to filter_level later.

Change-Id: I164eec8d3ccb3da7ff109c5c55f4b52c1536ddf1
diff --git a/av1/encoder/picklpf.c b/av1/encoder/picklpf.c
index da15d6a..73cf256 100644
--- a/av1/encoder/picklpf.c
+++ b/av1/encoder/picklpf.c
@@ -51,7 +51,7 @@
                                 int partial_frame
 #if CONFIG_UV_LVL
                                 ,
-                                int plane
+                                int plane, int dir
 #endif
                                 ) {
   AV1_COMMON *const cm = &cpi->common;
@@ -60,8 +60,12 @@
 #if CONFIG_VAR_TX || CONFIG_EXT_PARTITION || CONFIG_CB4X4
 #if CONFIG_UV_LVL
   assert(plane >= 0 && plane <= 2);
-  av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filt_level,
-                        plane, partial_frame);
+  int filter_level[2] = { filt_level, filt_level };
+  if (plane == 0 && dir == 0) filter_level[1] = cm->lf.filter_level[1];
+  if (plane == 0 && dir == 1) filter_level[0] = cm->lf.filter_level[0];
+
+  av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd,
+                        filter_level[0], filter_level[1], plane, partial_frame);
 #else
   av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filt_level, 1,
                         partial_frame);
@@ -100,7 +104,7 @@
                             int partial_frame, double *best_cost_ret
 #if CONFIG_UV_LVL
                             ,
-                            int plane
+                            int plane, int dir
 #endif
                             ) {
   const AV1_COMMON *const cm = &cpi->common;
@@ -117,7 +121,7 @@
 #if CONFIG_UV_LVL
   int lvl;
   switch (plane) {
-    case 0: lvl = lf->filter_level; break;
+    case 0: lvl = (dir == 1) ? lf->filter_level[1] : lf->filter_level[0]; break;
     case 1: lvl = lf->filter_level_u; break;
     case 2: lvl = lf->filter_level_v; break;
     default: assert(plane >= 0 && plane <= 2); return 0;
@@ -141,7 +145,7 @@
 #endif  // CONFIG_UV_LVL
 
 #if CONFIG_UV_LVL
-  best_err = try_filter_frame(sd, cpi, filt_mid, partial_frame, plane);
+  best_err = try_filter_frame(sd, cpi, filt_mid, partial_frame, plane, dir);
 #else
   best_err = try_filter_frame(sd, cpi, filt_mid, partial_frame);
 #endif  // CONFIG_UV_LVL
@@ -166,7 +170,7 @@
       if (ss_err[filt_low] < 0) {
 #if CONFIG_UV_LVL
         ss_err[filt_low] =
-            try_filter_frame(sd, cpi, filt_low, partial_frame, plane);
+            try_filter_frame(sd, cpi, filt_low, partial_frame, plane, dir);
 #else
         ss_err[filt_low] = try_filter_frame(sd, cpi, filt_low, partial_frame);
 #endif  // CONFIG_UV_LVL
@@ -187,7 +191,7 @@
       if (ss_err[filt_high] < 0) {
 #if CONFIG_UV_LVL
         ss_err[filt_high] =
-            try_filter_frame(sd, cpi, filt_high, partial_frame, plane);
+            try_filter_frame(sd, cpi, filt_high, partial_frame, plane, dir);
 #else
         ss_err[filt_high] = try_filter_frame(sd, cpi, filt_high, partial_frame);
 #endif  // CONFIG_UV_LVL
@@ -224,8 +228,13 @@
 
   lf->sharpness_level = cm->frame_type == KEY_FRAME ? 0 : cpi->oxcf.sharpness;
 
-  if (method == LPF_PICK_MINIMAL_LPF && lf->filter_level) {
+  if (method == LPF_PICK_MINIMAL_LPF) {
+#if CONFIG_UV_LVL
+    lf->filter_level[0] = 0;
+    lf->filter_level[1] = 0;
+#else
     lf->filter_level = 0;
+#endif
   } else if (method >= LPF_PICK_FROM_Q) {
     const int min_filter_level = 0;
     const int max_filter_level = av1_get_max_filter_level(cpi);
@@ -254,15 +263,25 @@
     int filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 1015158, 18);
 #endif  // CONFIG_HIGHBITDEPTH
     if (cm->frame_type == KEY_FRAME) filt_guess -= 4;
+#if CONFIG_UV_LVL
+    lf->filter_level[0] = clamp(filt_guess, min_filter_level, max_filter_level);
+    lf->filter_level[1] = clamp(filt_guess, min_filter_level, max_filter_level);
+#else
     lf->filter_level = clamp(filt_guess, min_filter_level, max_filter_level);
+#endif
   } else {
 #if CONFIG_UV_LVL
-    lf->filter_level = av1_search_filter_level(
-        sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, NULL, 0);
+    lf->filter_level[0] = lf->filter_level[1] = av1_search_filter_level(
+        sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, NULL, 0, 2);
+    lf->filter_level[0] = av1_search_filter_level(
+        sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, NULL, 0, 0);
+    lf->filter_level[1] = av1_search_filter_level(
+        sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, NULL, 0, 1);
+
     lf->filter_level_u = av1_search_filter_level(
-        sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, NULL, 1);
+        sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, NULL, 1, 0);
     lf->filter_level_v = av1_search_filter_level(
-        sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, NULL, 2);
+        sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, NULL, 2, 0);
 #else
     lf->filter_level = av1_search_filter_level(
         sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, NULL);