/src/aom/av1/encoder/interp_search.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2020, 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 "av1/common/filter.h" |
13 | | #include "av1/common/pred_common.h" |
14 | | #include "av1/encoder/interp_search.h" |
15 | | #include "av1/encoder/model_rd.h" |
16 | | #include "av1/encoder/rdopt_utils.h" |
17 | | #include "av1/encoder/reconinter_enc.h" |
18 | | |
19 | | // return mv_diff |
20 | | static inline int is_interp_filter_good_match( |
21 | | const INTERPOLATION_FILTER_STATS *st, MB_MODE_INFO *const mi, |
22 | 0 | int skip_level) { |
23 | 0 | const int is_comp = has_second_ref(mi); |
24 | 0 | int i; |
25 | |
|
26 | 0 | for (i = 0; i < 1 + is_comp; ++i) { |
27 | 0 | if (st->ref_frames[i] != mi->ref_frame[i]) return INT_MAX; |
28 | 0 | } |
29 | | |
30 | 0 | if (skip_level == 1 && is_comp) { |
31 | 0 | if (st->comp_type != mi->interinter_comp.type) return INT_MAX; |
32 | 0 | if (st->compound_idx != mi->compound_idx) return INT_MAX; |
33 | 0 | } |
34 | | |
35 | 0 | int mv_diff = 0; |
36 | 0 | for (i = 0; i < 1 + is_comp; ++i) { |
37 | 0 | mv_diff += abs(st->mv[i].as_mv.row - mi->mv[i].as_mv.row) + |
38 | 0 | abs(st->mv[i].as_mv.col - mi->mv[i].as_mv.col); |
39 | 0 | } |
40 | 0 | return mv_diff; |
41 | 0 | } |
42 | | |
43 | | static inline int save_interp_filter_search_stat( |
44 | | MB_MODE_INFO *const mbmi, int64_t rd, unsigned int pred_sse, |
45 | | INTERPOLATION_FILTER_STATS *interp_filter_stats, |
46 | 0 | int interp_filter_stats_idx) { |
47 | 0 | if (interp_filter_stats_idx < MAX_INTERP_FILTER_STATS) { |
48 | 0 | INTERPOLATION_FILTER_STATS stat = { mbmi->interp_filters, |
49 | 0 | { mbmi->mv[0], mbmi->mv[1] }, |
50 | 0 | { mbmi->ref_frame[0], |
51 | 0 | mbmi->ref_frame[1] }, |
52 | 0 | mbmi->interinter_comp.type, |
53 | 0 | mbmi->compound_idx, |
54 | 0 | rd, |
55 | 0 | pred_sse }; |
56 | 0 | interp_filter_stats[interp_filter_stats_idx] = stat; |
57 | 0 | interp_filter_stats_idx++; |
58 | 0 | } |
59 | 0 | return interp_filter_stats_idx; |
60 | 0 | } |
61 | | |
62 | | static inline int find_interp_filter_in_stats( |
63 | | MB_MODE_INFO *const mbmi, INTERPOLATION_FILTER_STATS *interp_filter_stats, |
64 | 0 | int interp_filter_stats_idx, int skip_level) { |
65 | | // [skip_levels][single or comp] |
66 | 0 | const int thr[2][2] = { { 0, 0 }, { 3, 7 } }; |
67 | 0 | const int is_comp = has_second_ref(mbmi); |
68 | | |
69 | | // Find good enough match. |
70 | | // TODO(yunqing): Separate single-ref mode and comp mode stats for fast |
71 | | // search. |
72 | 0 | int best = INT_MAX; |
73 | 0 | int match = -1; |
74 | 0 | for (int j = 0; j < interp_filter_stats_idx; ++j) { |
75 | 0 | const INTERPOLATION_FILTER_STATS *st = &interp_filter_stats[j]; |
76 | 0 | const int mv_diff = is_interp_filter_good_match(st, mbmi, skip_level); |
77 | | // Exact match is found. |
78 | 0 | if (mv_diff == 0) { |
79 | 0 | match = j; |
80 | 0 | break; |
81 | 0 | } else if (mv_diff < best && mv_diff <= thr[skip_level - 1][is_comp]) { |
82 | 0 | best = mv_diff; |
83 | 0 | match = j; |
84 | 0 | } |
85 | 0 | } |
86 | |
|
87 | 0 | if (match != -1) { |
88 | 0 | mbmi->interp_filters = interp_filter_stats[match].filters; |
89 | 0 | return match; |
90 | 0 | } |
91 | 0 | return -1; // no match result found |
92 | 0 | } |
93 | | |
94 | | static int find_interp_filter_match( |
95 | | MB_MODE_INFO *const mbmi, const AV1_COMP *const cpi, |
96 | | const InterpFilter assign_filter, const int need_search, |
97 | | INTERPOLATION_FILTER_STATS *interp_filter_stats, |
98 | 0 | int interp_filter_stats_idx) { |
99 | 0 | int match_found_idx = -1; |
100 | 0 | if (cpi->sf.interp_sf.use_interp_filter && need_search) |
101 | 0 | match_found_idx = find_interp_filter_in_stats( |
102 | 0 | mbmi, interp_filter_stats, interp_filter_stats_idx, |
103 | 0 | cpi->sf.interp_sf.use_interp_filter); |
104 | |
|
105 | 0 | if (!need_search || match_found_idx == -1) |
106 | 0 | set_default_interp_filters(mbmi, assign_filter); |
107 | 0 | return match_found_idx; |
108 | 0 | } |
109 | | |
110 | | static inline int get_switchable_rate(MACROBLOCK *const x, |
111 | | const int_interpfilters filters, |
112 | 0 | const int ctx[2], int dual_filter) { |
113 | 0 | const InterpFilter filter0 = filters.as_filters.y_filter; |
114 | 0 | int inter_filter_cost = |
115 | 0 | x->mode_costs.switchable_interp_costs[ctx[0]][filter0]; |
116 | 0 | if (dual_filter) { |
117 | 0 | const InterpFilter filter1 = filters.as_filters.x_filter; |
118 | 0 | inter_filter_cost += x->mode_costs.switchable_interp_costs[ctx[1]][filter1]; |
119 | 0 | } |
120 | 0 | return SWITCHABLE_INTERP_RATE_FACTOR * inter_filter_cost; |
121 | 0 | } |
122 | | |
123 | | // Build inter predictor and calculate model rd |
124 | | // for a given plane. |
125 | | static inline void interp_model_rd_eval( |
126 | | MACROBLOCK *const x, const AV1_COMP *const cpi, BLOCK_SIZE bsize, |
127 | | const BUFFER_SET *const orig_dst, int plane_from, int plane_to, |
128 | 0 | RD_STATS *rd_stats, int is_skip_build_pred) { |
129 | 0 | const AV1_COMMON *cm = &cpi->common; |
130 | 0 | MACROBLOCKD *const xd = &x->e_mbd; |
131 | 0 | RD_STATS tmp_rd_stats; |
132 | 0 | av1_init_rd_stats(&tmp_rd_stats); |
133 | | |
134 | | // Skip inter predictor if the predictor is already available. |
135 | 0 | if (!is_skip_build_pred) { |
136 | 0 | const int mi_row = xd->mi_row; |
137 | 0 | const int mi_col = xd->mi_col; |
138 | 0 | av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, |
139 | 0 | plane_from, plane_to); |
140 | 0 | } |
141 | |
|
142 | 0 | model_rd_sb_fn[cpi->sf.rt_sf.use_simple_rd_model |
143 | 0 | ? MODELRD_LEGACY |
144 | 0 | : MODELRD_TYPE_INTERP_FILTER]( |
145 | 0 | cpi, bsize, x, xd, plane_from, plane_to, &tmp_rd_stats.rate, |
146 | 0 | &tmp_rd_stats.dist, &tmp_rd_stats.skip_txfm, &tmp_rd_stats.sse, NULL, |
147 | 0 | NULL, NULL); |
148 | |
|
149 | 0 | av1_merge_rd_stats(rd_stats, &tmp_rd_stats); |
150 | 0 | } |
151 | | |
152 | | // calculate the rdcost of given interpolation_filter |
153 | | static inline int64_t interpolation_filter_rd( |
154 | | MACROBLOCK *const x, const AV1_COMP *const cpi, |
155 | | const TileDataEnc *tile_data, BLOCK_SIZE bsize, |
156 | | const BUFFER_SET *const orig_dst, int64_t *const rd, |
157 | | RD_STATS *rd_stats_luma, RD_STATS *rd_stats, int *const switchable_rate, |
158 | | const BUFFER_SET *dst_bufs[2], int filter_idx, const int switchable_ctx[2], |
159 | 0 | const int skip_pred) { |
160 | 0 | const AV1_COMMON *cm = &cpi->common; |
161 | 0 | const InterpSearchFlags *interp_search_flags = &cpi->interp_search_flags; |
162 | 0 | const int num_planes = av1_num_planes(cm); |
163 | 0 | MACROBLOCKD *const xd = &x->e_mbd; |
164 | 0 | MB_MODE_INFO *const mbmi = xd->mi[0]; |
165 | 0 | RD_STATS this_rd_stats_luma, this_rd_stats; |
166 | | |
167 | | // Initialize rd_stats structures to default values. |
168 | 0 | av1_init_rd_stats(&this_rd_stats_luma); |
169 | 0 | this_rd_stats = *rd_stats_luma; |
170 | 0 | const int_interpfilters last_best = mbmi->interp_filters; |
171 | 0 | mbmi->interp_filters = filter_sets[filter_idx]; |
172 | |
|
173 | 0 | const int is_sharp = |
174 | 0 | (mbmi->interp_filters.as_filters.x_filter == MULTITAP_SHARP || |
175 | 0 | mbmi->interp_filters.as_filters.y_filter == MULTITAP_SHARP); |
176 | 0 | const int mul = |
177 | 0 | (is_sharp && cpi->sf.interp_sf.use_more_sharp_interp) ? 90 : 100; |
178 | |
|
179 | 0 | const int tmp_rs = |
180 | 0 | get_switchable_rate(x, mbmi->interp_filters, switchable_ctx, |
181 | 0 | cm->seq_params->enable_dual_filter); |
182 | |
|
183 | 0 | int64_t min_rd = RDCOST(x->rdmult, tmp_rs, 0); |
184 | 0 | if (min_rd * mul / 100 > *rd) { |
185 | 0 | mbmi->interp_filters = last_best; |
186 | 0 | return 0; |
187 | 0 | } |
188 | | |
189 | 0 | (void)tile_data; |
190 | |
|
191 | 0 | assert((rd_stats_luma->rate >= 0) && (rd_stats->rate >= 0)); |
192 | 0 | assert((rd_stats_luma->dist >= 0) && (rd_stats->dist >= 0)); |
193 | 0 | assert((rd_stats_luma->sse >= 0) && (rd_stats->sse >= 0)); |
194 | 0 | assert((rd_stats_luma->skip_txfm == 0) || (rd_stats_luma->skip_txfm == 1)); |
195 | 0 | assert((rd_stats->skip_txfm == 0) || (rd_stats->skip_txfm == 1)); |
196 | 0 | assert((skip_pred >= 0) && |
197 | 0 | (skip_pred <= interp_search_flags->default_interp_skip_flags)); |
198 | | |
199 | | // When skip_txfm pred is equal to default_interp_skip_flags, |
200 | | // skip both luma and chroma MC. |
201 | | // For mono-chrome images: |
202 | | // num_planes = 1 and cpi->default_interp_skip_flags = 1, |
203 | | // skip_pred = 1: skip both luma and chroma |
204 | | // skip_pred = 0: Evaluate luma and as num_planes=1, |
205 | | // skip chroma evaluation |
206 | 0 | int tmp_skip_pred = |
207 | 0 | (skip_pred == interp_search_flags->default_interp_skip_flags) |
208 | 0 | ? INTERP_SKIP_LUMA_SKIP_CHROMA |
209 | 0 | : skip_pred; |
210 | 0 | assert(IMPLIES(tmp_skip_pred == INTERP_EVAL_LUMA_SKIP_CHROMA, |
211 | 0 | cpi->sf.interp_sf.skip_model_rd_uv)); |
212 | | |
213 | 0 | if (tmp_skip_pred == INTERP_SKIP_LUMA_SKIP_CHROMA) { |
214 | | // Both luma and chroma evaluation is skipped |
215 | 0 | this_rd_stats = *rd_stats; |
216 | 0 | } else { |
217 | | // Evaluate Luma |
218 | 0 | if (tmp_skip_pred == INTERP_EVAL_LUMA_EVAL_CHROMA || |
219 | 0 | tmp_skip_pred == INTERP_EVAL_LUMA_SKIP_CHROMA) { |
220 | 0 | interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_Y, AOM_PLANE_Y, |
221 | 0 | &this_rd_stats_luma, 0); |
222 | 0 | this_rd_stats = this_rd_stats_luma; |
223 | | #if CONFIG_COLLECT_RD_STATS == 3 |
224 | | RD_STATS rd_stats_y; |
225 | | av1_pick_recursive_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, |
226 | | INT64_MAX); |
227 | | PrintPredictionUnitStats(cpi, tile_data, x, &rd_stats_y, bsize); |
228 | | #endif // CONFIG_COLLECT_RD_STATS == 3 |
229 | 0 | } |
230 | | |
231 | | // Evaluate Chroma |
232 | 0 | if (tmp_skip_pred == INTERP_EVAL_LUMA_EVAL_CHROMA || |
233 | 0 | tmp_skip_pred == INTERP_SKIP_LUMA_EVAL_CHROMA) { |
234 | 0 | for (int plane = 1; plane < num_planes; ++plane) { |
235 | 0 | int64_t tmp_rd = |
236 | 0 | RDCOST(x->rdmult, tmp_rs + this_rd_stats.rate, this_rd_stats.dist); |
237 | 0 | if (tmp_rd * mul / 100 >= *rd) { |
238 | 0 | mbmi->interp_filters = last_best; |
239 | 0 | return 0; |
240 | 0 | } |
241 | 0 | interp_model_rd_eval(x, cpi, bsize, orig_dst, plane, plane, |
242 | 0 | &this_rd_stats, 0); |
243 | 0 | } |
244 | 0 | } |
245 | 0 | } |
246 | | |
247 | 0 | int64_t tmp_rd = |
248 | 0 | RDCOST(x->rdmult, tmp_rs + this_rd_stats.rate, this_rd_stats.dist); |
249 | |
|
250 | 0 | if (tmp_rd * mul / 100 < *rd) { |
251 | 0 | *rd = tmp_rd; |
252 | 0 | *switchable_rate = tmp_rs; |
253 | 0 | if (skip_pred != interp_search_flags->default_interp_skip_flags) { |
254 | 0 | if (skip_pred == INTERP_EVAL_LUMA_EVAL_CHROMA) { |
255 | | // Overwrite the data as current filter is the best one |
256 | 0 | *rd_stats_luma = this_rd_stats_luma; |
257 | 0 | *rd_stats = this_rd_stats; |
258 | | // As luma MC data is computed, no need to recompute after the search |
259 | 0 | x->recalc_luma_mc_data = 0; |
260 | 0 | } else if (skip_pred == INTERP_SKIP_LUMA_EVAL_CHROMA) { |
261 | | // As luma MC data is not computed, update of luma data can be skipped |
262 | 0 | *rd_stats = this_rd_stats; |
263 | | // As luma MC data is not recomputed and current filter is the best, |
264 | | // indicate the possibility of recomputing MC data |
265 | | // If current buffer contains valid MC data, toggle to indicate that |
266 | | // luma MC data needs to be recomputed |
267 | 0 | x->recalc_luma_mc_data ^= 1; |
268 | 0 | } |
269 | 0 | swap_dst_buf(xd, dst_bufs, num_planes); |
270 | 0 | } |
271 | 0 | return 1; |
272 | 0 | } |
273 | 0 | mbmi->interp_filters = last_best; |
274 | 0 | return 0; |
275 | 0 | } |
276 | | |
277 | | static inline INTERP_PRED_TYPE is_pred_filter_search_allowed( |
278 | | const AV1_COMP *const cpi, MACROBLOCKD *xd, BLOCK_SIZE bsize, |
279 | 0 | int_interpfilters *af, int_interpfilters *lf) { |
280 | 0 | const AV1_COMMON *cm = &cpi->common; |
281 | 0 | const MB_MODE_INFO *const above_mbmi = xd->above_mbmi; |
282 | 0 | const MB_MODE_INFO *const left_mbmi = xd->left_mbmi; |
283 | 0 | const int bsl = mi_size_wide_log2[bsize]; |
284 | 0 | int is_horiz_eq = 0, is_vert_eq = 0; |
285 | |
|
286 | 0 | if (above_mbmi && is_inter_block(above_mbmi)) |
287 | 0 | *af = above_mbmi->interp_filters; |
288 | |
|
289 | 0 | if (left_mbmi && is_inter_block(left_mbmi)) *lf = left_mbmi->interp_filters; |
290 | |
|
291 | 0 | if (af->as_filters.x_filter != INTERP_INVALID) |
292 | 0 | is_horiz_eq = af->as_filters.x_filter == lf->as_filters.x_filter; |
293 | 0 | if (af->as_filters.y_filter != INTERP_INVALID) |
294 | 0 | is_vert_eq = af->as_filters.y_filter == lf->as_filters.y_filter; |
295 | |
|
296 | 0 | INTERP_PRED_TYPE pred_filter_type = (is_vert_eq << 1) + is_horiz_eq; |
297 | 0 | const int mi_row = xd->mi_row; |
298 | 0 | const int mi_col = xd->mi_col; |
299 | 0 | int pred_filter_enable = |
300 | 0 | cpi->sf.interp_sf.cb_pred_filter_search |
301 | 0 | ? (((mi_row + mi_col) >> bsl) + |
302 | 0 | get_chessboard_index(cm->current_frame.frame_number)) & |
303 | 0 | 0x1 |
304 | 0 | : 0; |
305 | 0 | pred_filter_enable &= is_horiz_eq || is_vert_eq; |
306 | | // pred_filter_search = 0: pred_filter is disabled |
307 | | // pred_filter_search = 1: pred_filter is enabled and only horz pred matching |
308 | | // pred_filter_search = 2: pred_filter is enabled and only vert pred matching |
309 | | // pred_filter_search = 3: pred_filter is enabled and |
310 | | // both vert, horz pred matching |
311 | 0 | return pred_filter_enable * pred_filter_type; |
312 | 0 | } |
313 | | |
314 | | static DUAL_FILTER_TYPE find_best_interp_rd_facade( |
315 | | MACROBLOCK *const x, const AV1_COMP *const cpi, |
316 | | const TileDataEnc *tile_data, BLOCK_SIZE bsize, |
317 | | const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y, |
318 | | RD_STATS *rd_stats, int *const switchable_rate, |
319 | | const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2], |
320 | 0 | const int skip_pred, uint16_t allow_interp_mask, int is_w4_or_h4) { |
321 | 0 | int tmp_skip_pred = skip_pred; |
322 | 0 | DUAL_FILTER_TYPE best_filt_type = REG_REG; |
323 | | |
324 | | // If no filter are set to be evaluated, return from function |
325 | 0 | if (allow_interp_mask == 0x0) return best_filt_type; |
326 | | // For block width or height is 4, skip the pred evaluation of SHARP_SHARP |
327 | 0 | tmp_skip_pred = is_w4_or_h4 |
328 | 0 | ? cpi->interp_search_flags.default_interp_skip_flags |
329 | 0 | : skip_pred; |
330 | | |
331 | | // Loop over the all filter types and evaluate for only allowed filter types |
332 | 0 | for (int filt_type = SHARP_SHARP; filt_type >= REG_REG; --filt_type) { |
333 | 0 | const int is_filter_allowed = |
334 | 0 | get_interp_filter_allowed_mask(allow_interp_mask, filt_type); |
335 | 0 | if (is_filter_allowed) |
336 | 0 | if (interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd, |
337 | 0 | rd_stats_y, rd_stats, switchable_rate, |
338 | 0 | dst_bufs, filt_type, switchable_ctx, |
339 | 0 | tmp_skip_pred)) |
340 | 0 | best_filt_type = filt_type; |
341 | 0 | tmp_skip_pred = skip_pred; |
342 | 0 | } |
343 | 0 | return best_filt_type; |
344 | 0 | } |
345 | | |
346 | | static inline void pred_dual_interp_filter_rd( |
347 | | MACROBLOCK *const x, const AV1_COMP *const cpi, |
348 | | const TileDataEnc *tile_data, BLOCK_SIZE bsize, |
349 | | const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y, |
350 | | RD_STATS *rd_stats, int *const switchable_rate, |
351 | | const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2], |
352 | | const int skip_pred, INTERP_PRED_TYPE pred_filt_type, int_interpfilters *af, |
353 | 0 | int_interpfilters *lf) { |
354 | 0 | (void)lf; |
355 | 0 | assert(pred_filt_type > INTERP_HORZ_NEQ_VERT_NEQ); |
356 | 0 | assert(pred_filt_type < INTERP_PRED_TYPE_ALL); |
357 | 0 | uint16_t allowed_interp_mask = 0; |
358 | |
|
359 | 0 | if (pred_filt_type == INTERP_HORZ_EQ_VERT_NEQ) { |
360 | | // pred_filter_search = 1: Only horizontal filter is matching |
361 | 0 | allowed_interp_mask = |
362 | 0 | av1_interp_dual_filt_mask[pred_filt_type - 1][af->as_filters.x_filter]; |
363 | 0 | } else if (pred_filt_type == INTERP_HORZ_NEQ_VERT_EQ) { |
364 | | // pred_filter_search = 2: Only vertical filter is matching |
365 | 0 | allowed_interp_mask = |
366 | 0 | av1_interp_dual_filt_mask[pred_filt_type - 1][af->as_filters.y_filter]; |
367 | 0 | } else { |
368 | | // pred_filter_search = 3: Both horizontal and vertical filter are matching |
369 | 0 | int filt_type = |
370 | 0 | af->as_filters.x_filter + af->as_filters.y_filter * SWITCHABLE_FILTERS; |
371 | 0 | set_interp_filter_allowed_mask(&allowed_interp_mask, filt_type); |
372 | 0 | } |
373 | | // REG_REG is already been evaluated in the beginning |
374 | 0 | reset_interp_filter_allowed_mask(&allowed_interp_mask, REG_REG); |
375 | 0 | find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd, rd_stats_y, |
376 | 0 | rd_stats, switchable_rate, dst_bufs, |
377 | 0 | switchable_ctx, skip_pred, allowed_interp_mask, 0); |
378 | 0 | } |
379 | | // Evaluate dual filter type |
380 | | // a) Using above, left block interp filter |
381 | | // b) Find the best horizontal filter and |
382 | | // then evaluate corresponding vertical filters. |
383 | | static inline void fast_dual_interp_filter_rd( |
384 | | MACROBLOCK *const x, const AV1_COMP *const cpi, |
385 | | const TileDataEnc *tile_data, BLOCK_SIZE bsize, |
386 | | const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y, |
387 | | RD_STATS *rd_stats, int *const switchable_rate, |
388 | | const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2], |
389 | 0 | const int skip_hor, const int skip_ver) { |
390 | 0 | const InterpSearchFlags *interp_search_flags = &cpi->interp_search_flags; |
391 | 0 | MACROBLOCKD *const xd = &x->e_mbd; |
392 | 0 | MB_MODE_INFO *const mbmi = xd->mi[0]; |
393 | 0 | INTERP_PRED_TYPE pred_filter_type = INTERP_HORZ_NEQ_VERT_NEQ; |
394 | 0 | int_interpfilters af = av1_broadcast_interp_filter(INTERP_INVALID); |
395 | 0 | int_interpfilters lf = af; |
396 | |
|
397 | 0 | if (!have_newmv_in_inter_mode(mbmi->mode)) { |
398 | 0 | pred_filter_type = is_pred_filter_search_allowed(cpi, xd, bsize, &af, &lf); |
399 | 0 | } |
400 | |
|
401 | 0 | if (pred_filter_type) { |
402 | 0 | pred_dual_interp_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd, |
403 | 0 | rd_stats_y, rd_stats, switchable_rate, dst_bufs, |
404 | 0 | switchable_ctx, (skip_hor & skip_ver), |
405 | 0 | pred_filter_type, &af, &lf); |
406 | 0 | } else { |
407 | 0 | const int bw = block_size_wide[bsize]; |
408 | 0 | const int bh = block_size_high[bsize]; |
409 | 0 | int best_dual_mode = 0; |
410 | 0 | int skip_pred = |
411 | 0 | bw <= 4 ? interp_search_flags->default_interp_skip_flags : skip_hor; |
412 | | // TODO(any): Make use of find_best_interp_rd_facade() |
413 | | // if speed impact is negligible |
414 | 0 | for (int i = (SWITCHABLE_FILTERS - 1); i >= 1; --i) { |
415 | 0 | if (interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd, |
416 | 0 | rd_stats_y, rd_stats, switchable_rate, |
417 | 0 | dst_bufs, i, switchable_ctx, skip_pred)) { |
418 | 0 | best_dual_mode = i; |
419 | 0 | } |
420 | 0 | skip_pred = skip_hor; |
421 | 0 | } |
422 | | // From best of horizontal EIGHTTAP_REGULAR modes, check vertical modes |
423 | 0 | skip_pred = |
424 | 0 | bh <= 4 ? interp_search_flags->default_interp_skip_flags : skip_ver; |
425 | 0 | for (int i = (best_dual_mode + (SWITCHABLE_FILTERS * 2)); |
426 | 0 | i >= (best_dual_mode + SWITCHABLE_FILTERS); i -= SWITCHABLE_FILTERS) { |
427 | 0 | interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd, |
428 | 0 | rd_stats_y, rd_stats, switchable_rate, dst_bufs, |
429 | 0 | i, switchable_ctx, skip_pred); |
430 | 0 | skip_pred = skip_ver; |
431 | 0 | } |
432 | 0 | } |
433 | 0 | } |
434 | | |
435 | | // Find the best interp filter if dual_interp_filter = 0 |
436 | | static inline void find_best_non_dual_interp_filter( |
437 | | MACROBLOCK *const x, const AV1_COMP *const cpi, |
438 | | const TileDataEnc *tile_data, BLOCK_SIZE bsize, |
439 | | const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y, |
440 | | RD_STATS *rd_stats, int *const switchable_rate, |
441 | | const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2], |
442 | 0 | const int skip_ver, const int skip_hor) { |
443 | 0 | const InterpSearchFlags *interp_search_flags = &cpi->interp_search_flags; |
444 | 0 | int8_t i; |
445 | 0 | MACROBLOCKD *const xd = &x->e_mbd; |
446 | 0 | MB_MODE_INFO *const mbmi = xd->mi[0]; |
447 | |
|
448 | 0 | uint16_t interp_filter_search_mask = |
449 | 0 | interp_search_flags->interp_filter_search_mask; |
450 | |
|
451 | 0 | if (cpi->sf.interp_sf.adaptive_interp_filter_search == 2) { |
452 | 0 | const FRAME_UPDATE_TYPE update_type = |
453 | 0 | get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index); |
454 | 0 | const int ctx0 = av1_get_pred_context_switchable_interp(xd, 0); |
455 | 0 | const int ctx1 = av1_get_pred_context_switchable_interp(xd, 1); |
456 | 0 | int use_actual_frame_probs = 1; |
457 | 0 | const int *switchable_interp_p0; |
458 | 0 | const int *switchable_interp_p1; |
459 | | #if CONFIG_FPMT_TEST |
460 | | use_actual_frame_probs = |
461 | | (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) ? 0 : 1; |
462 | | if (!use_actual_frame_probs) { |
463 | | switchable_interp_p0 = (int *)cpi->ppi->temp_frame_probs |
464 | | .switchable_interp_probs[update_type][ctx0]; |
465 | | switchable_interp_p1 = (int *)cpi->ppi->temp_frame_probs |
466 | | .switchable_interp_probs[update_type][ctx1]; |
467 | | } |
468 | | #endif |
469 | 0 | if (use_actual_frame_probs) { |
470 | 0 | switchable_interp_p0 = |
471 | 0 | cpi->ppi->frame_probs.switchable_interp_probs[update_type][ctx0]; |
472 | 0 | switchable_interp_p1 = |
473 | 0 | cpi->ppi->frame_probs.switchable_interp_probs[update_type][ctx1]; |
474 | 0 | } |
475 | 0 | static const int thr[7] = { 0, 8, 8, 8, 8, 0, 8 }; |
476 | 0 | const int thresh = thr[update_type]; |
477 | 0 | for (i = 0; i < SWITCHABLE_FILTERS; i++) { |
478 | | // For non-dual case, the 2 dir's prob should be identical. |
479 | 0 | assert(switchable_interp_p0[i] == switchable_interp_p1[i]); |
480 | 0 | if (switchable_interp_p0[i] < thresh && |
481 | 0 | switchable_interp_p1[i] < thresh) { |
482 | 0 | DUAL_FILTER_TYPE filt_type = i + SWITCHABLE_FILTERS * i; |
483 | 0 | reset_interp_filter_allowed_mask(&interp_filter_search_mask, filt_type); |
484 | 0 | } |
485 | |
|
486 | 0 | if (cpi->oxcf.algo_cfg.sharpness == 3 && i == EIGHTTAP_SMOOTH) { |
487 | 0 | DUAL_FILTER_TYPE filt_type = i + SWITCHABLE_FILTERS * i; |
488 | 0 | reset_interp_filter_allowed_mask(&interp_filter_search_mask, filt_type); |
489 | 0 | } |
490 | 0 | } |
491 | 0 | } |
492 | | |
493 | | // Regular filter evaluation should have been done and hence the same should |
494 | | // be the winner |
495 | 0 | assert(x->e_mbd.mi[0]->interp_filters.as_int == filter_sets[0].as_int); |
496 | 0 | if ((skip_hor & skip_ver) != interp_search_flags->default_interp_skip_flags) { |
497 | 0 | INTERP_PRED_TYPE pred_filter_type = INTERP_HORZ_NEQ_VERT_NEQ; |
498 | 0 | int_interpfilters af = av1_broadcast_interp_filter(INTERP_INVALID); |
499 | 0 | int_interpfilters lf = af; |
500 | |
|
501 | 0 | pred_filter_type = is_pred_filter_search_allowed(cpi, xd, bsize, &af, &lf); |
502 | 0 | if (pred_filter_type) { |
503 | 0 | assert(af.as_filters.x_filter != INTERP_INVALID); |
504 | 0 | int filter_idx = SWITCHABLE * af.as_filters.x_filter; |
505 | | // This assert tells that (filter_x == filter_y) for non-dual filter case |
506 | 0 | assert(filter_sets[filter_idx].as_filters.x_filter == |
507 | 0 | filter_sets[filter_idx].as_filters.y_filter); |
508 | 0 | if (cpi->sf.interp_sf.adaptive_interp_filter_search && |
509 | 0 | !(get_interp_filter_allowed_mask(interp_filter_search_mask, |
510 | 0 | filter_idx))) { |
511 | 0 | return; |
512 | 0 | } |
513 | 0 | if (filter_idx) { |
514 | 0 | interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd, |
515 | 0 | rd_stats_y, rd_stats, switchable_rate, dst_bufs, |
516 | 0 | filter_idx, switchable_ctx, |
517 | 0 | (skip_hor & skip_ver)); |
518 | 0 | } |
519 | 0 | return; |
520 | 0 | } |
521 | 0 | } |
522 | | // Reuse regular filter's modeled rd data for sharp filter for following |
523 | | // cases |
524 | | // 1) When bsize is 4x4 |
525 | | // 2) When block width is 4 (i.e. 4x8/4x16 blocks) and MV in vertical |
526 | | // direction is full-pel |
527 | | // 3) When block height is 4 (i.e. 8x4/16x4 blocks) and MV in horizontal |
528 | | // direction is full-pel |
529 | | // TODO(any): Optimize cases 2 and 3 further if luma MV in relavant direction |
530 | | // alone is full-pel |
531 | | |
532 | 0 | if ((bsize == BLOCK_4X4) || |
533 | 0 | (block_size_wide[bsize] == 4 && |
534 | 0 | skip_ver == interp_search_flags->default_interp_skip_flags) || |
535 | 0 | (block_size_high[bsize] == 4 && |
536 | 0 | skip_hor == interp_search_flags->default_interp_skip_flags)) { |
537 | 0 | int skip_pred = skip_hor & skip_ver; |
538 | 0 | uint16_t allowed_interp_mask = 0; |
539 | | |
540 | | // REG_REG filter type is evaluated beforehand, hence skip it |
541 | 0 | set_interp_filter_allowed_mask(&allowed_interp_mask, SHARP_SHARP); |
542 | 0 | set_interp_filter_allowed_mask(&allowed_interp_mask, SMOOTH_SMOOTH); |
543 | 0 | if (cpi->sf.interp_sf.adaptive_interp_filter_search) |
544 | 0 | allowed_interp_mask &= interp_filter_search_mask; |
545 | |
|
546 | 0 | find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd, |
547 | 0 | rd_stats_y, rd_stats, switchable_rate, dst_bufs, |
548 | 0 | switchable_ctx, skip_pred, allowed_interp_mask, |
549 | 0 | 1); |
550 | 0 | } else { |
551 | 0 | int skip_pred = (skip_hor & skip_ver); |
552 | 0 | for (i = (SWITCHABLE_FILTERS + 1); i < DUAL_FILTER_SET_SIZE; |
553 | 0 | i += (SWITCHABLE_FILTERS + 1)) { |
554 | | // This assert tells that (filter_x == filter_y) for non-dual filter case |
555 | 0 | assert(filter_sets[i].as_filters.x_filter == |
556 | 0 | filter_sets[i].as_filters.y_filter); |
557 | 0 | if (cpi->sf.interp_sf.adaptive_interp_filter_search && |
558 | 0 | !(get_interp_filter_allowed_mask(interp_filter_search_mask, i))) { |
559 | 0 | continue; |
560 | 0 | } |
561 | 0 | interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd, |
562 | 0 | rd_stats_y, rd_stats, switchable_rate, dst_bufs, |
563 | 0 | i, switchable_ctx, skip_pred); |
564 | | // In first iteration, smooth filter is evaluated. If smooth filter |
565 | | // (which is less sharper) is the winner among regular and smooth filters, |
566 | | // sharp filter evaluation is skipped |
567 | | // TODO(any): Refine this gating based on modelled rd only (i.e., by not |
568 | | // accounting switchable filter rate) |
569 | 0 | if (cpi->sf.interp_sf.skip_sharp_interp_filter_search && |
570 | 0 | skip_pred != interp_search_flags->default_interp_skip_flags) { |
571 | 0 | if (mbmi->interp_filters.as_int == filter_sets[SMOOTH_SMOOTH].as_int) |
572 | 0 | break; |
573 | 0 | } |
574 | 0 | } |
575 | 0 | } |
576 | 0 | } |
577 | | |
578 | | static inline void calc_interp_skip_pred_flag(MACROBLOCK *const x, |
579 | | const AV1_COMP *const cpi, |
580 | 0 | int *skip_hor, int *skip_ver) { |
581 | 0 | const AV1_COMMON *cm = &cpi->common; |
582 | 0 | MACROBLOCKD *const xd = &x->e_mbd; |
583 | 0 | MB_MODE_INFO *const mbmi = xd->mi[0]; |
584 | 0 | const int num_planes = av1_num_planes(cm); |
585 | 0 | const int is_compound = has_second_ref(mbmi); |
586 | 0 | assert(is_intrabc_block(mbmi) == 0); |
587 | 0 | for (int ref = 0; ref < 1 + is_compound; ++ref) { |
588 | 0 | const struct scale_factors *const sf = |
589 | 0 | get_ref_scale_factors_const(cm, mbmi->ref_frame[ref]); |
590 | | // TODO(any): Refine skip flag calculation considering scaling |
591 | 0 | if (av1_is_scaled(sf)) { |
592 | 0 | *skip_hor = 0; |
593 | 0 | *skip_ver = 0; |
594 | 0 | break; |
595 | 0 | } |
596 | 0 | const MV mv = mbmi->mv[ref].as_mv; |
597 | 0 | int skip_hor_plane = 0; |
598 | 0 | int skip_ver_plane = 0; |
599 | 0 | for (int plane_idx = 0; plane_idx < AOMMAX(1, (num_planes - 1)); |
600 | 0 | ++plane_idx) { |
601 | 0 | struct macroblockd_plane *const pd = &xd->plane[plane_idx]; |
602 | 0 | const int bw = pd->width; |
603 | 0 | const int bh = pd->height; |
604 | 0 | const MV mv_q4 = clamp_mv_to_umv_border_sb( |
605 | 0 | xd, &mv, bw, bh, pd->subsampling_x, pd->subsampling_y); |
606 | 0 | const int sub_x = (mv_q4.col & SUBPEL_MASK) << SCALE_EXTRA_BITS; |
607 | 0 | const int sub_y = (mv_q4.row & SUBPEL_MASK) << SCALE_EXTRA_BITS; |
608 | 0 | skip_hor_plane |= ((sub_x == 0) << plane_idx); |
609 | 0 | skip_ver_plane |= ((sub_y == 0) << plane_idx); |
610 | 0 | } |
611 | 0 | *skip_hor &= skip_hor_plane; |
612 | 0 | *skip_ver &= skip_ver_plane; |
613 | | // It is not valid that "luma MV is sub-pel, whereas chroma MV is not" |
614 | 0 | assert(*skip_hor != 2); |
615 | 0 | assert(*skip_ver != 2); |
616 | 0 | } |
617 | | // When compond prediction type is compound segment wedge, luma MC and chroma |
618 | | // MC need to go hand in hand as mask generated during luma MC is reuired for |
619 | | // chroma MC. If skip_hor = 0 and skip_ver = 1, mask used for chroma MC during |
620 | | // vertical filter decision may be incorrect as temporary MC evaluation |
621 | | // overwrites the mask. Make skip_ver as 0 for this case so that mask is |
622 | | // populated during luma MC |
623 | 0 | if (is_compound && mbmi->compound_idx == 1 && |
624 | 0 | mbmi->interinter_comp.type == COMPOUND_DIFFWTD) { |
625 | 0 | assert(mbmi->comp_group_idx == 1); |
626 | 0 | if (*skip_hor == 0 && *skip_ver == 1) *skip_ver = 0; |
627 | 0 | } |
628 | | |
629 | | // Configure flags to skip chroma RD evaluation when skip_model_rd_uv is |
630 | | // enabled |
631 | 0 | if (cpi->sf.interp_sf.skip_model_rd_uv && num_planes > 1) { |
632 | 0 | *skip_hor |= INTERP_EVAL_LUMA_SKIP_CHROMA; |
633 | 0 | *skip_ver |= INTERP_EVAL_LUMA_SKIP_CHROMA; |
634 | 0 | } |
635 | 0 | } |
636 | | |
637 | | /*!\brief AV1 interpolation filter search |
638 | | * |
639 | | * \ingroup inter_mode_search |
640 | | * |
641 | | * \param[in] cpi Top-level encoder structure. |
642 | | * \param[in] tile_data Pointer to struct holding adaptive |
643 | | * data/contexts/models for the tile during |
644 | | * encoding. |
645 | | * \param[in] x Pointer to struc holding all the data for |
646 | | * the current macroblock. |
647 | | * \param[in] bsize Current block size. |
648 | | * \param[in] tmp_dst A temporary prediction buffer to hold a |
649 | | * computed prediction. |
650 | | * \param[in,out] orig_dst A prediction buffer to hold a computed |
651 | | * prediction. This will eventually hold the |
652 | | * final prediction, and the tmp_dst info will |
653 | | * be copied here. |
654 | | * \param[in,out] rd The RD cost associated with the selected |
655 | | * interpolation filter parameters. |
656 | | * \param[in,out] switchable_rate The rate associated with using a SWITCHABLE |
657 | | * filter mode. |
658 | | * \param[in,out] skip_build_pred Indicates whether or not to build the inter |
659 | | * predictor. If this is 3, the inter predictor |
660 | | * has already been built and thus we can avoid |
661 | | * repeating computation. |
662 | | * \param[in] args HandleInterModeArgs struct holding |
663 | | * miscellaneous arguments for inter mode |
664 | | * search. See the documentation for this |
665 | | * struct for a description of each member. |
666 | | * \param[in] ref_best_rd Best RD found so far for this block. |
667 | | * It is used for early termination of this |
668 | | * search if the RD exceeds this value. |
669 | | * |
670 | | * \return Returns INT64_MAX if the filter parameters are invalid and the |
671 | | * current motion mode being tested should be skipped. It returns 0 if the |
672 | | * parameter search is a success. |
673 | | */ |
674 | | int64_t av1_interpolation_filter_search( |
675 | | MACROBLOCK *const x, const AV1_COMP *const cpi, |
676 | | const TileDataEnc *tile_data, BLOCK_SIZE bsize, |
677 | | const BUFFER_SET *const tmp_dst, const BUFFER_SET *const orig_dst, |
678 | | int64_t *const rd, int *const switchable_rate, int *skip_build_pred, |
679 | 0 | HandleInterModeArgs *args, int64_t ref_best_rd) { |
680 | 0 | const AV1_COMMON *cm = &cpi->common; |
681 | 0 | const InterpSearchFlags *interp_search_flags = &cpi->interp_search_flags; |
682 | 0 | const int num_planes = av1_num_planes(cm); |
683 | 0 | MACROBLOCKD *const xd = &x->e_mbd; |
684 | 0 | MB_MODE_INFO *const mbmi = xd->mi[0]; |
685 | 0 | const int need_search = av1_is_interp_needed(xd); |
686 | 0 | const int ref_frame = xd->mi[0]->ref_frame[0]; |
687 | 0 | const int skip_model_rd_uv = cpi->sf.interp_sf.skip_model_rd_uv; |
688 | 0 | RD_STATS rd_stats_luma, rd_stats; |
689 | | |
690 | | // Initialization of rd_stats structures with default values |
691 | 0 | av1_init_rd_stats(&rd_stats_luma); |
692 | 0 | av1_init_rd_stats(&rd_stats); |
693 | |
|
694 | 0 | int match_found_idx = -1; |
695 | 0 | const InterpFilter assign_filter = cm->features.interp_filter; |
696 | |
|
697 | 0 | match_found_idx = find_interp_filter_match( |
698 | 0 | mbmi, cpi, assign_filter, need_search, args->interp_filter_stats, |
699 | 0 | args->interp_filter_stats_idx); |
700 | |
|
701 | 0 | if (match_found_idx != -1) { |
702 | 0 | *rd = args->interp_filter_stats[match_found_idx].rd; |
703 | 0 | x->pred_sse[ref_frame] = |
704 | 0 | args->interp_filter_stats[match_found_idx].pred_sse; |
705 | 0 | *skip_build_pred = INTERP_EVAL_LUMA_EVAL_CHROMA; |
706 | 0 | return 0; |
707 | 0 | } |
708 | | |
709 | 0 | int switchable_ctx[2]; |
710 | 0 | switchable_ctx[0] = av1_get_pred_context_switchable_interp(xd, 0); |
711 | 0 | switchable_ctx[1] = av1_get_pred_context_switchable_interp(xd, 1); |
712 | 0 | *switchable_rate = |
713 | 0 | get_switchable_rate(x, mbmi->interp_filters, switchable_ctx, |
714 | 0 | cm->seq_params->enable_dual_filter); |
715 | | |
716 | | // Do MC evaluation for default filter_type. |
717 | | // Luma MC |
718 | 0 | interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_Y, AOM_PLANE_Y, |
719 | 0 | &rd_stats_luma, *skip_build_pred); |
720 | |
|
721 | | #if CONFIG_COLLECT_RD_STATS == 3 |
722 | | RD_STATS rd_stats_y; |
723 | | av1_pick_recursive_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, INT64_MAX); |
724 | | PrintPredictionUnitStats(cpi, tile_data, x, &rd_stats_y, bsize); |
725 | | #endif // CONFIG_COLLECT_RD_STATS == 3 |
726 | | // Chroma MC |
727 | 0 | if (num_planes > 1 && !skip_model_rd_uv) { |
728 | 0 | interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_U, AOM_PLANE_V, |
729 | 0 | &rd_stats, *skip_build_pred); |
730 | 0 | } |
731 | 0 | *skip_build_pred = num_planes > 1 && skip_model_rd_uv |
732 | 0 | ? INTERP_SKIP_LUMA_EVAL_CHROMA |
733 | 0 | : INTERP_SKIP_LUMA_SKIP_CHROMA; |
734 | |
|
735 | 0 | av1_merge_rd_stats(&rd_stats, &rd_stats_luma); |
736 | |
|
737 | 0 | assert(rd_stats.rate >= 0); |
738 | | |
739 | 0 | *rd = RDCOST(x->rdmult, *switchable_rate + rd_stats.rate, rd_stats.dist); |
740 | 0 | x->pred_sse[ref_frame] = (unsigned int)(rd_stats_luma.sse >> 4); |
741 | |
|
742 | 0 | if (assign_filter != SWITCHABLE || match_found_idx != -1) { |
743 | 0 | return 0; |
744 | 0 | } |
745 | 0 | if (!need_search) { |
746 | 0 | int_interpfilters filters = av1_broadcast_interp_filter(EIGHTTAP_REGULAR); |
747 | 0 | assert(mbmi->interp_filters.as_int == filters.as_int); |
748 | 0 | (void)filters; |
749 | 0 | return 0; |
750 | 0 | } |
751 | 0 | if (args->modelled_rd != NULL) { |
752 | 0 | if (has_second_ref(mbmi)) { |
753 | 0 | const int ref_mv_idx = mbmi->ref_mv_idx; |
754 | 0 | MV_REFERENCE_FRAME *refs = mbmi->ref_frame; |
755 | 0 | const int mode0 = compound_ref0_mode(mbmi->mode); |
756 | 0 | const int mode1 = compound_ref1_mode(mbmi->mode); |
757 | 0 | const int64_t mrd = AOMMIN(args->modelled_rd[mode0][ref_mv_idx][refs[0]], |
758 | 0 | args->modelled_rd[mode1][ref_mv_idx][refs[1]]); |
759 | 0 | if ((*rd >> 1) > mrd && ref_best_rd < INT64_MAX) { |
760 | 0 | return INT64_MAX; |
761 | 0 | } |
762 | 0 | } |
763 | 0 | } |
764 | | |
765 | 0 | x->recalc_luma_mc_data = 0; |
766 | | // skip_flag=xx (in binary form) |
767 | | // Setting 0th flag corresonds to skipping luma MC and setting 1st bt |
768 | | // corresponds to skipping chroma MC skip_flag=0 corresponds to "Don't skip |
769 | | // luma and chroma MC" Skip flag=1 corresponds to "Skip Luma MC only" |
770 | | // Skip_flag=2 corresponds to "Skip chroma MC only". This is valid only when |
771 | | // skip_model_rd_uv speed feature is enabled |
772 | | // skip_flag=3 corresponds to "Skip both luma and chroma MC" |
773 | 0 | int skip_hor = interp_search_flags->default_interp_skip_flags; |
774 | 0 | int skip_ver = interp_search_flags->default_interp_skip_flags; |
775 | 0 | calc_interp_skip_pred_flag(x, cpi, &skip_hor, &skip_ver); |
776 | | |
777 | | // do interp_filter search |
778 | 0 | restore_dst_buf(xd, *tmp_dst, num_planes); |
779 | 0 | const BUFFER_SET *dst_bufs[2] = { tmp_dst, orig_dst }; |
780 | | // Evaluate dual interp filters |
781 | 0 | if (cm->seq_params->enable_dual_filter) { |
782 | 0 | if (cpi->sf.interp_sf.use_fast_interpolation_filter_search) { |
783 | 0 | fast_dual_interp_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd, |
784 | 0 | &rd_stats_luma, &rd_stats, switchable_rate, |
785 | 0 | dst_bufs, switchable_ctx, skip_hor, skip_ver); |
786 | 0 | } else { |
787 | | // Use full interpolation filter search |
788 | 0 | uint16_t allowed_interp_mask = ALLOW_ALL_INTERP_FILT_MASK; |
789 | | // REG_REG filter type is evaluated beforehand, so loop is repeated over |
790 | | // REG_SMOOTH to SHARP_SHARP for full interpolation filter search |
791 | 0 | reset_interp_filter_allowed_mask(&allowed_interp_mask, REG_REG); |
792 | 0 | find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd, |
793 | 0 | &rd_stats_luma, &rd_stats, switchable_rate, |
794 | 0 | dst_bufs, switchable_ctx, |
795 | 0 | (skip_hor & skip_ver), allowed_interp_mask, 0); |
796 | 0 | } |
797 | 0 | } else { |
798 | | // Evaluate non-dual interp filters |
799 | 0 | find_best_non_dual_interp_filter( |
800 | 0 | x, cpi, tile_data, bsize, orig_dst, rd, &rd_stats_luma, &rd_stats, |
801 | 0 | switchable_rate, dst_bufs, switchable_ctx, skip_ver, skip_hor); |
802 | 0 | } |
803 | 0 | swap_dst_buf(xd, dst_bufs, num_planes); |
804 | | // Recompute final MC data if required |
805 | 0 | if (x->recalc_luma_mc_data == 1) { |
806 | | // Recomputing final luma MC data is required only if the same was skipped |
807 | | // in either of the directions Condition below is necessary, but not |
808 | | // sufficient |
809 | 0 | assert((skip_hor == 1) || (skip_ver == 1)); |
810 | 0 | const int mi_row = xd->mi_row; |
811 | 0 | const int mi_col = xd->mi_col; |
812 | 0 | av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, |
813 | 0 | AOM_PLANE_Y, AOM_PLANE_Y); |
814 | 0 | } |
815 | 0 | x->pred_sse[ref_frame] = (unsigned int)(rd_stats_luma.sse >> 4); |
816 | | |
817 | | // save search results |
818 | 0 | if (cpi->sf.interp_sf.use_interp_filter) { |
819 | 0 | assert(match_found_idx == -1); |
820 | 0 | args->interp_filter_stats_idx = save_interp_filter_search_stat( |
821 | 0 | mbmi, *rd, x->pred_sse[ref_frame], args->interp_filter_stats, |
822 | 0 | args->interp_filter_stats_idx); |
823 | 0 | } |
824 | 0 | return 0; |
825 | 0 | } |