• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef AOM_AV1_ENCODER_ENCODEFRAME_UTILS_H_
13 #define AOM_AV1_ENCODER_ENCODEFRAME_UTILS_H_
14 
15 #include "aom_ports/aom_timer.h"
16 
17 #include "av1/common/reconinter.h"
18 
19 #include "av1/encoder/encoder.h"
20 #include "av1/encoder/rdopt.h"
21 
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25 
26 #define WRITE_FEATURE_TO_FILE 0
27 
28 #define FEATURE_SIZE_SMS_SPLIT_FAST 6
29 #define FEATURE_SIZE_SMS_SPLIT 17
30 #define FEATURE_SIZE_SMS_PRUNE_PART 25
31 #define FEATURE_SIZE_SMS_TERM_NONE 28
32 #define FEATURE_SIZE_FP_SMS_TERM_NONE 20
33 #define FEATURE_SIZE_MAX_MIN_PART_PRED 13
34 #define MAX_NUM_CLASSES_MAX_MIN_PART_PRED 4
35 
36 #define FEATURE_SMS_NONE_FLAG 1
37 #define FEATURE_SMS_SPLIT_FLAG (1 << 1)
38 #define FEATURE_SMS_RECT_FLAG (1 << 2)
39 
40 #define FEATURE_SMS_PRUNE_PART_FLAG \
41   (FEATURE_SMS_NONE_FLAG | FEATURE_SMS_SPLIT_FLAG | FEATURE_SMS_RECT_FLAG)
42 #define FEATURE_SMS_SPLIT_MODEL_FLAG \
43   (FEATURE_SMS_NONE_FLAG | FEATURE_SMS_SPLIT_FLAG)
44 
45 // Number of sub-partitions in rectangular partition types.
46 #define SUB_PARTITIONS_RECT 2
47 
48 // Number of sub-partitions in split partition type.
49 #define SUB_PARTITIONS_SPLIT 4
50 
51 // Number of sub-partitions in AB partition types.
52 #define SUB_PARTITIONS_AB 3
53 
54 // Number of sub-partitions in 4-way partition types.
55 #define SUB_PARTITIONS_PART4 4
56 
57 // 4part partition types.
58 enum { HORZ4 = 0, VERT4, NUM_PART4_TYPES } UENUM1BYTE(PART4_TYPES);
59 
60 // AB partition types.
61 enum {
62   HORZ_A = 0,
63   HORZ_B,
64   VERT_A,
65   VERT_B,
66   NUM_AB_PARTS
67 } UENUM1BYTE(AB_PART_TYPE);
68 
69 // Rectangular partition types.
70 enum { HORZ = 0, VERT, NUM_RECT_PARTS } UENUM1BYTE(RECT_PART_TYPE);
71 
72 // Structure to keep win flags for HORZ and VERT partition evaluations.
73 typedef struct {
74   int rect_part_win[NUM_RECT_PARTS];
75 } RD_RECT_PART_WIN_INFO;
76 
77 enum { PICK_MODE_RD = 0, PICK_MODE_NONRD };
78 
79 enum {
80   SB_SINGLE_PASS,  // Single pass encoding: all ctxs get updated normally
81   SB_DRY_PASS,     // First pass of multi-pass: does not update the ctxs
82   SB_WET_PASS      // Second pass of multi-pass: finalize and update the ctx
83 } UENUM1BYTE(SB_MULTI_PASS_MODE);
84 
85 typedef struct {
86   ENTROPY_CONTEXT a[MAX_MIB_SIZE * MAX_MB_PLANE];
87   ENTROPY_CONTEXT l[MAX_MIB_SIZE * MAX_MB_PLANE];
88   PARTITION_CONTEXT sa[MAX_MIB_SIZE];
89   PARTITION_CONTEXT sl[MAX_MIB_SIZE];
90   TXFM_CONTEXT *p_ta;
91   TXFM_CONTEXT *p_tl;
92   TXFM_CONTEXT ta[MAX_MIB_SIZE];
93   TXFM_CONTEXT tl[MAX_MIB_SIZE];
94 } RD_SEARCH_MACROBLOCK_CONTEXT;
95 
96 // This struct is used to store the statistics used by sb-level multi-pass
97 // encoding. Currently, this is only used to make a copy of the state before we
98 // perform the first pass
99 typedef struct SB_FIRST_PASS_STATS {
100   RD_SEARCH_MACROBLOCK_CONTEXT x_ctx;
101   RD_COUNTS rd_count;
102 
103   int split_count;
104   FRAME_COUNTS fc;
105   InterModeRdModel inter_mode_rd_models[BLOCK_SIZES_ALL];
106   int thresh_freq_fact[BLOCK_SIZES_ALL][MAX_MODES];
107   int current_qindex;
108 
109 #if CONFIG_INTERNAL_STATS
110   unsigned int mode_chosen_counts[MAX_MODES];
111 #endif  // CONFIG_INTERNAL_STATS
112 } SB_FIRST_PASS_STATS;
113 
114 // This structure contains block size related
115 // variables for use in rd_pick_partition().
116 typedef struct {
117   // Half of block width to determine block edge.
118   int mi_step;
119 
120   // Block row and column indices.
121   int mi_row;
122   int mi_col;
123 
124   // Block edge row and column indices.
125   int mi_row_edge;
126   int mi_col_edge;
127 
128   // Block width of current partition block.
129   int width;
130 
131   // Block width of minimum partition size allowed.
132   int min_partition_size_1d;
133 
134   // Flag to indicate if partition is 8x8 or higher size.
135   int bsize_at_least_8x8;
136 
137   // Indicates edge blocks in frame.
138   int has_rows;
139   int has_cols;
140 
141   // Block size of current partition.
142   BLOCK_SIZE bsize;
143 
144   // Size of current sub-partition.
145   BLOCK_SIZE subsize;
146 
147   // Size of split partition.
148   BLOCK_SIZE split_bsize2;
149 } PartitionBlkParams;
150 
151 #if CONFIG_COLLECT_PARTITION_STATS
152 typedef struct PartitionTimingStats {
153   // Tracks the number of partition decision used in the current call to \ref
154   // av1_rd_pick_partition
155   int partition_decisions[EXT_PARTITION_TYPES];
156   // Tracks the number of partition_block searched in the current call to \ref
157   // av1_rd_pick_partition
158   int partition_attempts[EXT_PARTITION_TYPES];
159   // Tracks the time spent on each partition search in the current call to \ref
160   // av1_rd_pick_partition
161   int64_t partition_times[EXT_PARTITION_TYPES];
162   // Tracks the rdcost spent on each partition search in the current call to
163   // \ref av1_rd_pick_partition
164   int64_t partition_rdcost[EXT_PARTITION_TYPES];
165   // Timer used to time the partitions.
166   struct aom_usec_timer timer;
167   // Whether the timer is on
168   int timer_is_on;
169 } PartitionTimingStats;
170 #endif  // CONFIG_COLLECT_PARTITION_STATS
171 
172 // Structure holding state variables for partition search.
173 typedef struct {
174   // Intra partitioning related info.
175   PartitionSearchInfo *intra_part_info;
176 
177   // Parameters related to partition block size.
178   PartitionBlkParams part_blk_params;
179 
180   // Win flags for HORZ and VERT partition evaluations.
181   RD_RECT_PART_WIN_INFO split_part_rect_win[SUB_PARTITIONS_SPLIT];
182 
183   // RD cost for the current block of given partition type.
184   RD_STATS this_rdc;
185 
186   // RD cost summed across all blocks of partition type.
187   RD_STATS sum_rdc;
188 
189   // Array holding partition type cost.
190   int tmp_partition_cost[PARTITION_TYPES];
191 
192   // Pointer to partition cost buffer
193   int *partition_cost;
194 
195   // RD costs for different partition types.
196   int64_t none_rd;
197   int64_t split_rd[SUB_PARTITIONS_SPLIT];
198   // RD costs for rectangular partitions.
199   // rect_part_rd[0][i] is the RD cost of ith partition index of PARTITION_HORZ.
200   // rect_part_rd[1][i] is the RD cost of ith partition index of PARTITION_VERT.
201   int64_t rect_part_rd[NUM_RECT_PARTS][SUB_PARTITIONS_RECT];
202 
203   // Flags indicating if the corresponding partition was winner or not.
204   // Used to bypass similar blocks during AB partition evaluation.
205   int is_split_ctx_is_ready[2];
206   int is_rect_ctx_is_ready[NUM_RECT_PARTS];
207 
208   // If true, skips the rest of partition evaluation at the current bsize level.
209   int terminate_partition_search;
210 
211   // If false, skips rdopt on PARTITION_NONE.
212   int partition_none_allowed;
213 
214   // If partition_rect_allowed[HORZ] is false, skips searching PARTITION_HORZ,
215   // PARTITION_HORZ_A, PARTITIO_HORZ_B, PARTITION_HORZ_4. Same holds for VERT.
216   int partition_rect_allowed[NUM_RECT_PARTS];
217 
218   // If false, skips searching rectangular partition unless some logic related
219   // to edge detection holds.
220   int do_rectangular_split;
221 
222   // If false, skips searching PARTITION_SPLIT.
223   int do_square_split;
224 
225   // If true, prunes the corresponding PARTITION_HORZ/PARTITION_VERT. Note that
226   // this does not directly affect the extended partitions, so this can be used
227   // to prune out PARTITION_HORZ/PARTITION_VERT while still allowing rdopt of
228   // PARTITION_HORZ_AB4, etc.
229   int prune_rect_part[NUM_RECT_PARTS];
230 
231   // Chroma subsampling in x and y directions.
232   int ss_x;
233   int ss_y;
234 
235   // Partition plane context index.
236   int pl_ctx_idx;
237 
238   // This flag will be set if best partition is found from the search.
239   bool found_best_partition;
240 
241 #if CONFIG_COLLECT_PARTITION_STATS
242   PartitionTimingStats part_timing_stats;
243 #endif  // CONFIG_COLLECT_PARTITION_STATS
244 } PartitionSearchState;
245 
av1_disable_square_split_partition(PartitionSearchState * part_state)246 static AOM_INLINE void av1_disable_square_split_partition(
247     PartitionSearchState *part_state) {
248   part_state->do_square_split = 0;
249 }
250 
251 // Disables all possible rectangular splits. This includes PARTITION_AB4 as they
252 // depend on the corresponding partition_rect_allowed.
av1_disable_rect_partitions(PartitionSearchState * part_state)253 static AOM_INLINE void av1_disable_rect_partitions(
254     PartitionSearchState *part_state) {
255   part_state->do_rectangular_split = 0;
256   part_state->partition_rect_allowed[HORZ] = 0;
257   part_state->partition_rect_allowed[VERT] = 0;
258 }
259 
260 // Disables all possible splits so that only PARTITION_NONE *might* be allowed.
av1_disable_all_splits(PartitionSearchState * part_state)261 static AOM_INLINE void av1_disable_all_splits(
262     PartitionSearchState *part_state) {
263   av1_disable_square_split_partition(part_state);
264   av1_disable_rect_partitions(part_state);
265 }
266 
av1_set_square_split_only(PartitionSearchState * part_state)267 static AOM_INLINE void av1_set_square_split_only(
268     PartitionSearchState *part_state) {
269   part_state->partition_none_allowed = 0;
270   part_state->do_square_split = 1;
271   av1_disable_rect_partitions(part_state);
272 }
273 
av1_blk_has_rows_and_cols(const PartitionBlkParams * blk_params)274 static AOM_INLINE bool av1_blk_has_rows_and_cols(
275     const PartitionBlkParams *blk_params) {
276   return blk_params->has_rows && blk_params->has_cols;
277 }
278 
av1_is_whole_blk_in_frame(const PartitionBlkParams * blk_params,const CommonModeInfoParams * mi_params)279 static AOM_INLINE bool av1_is_whole_blk_in_frame(
280     const PartitionBlkParams *blk_params,
281     const CommonModeInfoParams *mi_params) {
282   const int mi_row = blk_params->mi_row, mi_col = blk_params->mi_col;
283   const BLOCK_SIZE bsize = blk_params->bsize;
284   return mi_row + mi_size_high[bsize] <= mi_params->mi_rows &&
285          mi_col + mi_size_wide[bsize] <= mi_params->mi_cols;
286 }
287 
update_filter_type_cdf(const MACROBLOCKD * xd,const MB_MODE_INFO * mbmi,int dual_filter)288 static AOM_INLINE void update_filter_type_cdf(const MACROBLOCKD *xd,
289                                               const MB_MODE_INFO *mbmi,
290                                               int dual_filter) {
291   for (int dir = 0; dir < 2; ++dir) {
292     if (dir && !dual_filter) break;
293     const int ctx = av1_get_pred_context_switchable_interp(xd, dir);
294     InterpFilter filter = av1_extract_interp_filter(mbmi->interp_filters, dir);
295     update_cdf(xd->tile_ctx->switchable_interp_cdf[ctx], filter,
296                SWITCHABLE_FILTERS);
297   }
298 }
299 
set_rdmult(const AV1_COMP * const cpi,const MACROBLOCK * const x,int segment_id)300 static AOM_INLINE int set_rdmult(const AV1_COMP *const cpi,
301                                  const MACROBLOCK *const x, int segment_id) {
302   const AV1_COMMON *const cm = &cpi->common;
303   const GF_GROUP *const gf_group = &cpi->ppi->gf_group;
304   const CommonQuantParams *quant_params = &cm->quant_params;
305   const aom_bit_depth_t bit_depth = cm->seq_params->bit_depth;
306   const FRAME_UPDATE_TYPE update_type =
307       cpi->ppi->gf_group.update_type[cpi->gf_frame_index];
308   const FRAME_TYPE frame_type = cm->current_frame.frame_type;
309   const int boost_index = AOMMIN(15, (cpi->ppi->p_rc.gfu_boost / 100));
310   const int layer_depth = AOMMIN(gf_group->layer_depth[cpi->gf_frame_index], 6);
311 
312   int qindex;
313   if (segment_id >= 0) {
314     qindex = av1_get_qindex(&cm->seg, segment_id, cm->quant_params.base_qindex);
315   } else {
316     qindex = quant_params->base_qindex + x->rdmult_delta_qindex +
317              quant_params->y_dc_delta_q;
318   }
319 
320   return av1_compute_rd_mult(
321       qindex, bit_depth, update_type, layer_depth, boost_index, frame_type,
322       cpi->oxcf.q_cfg.use_fixed_qp_offsets, is_stat_consumption_stage(cpi));
323 }
324 
do_split_check(BLOCK_SIZE bsize)325 static AOM_INLINE int do_split_check(BLOCK_SIZE bsize) {
326   return (bsize == BLOCK_16X16 || bsize == BLOCK_32X32);
327 }
328 
329 #if !CONFIG_REALTIME_ONLY
read_one_frame_stats(const TWO_PASS * p,int frm)330 static AOM_INLINE const FIRSTPASS_STATS *read_one_frame_stats(const TWO_PASS *p,
331                                                               int frm) {
332   assert(frm >= 0);
333   if (frm < 0 ||
334       p->stats_buf_ctx->stats_in_start + frm > p->stats_buf_ctx->stats_in_end) {
335     return NULL;
336   }
337 
338   return &p->stats_buf_ctx->stats_in_start[frm];
339 }
340 
341 int av1_get_rdmult_delta(AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row,
342                          int mi_col, int orig_rdmult);
343 
344 int av1_active_h_edge(const AV1_COMP *cpi, int mi_row, int mi_step);
345 
346 int av1_active_v_edge(const AV1_COMP *cpi, int mi_col, int mi_step);
347 
348 void av1_get_tpl_stats_sb(AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row,
349                           int mi_col, SuperBlockEnc *sb_enc);
350 
351 int av1_get_q_for_deltaq_objective(AV1_COMP *const cpi, ThreadData *td,
352                                    int64_t *delta_dist, BLOCK_SIZE bsize,
353                                    int mi_row, int mi_col);
354 
355 int av1_get_q_for_hdr(AV1_COMP *const cpi, MACROBLOCK *const x,
356                       BLOCK_SIZE bsize, int mi_row, int mi_col);
357 
358 int av1_get_cb_rdmult(const AV1_COMP *const cpi, MACROBLOCK *const x,
359                       const BLOCK_SIZE bsize, const int mi_row,
360                       const int mi_col);
361 
362 int av1_get_hier_tpl_rdmult(const AV1_COMP *const cpi, MACROBLOCK *const x,
363                             const BLOCK_SIZE bsize, const int mi_row,
364                             const int mi_col, int orig_rdmult);
365 #endif  // !CONFIG_REALTIME_ONLY
366 
367 void av1_set_ssim_rdmult(const AV1_COMP *const cpi, int *errorperbit,
368                          const BLOCK_SIZE bsize, const int mi_row,
369                          const int mi_col, int *const rdmult);
370 
371 void av1_update_state(const AV1_COMP *const cpi, ThreadData *td,
372                       const PICK_MODE_CONTEXT *const ctx, int mi_row,
373                       int mi_col, BLOCK_SIZE bsize, RUN_TYPE dry_run);
374 
375 void av1_update_inter_mode_stats(FRAME_CONTEXT *fc, FRAME_COUNTS *counts,
376                                  PREDICTION_MODE mode, int16_t mode_context);
377 
378 void av1_sum_intra_stats(const AV1_COMMON *const cm, FRAME_COUNTS *counts,
379                          MACROBLOCKD *xd, const MB_MODE_INFO *const mbmi,
380                          const MB_MODE_INFO *above_mi,
381                          const MB_MODE_INFO *left_mi, const int intraonly);
382 
383 void av1_restore_context(MACROBLOCK *x, const RD_SEARCH_MACROBLOCK_CONTEXT *ctx,
384                          int mi_row, int mi_col, BLOCK_SIZE bsize,
385                          const int num_planes);
386 
387 void av1_save_context(const MACROBLOCK *x, RD_SEARCH_MACROBLOCK_CONTEXT *ctx,
388                       int mi_row, int mi_col, BLOCK_SIZE bsize,
389                       const int num_planes);
390 
391 void av1_set_fixed_partitioning(AV1_COMP *cpi, const TileInfo *const tile,
392                                 MB_MODE_INFO **mib, int mi_row, int mi_col,
393                                 BLOCK_SIZE bsize);
394 
395 int av1_is_leaf_split_partition(AV1_COMMON *cm, int mi_row, int mi_col,
396                                 BLOCK_SIZE bsize);
397 
398 void av1_reset_simple_motion_tree_partition(SIMPLE_MOTION_DATA_TREE *sms_tree,
399                                             BLOCK_SIZE bsize);
400 
401 void av1_update_picked_ref_frames_mask(MACROBLOCK *const x, int ref_type,
402                                        BLOCK_SIZE bsize, int mib_size,
403                                        int mi_row, int mi_col);
404 
405 void av1_avg_cdf_symbols(FRAME_CONTEXT *ctx_left, FRAME_CONTEXT *ctx_tr,
406                          int wt_left, int wt_tr);
407 
408 void av1_source_content_sb(AV1_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data,
409                            int mi_row, int mi_col);
410 
411 void av1_reset_mbmi(CommonModeInfoParams *const mi_params, BLOCK_SIZE sb_size,
412                     int mi_row, int mi_col);
413 
414 void av1_backup_sb_state(SB_FIRST_PASS_STATS *sb_fp_stats, const AV1_COMP *cpi,
415                          ThreadData *td, const TileDataEnc *tile_data,
416                          int mi_row, int mi_col);
417 
418 void av1_restore_sb_state(const SB_FIRST_PASS_STATS *sb_fp_stats, AV1_COMP *cpi,
419                           ThreadData *td, TileDataEnc *tile_data, int mi_row,
420                           int mi_col);
421 
422 void av1_set_cost_upd_freq(AV1_COMP *cpi, ThreadData *td,
423                            const TileInfo *const tile_info, const int mi_row,
424                            const int mi_col);
425 
av1_dealloc_mb_data(struct AV1Common * cm,struct macroblock * mb)426 static AOM_INLINE void av1_dealloc_mb_data(struct AV1Common *cm,
427                                            struct macroblock *mb) {
428   aom_free(mb->txfm_search_info.mb_rd_record);
429   mb->txfm_search_info.mb_rd_record = NULL;
430 
431   aom_free(mb->inter_modes_info);
432   mb->inter_modes_info = NULL;
433 
434   const int num_planes = av1_num_planes(cm);
435   for (int plane = 0; plane < num_planes; plane++) {
436     aom_free(mb->plane[plane].src_diff);
437     mb->plane[plane].src_diff = NULL;
438   }
439 
440   aom_free(mb->e_mbd.seg_mask);
441   mb->e_mbd.seg_mask = NULL;
442 
443   aom_free(mb->winner_mode_stats);
444   mb->winner_mode_stats = NULL;
445 }
446 
allocate_winner_mode_stats(const AV1_COMP * cpi,struct macroblock * mb)447 static AOM_INLINE void allocate_winner_mode_stats(const AV1_COMP *cpi,
448                                                   struct macroblock *mb) {
449   const SPEED_FEATURES *sf = &cpi->sf;
450   // The winner_mode_stats buffer is not required in these cases.
451   if (is_stat_generation_stage(cpi) ||
452       (sf->rt_sf.use_nonrd_pick_mode && !sf->rt_sf.hybrid_intra_pickmode) ||
453       (sf->winner_mode_sf.multi_winner_mode_type == MULTI_WINNER_MODE_OFF))
454     return;
455 
456   const AV1_COMMON *cm = &cpi->common;
457   const int winner_mode_count =
458       winner_mode_count_allowed[sf->winner_mode_sf.multi_winner_mode_type];
459   CHECK_MEM_ERROR(cm, mb->winner_mode_stats,
460                   (WinnerModeStats *)aom_malloc(
461                       winner_mode_count * sizeof(mb->winner_mode_stats[0])));
462 }
463 
av1_alloc_mb_data(const AV1_COMP * cpi,struct macroblock * mb)464 static AOM_INLINE void av1_alloc_mb_data(const AV1_COMP *cpi,
465                                          struct macroblock *mb) {
466   const AV1_COMMON *cm = &cpi->common;
467   const SPEED_FEATURES *sf = &cpi->sf;
468   if (!sf->rt_sf.use_nonrd_pick_mode) {
469     // Memory for mb_rd_record is allocated only when use_mb_rd_hash sf is
470     // enabled.
471     if (sf->rd_sf.use_mb_rd_hash)
472       CHECK_MEM_ERROR(cm, mb->txfm_search_info.mb_rd_record,
473                       (MB_RD_RECORD *)aom_malloc(sizeof(MB_RD_RECORD)));
474     if (!frame_is_intra_only(cm))
475       CHECK_MEM_ERROR(
476           cm, mb->inter_modes_info,
477           (InterModesInfo *)aom_malloc(sizeof(*mb->inter_modes_info)));
478   }
479   const int num_planes = av1_num_planes(cm);
480   for (int plane = 0; plane < num_planes; plane++) {
481     const int subsampling_xy =
482         plane ? cm->seq_params->subsampling_x + cm->seq_params->subsampling_y
483               : 0;
484     const int sb_size = MAX_SB_SQUARE >> subsampling_xy;
485     CHECK_MEM_ERROR(cm, mb->plane[plane].src_diff,
486                     (int16_t *)aom_memalign(
487                         32, sizeof(*mb->plane[plane].src_diff) * sb_size));
488   }
489   CHECK_MEM_ERROR(cm, mb->e_mbd.seg_mask,
490                   (uint8_t *)aom_memalign(
491                       16, 2 * MAX_SB_SQUARE * sizeof(mb->e_mbd.seg_mask[0])));
492 
493   allocate_winner_mode_stats(cpi, mb);
494 }
495 
496 // This function will compute the number of reference frames to be disabled
497 // based on selective_ref_frame speed feature.
get_num_refs_to_disable(const AV1_COMP * cpi,const int * ref_frame_flags,const unsigned int * ref_display_order_hint,unsigned int cur_frame_display_index)498 static AOM_INLINE unsigned int get_num_refs_to_disable(
499     const AV1_COMP *cpi, const int *ref_frame_flags,
500     const unsigned int *ref_display_order_hint,
501     unsigned int cur_frame_display_index) {
502   unsigned int num_refs_to_disable = 0;
503   if (cpi->sf.inter_sf.selective_ref_frame >= 3) {
504     num_refs_to_disable++;
505     if (cpi->sf.inter_sf.selective_ref_frame >= 6) {
506       // Disable LAST2_FRAME  and ALTREF2_FRAME
507       num_refs_to_disable += 2;
508     } else if (cpi->sf.inter_sf.selective_ref_frame == 5 &&
509                *ref_frame_flags & av1_ref_frame_flag_list[LAST2_FRAME]) {
510       const int last2_frame_dist = av1_encoder_get_relative_dist(
511           ref_display_order_hint[LAST2_FRAME - LAST_FRAME],
512           cur_frame_display_index);
513       // Disable LAST2_FRAME if it is a temporally distant frame
514       if (abs(last2_frame_dist) > 2) {
515         num_refs_to_disable++;
516       }
517 #if !CONFIG_REALTIME_ONLY
518       else if (is_stat_consumption_stage_twopass(cpi)) {
519         const FIRSTPASS_STATS *const this_frame_stats =
520             read_one_frame_stats(&cpi->ppi->twopass, cur_frame_display_index);
521         const double coded_error_per_mb = this_frame_stats->coded_error;
522         // Disable LAST2_FRAME if the coded error of the current frame based on
523         // first pass stats is very low.
524         if (coded_error_per_mb < 100.0) num_refs_to_disable++;
525       }
526 #endif  // CONFIG_REALTIME_ONLY
527     }
528   }
529   return num_refs_to_disable;
530 }
531 
get_max_allowed_ref_frames(const AV1_COMP * cpi,const int * ref_frame_flags,const unsigned int * ref_display_order_hint,unsigned int cur_frame_display_index)532 static INLINE int get_max_allowed_ref_frames(
533     const AV1_COMP *cpi, const int *ref_frame_flags,
534     const unsigned int *ref_display_order_hint,
535     unsigned int cur_frame_display_index) {
536   const unsigned int max_reference_frames =
537       cpi->oxcf.ref_frm_cfg.max_reference_frames;
538   const unsigned int num_refs_to_disable = get_num_refs_to_disable(
539       cpi, ref_frame_flags, ref_display_order_hint, cur_frame_display_index);
540   const unsigned int max_allowed_refs_for_given_speed =
541       INTER_REFS_PER_FRAME - num_refs_to_disable;
542   return AOMMIN(max_allowed_refs_for_given_speed, max_reference_frames);
543 }
544 
545 // Enforce the number of references for each arbitrary frame based on user
546 // options and speed.
enforce_max_ref_frames(AV1_COMP * cpi,int * ref_frame_flags,const unsigned int * ref_display_order_hint,unsigned int cur_frame_display_index)547 static AOM_INLINE void enforce_max_ref_frames(
548     AV1_COMP *cpi, int *ref_frame_flags,
549     const unsigned int *ref_display_order_hint,
550     unsigned int cur_frame_display_index) {
551   MV_REFERENCE_FRAME ref_frame;
552   int total_valid_refs = 0;
553 
554   for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
555     if (*ref_frame_flags & av1_ref_frame_flag_list[ref_frame]) {
556       total_valid_refs++;
557     }
558   }
559 
560   const int max_allowed_refs = get_max_allowed_ref_frames(
561       cpi, ref_frame_flags, ref_display_order_hint, cur_frame_display_index);
562 
563   for (int i = 0; i < 4 && total_valid_refs > max_allowed_refs; ++i) {
564     const MV_REFERENCE_FRAME ref_frame_to_disable = disable_order[i];
565 
566     if (!(*ref_frame_flags & av1_ref_frame_flag_list[ref_frame_to_disable])) {
567       continue;
568     }
569 
570     switch (ref_frame_to_disable) {
571       case LAST3_FRAME: *ref_frame_flags &= ~AOM_LAST3_FLAG; break;
572       case LAST2_FRAME: *ref_frame_flags &= ~AOM_LAST2_FLAG; break;
573       case ALTREF2_FRAME: *ref_frame_flags &= ~AOM_ALT2_FLAG; break;
574       case BWDREF_FRAME: *ref_frame_flags &= ~AOM_GOLD_FLAG; break;
575       default: assert(0);
576     }
577     --total_valid_refs;
578   }
579   assert(total_valid_refs <= max_allowed_refs);
580 }
581 
582 #ifdef __cplusplus
583 }  // extern "C"
584 #endif
585 
586 #endif  // AOM_AV1_ENCODER_ENCODEFRAME_UTILS_H_
587