1 /*
2  * Copyright (c) 2016, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 2 Clause License and
5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6  * was not distributed with this source code in the LICENSE file, you can
7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8  * Media Patent License 1.0 was not distributed with this source code in the
9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10  */
11 
12 #include <assert.h>
13 #include <limits.h>
14 
15 #include "./aom_scale_rtcd.h"
16 
17 #include "aom_dsp/aom_dsp_common.h"
18 #include "aom_dsp/psnr.h"
19 #include "aom_mem/aom_mem.h"
20 #include "aom_ports/mem.h"
21 
22 #include "av1/common/av1_loopfilter.h"
23 #include "av1/common/onyxc_int.h"
24 #include "av1/common/quant_common.h"
25 
26 #include "av1/encoder/av1_quantize.h"
27 #include "av1/encoder/encoder.h"
28 #include "av1/encoder/picklpf.h"
29 
30 #if CONFIG_LPF_SB
31 #if CONFIG_HIGHBITDEPTH
compute_sb_y_sse_highbd(const YV12_BUFFER_CONFIG * src,const YV12_BUFFER_CONFIG * frame,AV1_COMMON * const cm,int mi_row,int mi_col)32 static int compute_sb_y_sse_highbd(const YV12_BUFFER_CONFIG *src,
33                                    const YV12_BUFFER_CONFIG *frame,
34                                    AV1_COMMON *const cm, int mi_row,
35                                    int mi_col) {
36   int sse = 0;
37   const int mi_row_start = AOMMAX(0, mi_row - FILT_BOUNDARY_MI_OFFSET);
38   const int mi_col_start = AOMMAX(0, mi_col - FILT_BOUNDARY_MI_OFFSET);
39   const int mi_row_range = mi_row - FILT_BOUNDARY_MI_OFFSET + MAX_MIB_SIZE;
40   const int mi_col_range = mi_col - FILT_BOUNDARY_MI_OFFSET + MAX_MIB_SIZE;
41   const int mi_row_end = AOMMIN(mi_row_range, cm->mi_rows);
42   const int mi_col_end = AOMMIN(mi_col_range, cm->mi_cols);
43 
44   const int row = mi_row_start * MI_SIZE;
45   const int col = mi_col_start * MI_SIZE;
46   const uint16_t *src_y =
47       CONVERT_TO_SHORTPTR(src->y_buffer) + row * src->y_stride + col;
48   const uint16_t *frame_y =
49       CONVERT_TO_SHORTPTR(frame->y_buffer) + row * frame->y_stride + col;
50   const int row_end = (mi_row_end - mi_row_start) * MI_SIZE;
51   const int col_end = (mi_col_end - mi_col_start) * MI_SIZE;
52 
53   int x, y;
54   for (y = 0; y < row_end; ++y) {
55     for (x = 0; x < col_end; ++x) {
56       const int diff = src_y[x] - frame_y[x];
57       sse += diff * diff;
58     }
59     src_y += src->y_stride;
60     frame_y += frame->y_stride;
61   }
62   return sse;
63 }
64 #endif
65 
compute_sb_y_sse(const YV12_BUFFER_CONFIG * src,const YV12_BUFFER_CONFIG * frame,AV1_COMMON * const cm,int mi_row,int mi_col)66 static int compute_sb_y_sse(const YV12_BUFFER_CONFIG *src,
67                             const YV12_BUFFER_CONFIG *frame,
68                             AV1_COMMON *const cm, int mi_row, int mi_col) {
69   int sse = 0;
70   const int mi_row_start = AOMMAX(0, mi_row - FILT_BOUNDARY_MI_OFFSET);
71   const int mi_col_start = AOMMAX(0, mi_col - FILT_BOUNDARY_MI_OFFSET);
72   const int mi_row_range = mi_row - FILT_BOUNDARY_MI_OFFSET + MAX_MIB_SIZE;
73   const int mi_col_range = mi_col - FILT_BOUNDARY_MI_OFFSET + MAX_MIB_SIZE;
74   const int mi_row_end = AOMMIN(mi_row_range, cm->mi_rows);
75   const int mi_col_end = AOMMIN(mi_col_range, cm->mi_cols);
76 
77   const int row = mi_row_start * MI_SIZE;
78   const int col = mi_col_start * MI_SIZE;
79   const uint8_t *src_y = src->y_buffer + row * src->y_stride + col;
80   const uint8_t *frame_y = frame->y_buffer + row * frame->y_stride + col;
81   const int row_end = (mi_row_end - mi_row_start) * MI_SIZE;
82   const int col_end = (mi_col_end - mi_col_start) * MI_SIZE;
83 
84   int x, y;
85   for (y = 0; y < row_end; ++y) {
86     for (x = 0; x < col_end; ++x) {
87       const int diff = src_y[x] - frame_y[x];
88       sse += diff * diff;
89     }
90     src_y += src->y_stride;
91     frame_y += frame->y_stride;
92   }
93   return sse;
94 }
95 #endif  // CONFIG_LPF_SB
96 
97 #if !CONFIG_LPF_SB
yv12_copy_plane(const YV12_BUFFER_CONFIG * src_bc,YV12_BUFFER_CONFIG * dst_bc,int plane)98 static void yv12_copy_plane(const YV12_BUFFER_CONFIG *src_bc,
99                             YV12_BUFFER_CONFIG *dst_bc, int plane) {
100   switch (plane) {
101     case 0: aom_yv12_copy_y(src_bc, dst_bc); break;
102     case 1: aom_yv12_copy_u(src_bc, dst_bc); break;
103     case 2: aom_yv12_copy_v(src_bc, dst_bc); break;
104     default: assert(plane >= 0 && plane <= 2); break;
105   }
106 }
107 #endif  // CONFIG_LPF_SB
108 
av1_get_max_filter_level(const AV1_COMP * cpi)109 int av1_get_max_filter_level(const AV1_COMP *cpi) {
110   if (cpi->oxcf.pass == 2) {
111     return cpi->twopass.section_intra_rating > 8 ? MAX_LOOP_FILTER * 3 / 4
112                                                  : MAX_LOOP_FILTER;
113   } else {
114     return MAX_LOOP_FILTER;
115   }
116 }
117 
118 #if CONFIG_LPF_SB
119 // TODO(chengchen): reduce memory usage by copy superblock instead of frame
try_filter_superblock(const YV12_BUFFER_CONFIG * sd,AV1_COMP * const cpi,int filt_level,int partial_frame,int mi_row,int mi_col)120 static int try_filter_superblock(const YV12_BUFFER_CONFIG *sd,
121                                  AV1_COMP *const cpi, int filt_level,
122                                  int partial_frame, int mi_row, int mi_col) {
123   AV1_COMMON *const cm = &cpi->common;
124   int filt_err;
125 
126 #if CONFIG_VAR_TX || CONFIG_EXT_PARTITION || CONFIG_CB4X4
127   av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filt_level, 1,
128                         partial_frame, mi_row, mi_col);
129 #else
130   if (cpi->num_workers > 1)
131     av1_loop_filter_frame_mt(cm->frame_to_show, cm, cpi->td.mb.e_mbd.plane,
132                              filt_level, 1, partial_frame, cpi->workers,
133                              cpi->num_workers, &cpi->lf_row_sync);
134   else
135     av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filt_level,
136                           1, partial_frame);
137 #endif
138 
139 #if CONFIG_HIGHBITDEPTH
140   if (cm->use_highbitdepth) {
141     filt_err =
142         compute_sb_y_sse_highbd(sd, cm->frame_to_show, cm, mi_row, mi_col);
143   } else {
144     filt_err = compute_sb_y_sse(sd, cm->frame_to_show, cm, mi_row, mi_col);
145   }
146 #else
147   filt_err = compute_sb_y_sse(sd, cm->frame_to_show, cm, mi_row, mi_col);
148 #endif  // CONFIG_HIGHBITDEPTH
149 
150   // TODO(chengchen): Copy the superblock only
151   // Re-instate the unfiltered frame
152   aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
153 
154   return filt_err;
155 }
156 
search_filter_level(const YV12_BUFFER_CONFIG * sd,AV1_COMP * cpi,int partial_frame,double * best_cost_ret,int mi_row,int mi_col,int last_lvl)157 static int search_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi,
158                                int partial_frame, double *best_cost_ret,
159                                int mi_row, int mi_col, int last_lvl) {
160   assert(partial_frame == 1);
161   assert(last_lvl >= 0);
162 
163   const AV1_COMMON *const cm = &cpi->common;
164   MACROBLOCK *x = &cpi->td.mb;
165 
166   int min_filter_level = AOMMAX(0, last_lvl - MAX_LPF_OFFSET);
167   int max_filter_level =
168       AOMMIN(av1_get_max_filter_level(cpi), last_lvl + MAX_LPF_OFFSET);
169 
170   // search a larger range for the start superblock
171   if (mi_row == 0 && mi_col == 0) {
172     min_filter_level = 0;
173     max_filter_level = av1_get_max_filter_level(cpi);
174   }
175 
176   // TODO(chengchen): Copy for superblock only
177   // Make a copy of the unfiltered / processed recon buffer
178   aom_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_uf);
179 
180   int estimate_err =
181       try_filter_superblock(sd, cpi, last_lvl, partial_frame, mi_row, mi_col);
182 
183   int best_err = estimate_err;
184   int filt_best = last_lvl;
185 
186   int i;
187   for (i = min_filter_level; i <= max_filter_level; i += LPF_STEP) {
188     if (i == last_lvl) continue;
189 
190     int filt_err =
191         try_filter_superblock(sd, cpi, i, partial_frame, mi_row, mi_col);
192 
193     if (filt_err < best_err) {
194       best_err = filt_err;
195       filt_best = i;
196     }
197   }
198 
199   // If previous sb filter level has similar filtering performance as current
200   // best filter level, use previous level such that we can only send one bit
201   // to indicate current filter level is the same as the previous.
202   int threshold = 400;
203 
204   // ratio = the filtering area / a superblock size
205   int ratio = 1;
206   if (mi_row + MAX_MIB_SIZE > cm->mi_rows) {
207     ratio *= (cm->mi_rows - mi_row);
208   } else {
209     if (mi_row == 0) {
210       ratio *= (MAX_MIB_SIZE - FILT_BOUNDARY_MI_OFFSET);
211     } else {
212       ratio *= MAX_MIB_SIZE;
213     }
214   }
215   if (mi_col + MAX_MIB_SIZE > cm->mi_cols) {
216     ratio *= (cm->mi_cols - mi_col);
217   } else {
218     if (mi_col == 0) {
219       ratio *= (MAX_MIB_SIZE - FILT_BOUNDARY_MI_OFFSET);
220     } else {
221       ratio *= MAX_MIB_SIZE;
222     }
223   }
224   threshold = threshold * ratio / (MAX_MIB_SIZE * MAX_MIB_SIZE);
225 
226   const int diff = abs(estimate_err - best_err);
227 
228   const int percent_thresh = (int)((double)estimate_err * 0.01);
229   threshold = AOMMAX(threshold, percent_thresh);
230   if (diff < threshold) {
231     best_err = estimate_err;
232     filt_best = last_lvl;
233   }
234 
235   // Compute rdcost to determine whether to reuse previous filter lvl
236   if (filt_best != last_lvl) {
237   }
238 
239   if (best_cost_ret) *best_cost_ret = RDCOST_DBL(x->rdmult, 0, best_err);
240   return filt_best;
241 }
242 
243 #else  // CONFIG_LPF_SB
try_filter_frame(const YV12_BUFFER_CONFIG * sd,AV1_COMP * const cpi,int filt_level,int partial_frame,int plane,int dir)244 static int64_t try_filter_frame(const YV12_BUFFER_CONFIG *sd,
245                                 AV1_COMP *const cpi, int filt_level,
246                                 int partial_frame
247 #if CONFIG_LOOPFILTER_LEVEL
248                                 ,
249                                 int plane, int dir
250 #endif
251                                 ) {
252   AV1_COMMON *const cm = &cpi->common;
253   int64_t filt_err;
254 
255 #if CONFIG_VAR_TX || CONFIG_EXT_PARTITION || CONFIG_CB4X4
256 #if CONFIG_LOOPFILTER_LEVEL
257   assert(plane >= 0 && plane <= 2);
258   int filter_level[2] = { filt_level, filt_level };
259   if (plane == 0 && dir == 0) filter_level[1] = cm->lf.filter_level[1];
260   if (plane == 0 && dir == 1) filter_level[0] = cm->lf.filter_level[0];
261 
262   av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd,
263                         filter_level[0], filter_level[1], plane, partial_frame);
264 #else
265   av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filt_level, 1,
266                         partial_frame);
267 #endif  // CONFIG_LOOPFILTER_LEVEL
268 #else
269   if (cpi->num_workers > 1)
270     av1_loop_filter_frame_mt(cm->frame_to_show, cm, cpi->td.mb.e_mbd.plane,
271                              filt_level, 1, partial_frame, cpi->workers,
272                              cpi->num_workers, &cpi->lf_row_sync);
273   else
274     av1_loop_filter_frame(cm->frame_to_show, cm, &cpi->td.mb.e_mbd, filt_level,
275                           1, partial_frame);
276 #endif
277 
278   int highbd = 0;
279 #if CONFIG_HIGHBITDEPTH
280   highbd = cm->use_highbitdepth;
281 #endif  // CONFIG_HIGHBITDEPTH
282 
283 #if CONFIG_LOOPFILTER_LEVEL
284   filt_err = aom_get_sse_plane(sd, cm->frame_to_show, plane, highbd);
285 
286   // Re-instate the unfiltered frame
287   yv12_copy_plane(&cpi->last_frame_uf, cm->frame_to_show, plane);
288 #else
289   filt_err = aom_get_sse_plane(sd, cm->frame_to_show, 0, highbd);
290 
291   // Re-instate the unfiltered frame
292   yv12_copy_plane(&cpi->last_frame_uf, cm->frame_to_show, 0);
293 #endif  // CONFIG_LOOPFILTER_LEVEL
294 
295   return filt_err;
296 }
297 
search_filter_level(const YV12_BUFFER_CONFIG * sd,AV1_COMP * cpi,int partial_frame,double * best_cost_ret,int plane,int dir)298 static int search_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi,
299                                int partial_frame, double *best_cost_ret
300 #if CONFIG_LOOPFILTER_LEVEL
301                                ,
302                                int plane, int dir
303 #endif
304                                ) {
305   const AV1_COMMON *const cm = &cpi->common;
306   const struct loopfilter *const lf = &cm->lf;
307   const int min_filter_level = 0;
308   const int max_filter_level = av1_get_max_filter_level(cpi);
309   int filt_direction = 0;
310   int64_t best_err;
311   int filt_best;
312   MACROBLOCK *x = &cpi->td.mb;
313 
314 // Start the search at the previous frame filter level unless it is now out of
315 // range.
316 #if CONFIG_LOOPFILTER_LEVEL
317   int lvl;
318   switch (plane) {
319     case 0: lvl = (dir == 1) ? lf->filter_level[1] : lf->filter_level[0]; break;
320     case 1: lvl = lf->filter_level_u; break;
321     case 2: lvl = lf->filter_level_v; break;
322     default: assert(plane >= 0 && plane <= 2); return 0;
323   }
324   int filt_mid = clamp(lvl, min_filter_level, max_filter_level);
325 #else
326   int filt_mid = clamp(lf->filter_level, min_filter_level, max_filter_level);
327 #endif  // CONFIG_LOOPFILTER_LEVEL
328   int filter_step = filt_mid < 16 ? 4 : filt_mid / 4;
329   // Sum squared error at each filter level
330   int64_t ss_err[MAX_LOOP_FILTER + 1];
331 
332   // Set each entry to -1
333   memset(ss_err, 0xFF, sizeof(ss_err));
334 
335 #if CONFIG_LOOPFILTER_LEVEL
336   yv12_copy_plane(cm->frame_to_show, &cpi->last_frame_uf, plane);
337 #else
338   //  Make a copy of the unfiltered / processed recon buffer
339   aom_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_uf);
340 #endif  // CONFIG_LOOPFILTER_LEVEL
341 
342 #if CONFIG_LOOPFILTER_LEVEL
343   best_err = try_filter_frame(sd, cpi, filt_mid, partial_frame, plane, dir);
344 #else
345   best_err = try_filter_frame(sd, cpi, filt_mid, partial_frame);
346 #endif  // CONFIG_LOOPFILTER_LEVEL
347   filt_best = filt_mid;
348   ss_err[filt_mid] = best_err;
349 
350   while (filter_step > 0) {
351     const int filt_high = AOMMIN(filt_mid + filter_step, max_filter_level);
352     const int filt_low = AOMMAX(filt_mid - filter_step, min_filter_level);
353 
354     // Bias against raising loop filter in favor of lowering it.
355     int64_t bias = (best_err >> (15 - (filt_mid / 8))) * filter_step;
356 
357     if ((cpi->oxcf.pass == 2) && (cpi->twopass.section_intra_rating < 20))
358       bias = (bias * cpi->twopass.section_intra_rating) / 20;
359 
360     // yx, bias less for large block size
361     if (cm->tx_mode != ONLY_4X4) bias >>= 1;
362 
363     if (filt_direction <= 0 && filt_low != filt_mid) {
364       // Get Low filter error score
365       if (ss_err[filt_low] < 0) {
366 #if CONFIG_LOOPFILTER_LEVEL
367         ss_err[filt_low] =
368             try_filter_frame(sd, cpi, filt_low, partial_frame, plane, dir);
369 #else
370         ss_err[filt_low] = try_filter_frame(sd, cpi, filt_low, partial_frame);
371 #endif  // CONFIG_LOOPFILTER_LEVEL
372       }
373       // If value is close to the best so far then bias towards a lower loop
374       // filter value.
375       if (ss_err[filt_low] < (best_err + bias)) {
376         // Was it actually better than the previous best?
377         if (ss_err[filt_low] < best_err) {
378           best_err = ss_err[filt_low];
379         }
380         filt_best = filt_low;
381       }
382     }
383 
384     // Now look at filt_high
385     if (filt_direction >= 0 && filt_high != filt_mid) {
386       if (ss_err[filt_high] < 0) {
387 #if CONFIG_LOOPFILTER_LEVEL
388         ss_err[filt_high] =
389             try_filter_frame(sd, cpi, filt_high, partial_frame, plane, dir);
390 #else
391         ss_err[filt_high] = try_filter_frame(sd, cpi, filt_high, partial_frame);
392 #endif  // CONFIG_LOOPFILTER_LEVEL
393       }
394       // If value is significantly better than previous best, bias added against
395       // raising filter value
396       if (ss_err[filt_high] < (best_err - bias)) {
397         best_err = ss_err[filt_high];
398         filt_best = filt_high;
399       }
400     }
401 
402     // Half the step distance if the best filter value was the same as last time
403     if (filt_best == filt_mid) {
404       filter_step /= 2;
405       filt_direction = 0;
406     } else {
407       filt_direction = (filt_best < filt_mid) ? -1 : 1;
408       filt_mid = filt_best;
409     }
410   }
411 
412   // Update best error
413   best_err = ss_err[filt_best];
414 
415   if (best_cost_ret) *best_cost_ret = RDCOST_DBL(x->rdmult, 0, best_err);
416   return filt_best;
417 }
418 #endif  // CONFIG_LPF_SB
419 
av1_pick_filter_level(const YV12_BUFFER_CONFIG * sd,AV1_COMP * cpi,LPF_PICK_METHOD method)420 void av1_pick_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi,
421                            LPF_PICK_METHOD method) {
422   AV1_COMMON *const cm = &cpi->common;
423   struct loopfilter *const lf = &cm->lf;
424 
425   lf->sharpness_level = cm->frame_type == KEY_FRAME ? 0 : cpi->oxcf.sharpness;
426 
427   if (method == LPF_PICK_MINIMAL_LPF) {
428 #if CONFIG_LOOPFILTER_LEVEL
429     lf->filter_level[0] = 0;
430     lf->filter_level[1] = 0;
431 #else
432     lf->filter_level = 0;
433 #endif
434   } else if (method >= LPF_PICK_FROM_Q) {
435     const int min_filter_level = 0;
436     const int max_filter_level = av1_get_max_filter_level(cpi);
437     const int q = av1_ac_quant(cm->base_qindex, 0, cm->bit_depth);
438 // These values were determined by linear fitting the result of the
439 // searched level, filt_guess = q * 0.316206 + 3.87252
440 #if CONFIG_HIGHBITDEPTH
441     int filt_guess;
442     switch (cm->bit_depth) {
443       case AOM_BITS_8:
444         filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 1015158, 18);
445         break;
446       case AOM_BITS_10:
447         filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 4060632, 20);
448         break;
449       case AOM_BITS_12:
450         filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 16242526, 22);
451         break;
452       default:
453         assert(0 &&
454                "bit_depth should be AOM_BITS_8, AOM_BITS_10 "
455                "or AOM_BITS_12");
456         return;
457     }
458 #else
459     int filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 1015158, 18);
460 #endif  // CONFIG_HIGHBITDEPTH
461     if (cm->frame_type == KEY_FRAME) filt_guess -= 4;
462 #if CONFIG_LOOPFILTER_LEVEL
463     lf->filter_level[0] = clamp(filt_guess, min_filter_level, max_filter_level);
464     lf->filter_level[1] = clamp(filt_guess, min_filter_level, max_filter_level);
465 #else
466     lf->filter_level = clamp(filt_guess, min_filter_level, max_filter_level);
467 #endif
468   } else {
469 #if CONFIG_LPF_SB
470     int mi_row, mi_col;
471     // TODO(chengchen): init last_lvl using previous frame's info?
472     int last_lvl = 0;
473     // TODO(chengchen): if the frame size makes the last superblock very small,
474     // consider merge it to the previous superblock to save bits.
475     // Example, if frame size 1080x720, then in the last row of superblock,
476     // there're (FILT_BOUNDAR_OFFSET + 16) pixels.
477     for (mi_row = 0; mi_row < cm->mi_rows; mi_row += MAX_MIB_SIZE) {
478       for (mi_col = 0; mi_col < cm->mi_cols; mi_col += MAX_MIB_SIZE) {
479         int lvl =
480             search_filter_level(sd, cpi, 1, NULL, mi_row, mi_col, last_lvl);
481 
482         av1_loop_filter_sb_level_init(cm, mi_row, mi_col, lvl);
483 
484         // For the superblock at row start, its previous filter level should be
485         // the one above it, not the one at the end of last row
486         if (mi_col + MAX_MIB_SIZE >= cm->mi_cols) {
487           last_lvl = cm->mi_grid_visible[mi_row * cm->mi_stride]->mbmi.filt_lvl;
488         } else {
489           last_lvl = lvl;
490         }
491       }
492     }
493 #else  // CONFIG_LPF_SB
494 #if CONFIG_LOOPFILTER_LEVEL
495     lf->filter_level[0] = lf->filter_level[1] = search_filter_level(
496         sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, NULL, 0, 2);
497     lf->filter_level[0] = search_filter_level(
498         sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, NULL, 0, 0);
499     lf->filter_level[1] = search_filter_level(
500         sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, NULL, 0, 1);
501 
502     lf->filter_level_u = search_filter_level(
503         sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, NULL, 1, 0);
504     lf->filter_level_v = search_filter_level(
505         sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, NULL, 2, 0);
506 #else
507     lf->filter_level =
508         search_filter_level(sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, NULL);
509 #endif  // CONFIG_LOOPFILTER_LEVEL
510 #endif  // CONFIG_LPF_SB
511   }
512 }
513