tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

encodeframe_utils.h (21558B)


      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 
    246 static 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.
    253 static 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.
    261 static inline void av1_disable_all_splits(PartitionSearchState *part_state) {
    262  av1_disable_square_split_partition(part_state);
    263  av1_disable_rect_partitions(part_state);
    264 }
    265 
    266 static inline void av1_set_square_split_only(PartitionSearchState *part_state) {
    267  part_state->partition_none_allowed = 0;
    268  part_state->do_square_split = 1;
    269  av1_disable_rect_partitions(part_state);
    270 }
    271 
    272 static inline bool av1_blk_has_rows_and_cols(
    273    const PartitionBlkParams *blk_params) {
    274  return blk_params->has_rows && blk_params->has_cols;
    275 }
    276 
    277 static inline bool av1_is_whole_blk_in_frame(
    278    const PartitionBlkParams *blk_params,
    279    const CommonModeInfoParams *mi_params) {
    280  const int mi_row = blk_params->mi_row, mi_col = blk_params->mi_col;
    281  const BLOCK_SIZE bsize = blk_params->bsize;
    282  return mi_row + mi_size_high[bsize] <= mi_params->mi_rows &&
    283         mi_col + mi_size_wide[bsize] <= mi_params->mi_cols;
    284 }
    285 
    286 static inline void update_filter_type_cdf(const MACROBLOCKD *xd,
    287                                          const MB_MODE_INFO *mbmi,
    288                                          int dual_filter) {
    289  for (int dir = 0; dir < 2; ++dir) {
    290    if (dir && !dual_filter) break;
    291    const int ctx = av1_get_pred_context_switchable_interp(xd, dir);
    292    InterpFilter filter = av1_extract_interp_filter(mbmi->interp_filters, dir);
    293    update_cdf(xd->tile_ctx->switchable_interp_cdf[ctx], filter,
    294               SWITCHABLE_FILTERS);
    295  }
    296 }
    297 
    298 static inline int set_rdmult(const AV1_COMP *const cpi,
    299                             const MACROBLOCK *const x, int segment_id) {
    300  const AV1_COMMON *const cm = &cpi->common;
    301  const GF_GROUP *const gf_group = &cpi->ppi->gf_group;
    302  const CommonQuantParams *quant_params = &cm->quant_params;
    303  const aom_bit_depth_t bit_depth = cm->seq_params->bit_depth;
    304  const FRAME_UPDATE_TYPE update_type =
    305      cpi->ppi->gf_group.update_type[cpi->gf_frame_index];
    306  const FRAME_TYPE frame_type = cm->current_frame.frame_type;
    307  const int boost_index = AOMMIN(15, (cpi->ppi->p_rc.gfu_boost / 100));
    308  const int layer_depth = AOMMIN(gf_group->layer_depth[cpi->gf_frame_index], 6);
    309 
    310  int qindex;
    311  if (segment_id >= 0) {
    312    qindex = av1_get_qindex(&cm->seg, segment_id, cm->quant_params.base_qindex);
    313  } else {
    314    qindex = quant_params->base_qindex + x->rdmult_delta_qindex +
    315             quant_params->y_dc_delta_q;
    316  }
    317 
    318  return av1_compute_rd_mult(
    319      qindex, bit_depth, update_type, layer_depth, boost_index, frame_type,
    320      cpi->oxcf.q_cfg.use_fixed_qp_offsets, is_stat_consumption_stage(cpi),
    321      cpi->oxcf.tune_cfg.tuning);
    322 }
    323 
    324 static inline int do_split_check(BLOCK_SIZE bsize) {
    325  return (bsize == BLOCK_16X16 || bsize == BLOCK_32X32);
    326 }
    327 
    328 #if !CONFIG_REALTIME_ONLY
    329 static inline const FIRSTPASS_STATS *read_one_frame_stats(const TWO_PASS *p,
    330                                                          int frm) {
    331  assert(frm >= 0);
    332  if (frm < 0 ||
    333      p->stats_buf_ctx->stats_in_start + frm > p->stats_buf_ctx->stats_in_end) {
    334    return NULL;
    335  }
    336 
    337  return &p->stats_buf_ctx->stats_in_start[frm];
    338 }
    339 
    340 int av1_get_rdmult_delta(AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row,
    341                         int mi_col, int orig_rdmult);
    342 
    343 int av1_active_h_edge(const AV1_COMP *cpi, int mi_row, int mi_step);
    344 
    345 int av1_active_v_edge(const AV1_COMP *cpi, int mi_col, int mi_step);
    346 
    347 void av1_get_tpl_stats_sb(AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row,
    348                          int mi_col, SuperBlockEnc *sb_enc);
    349 
    350 int av1_get_q_for_deltaq_objective(AV1_COMP *const cpi, ThreadData *td,
    351                                   int64_t *delta_dist, BLOCK_SIZE bsize,
    352                                   int mi_row, int mi_col);
    353 
    354 int av1_get_q_for_hdr(AV1_COMP *const cpi, MACROBLOCK *const x,
    355                      BLOCK_SIZE bsize, int mi_row, int mi_col);
    356 
    357 int av1_get_cb_rdmult(const AV1_COMP *const cpi, MACROBLOCK *const x,
    358                      const BLOCK_SIZE bsize, const int mi_row,
    359                      const int mi_col);
    360 #endif  // !CONFIG_REALTIME_ONLY
    361 
    362 void av1_set_ssim_rdmult(const AV1_COMP *const cpi, int *errorperbit,
    363                         const BLOCK_SIZE bsize, const int mi_row,
    364                         const int mi_col, int *const rdmult);
    365 
    366 #if CONFIG_SALIENCY_MAP
    367 void av1_set_saliency_map_vmaf_rdmult(const AV1_COMP *const cpi,
    368                                      int *errorperbit, const BLOCK_SIZE bsize,
    369                                      const int mi_row, const int mi_col,
    370                                      int *const rdmult);
    371 #endif
    372 
    373 void av1_update_state(const AV1_COMP *const cpi, ThreadData *td,
    374                      const PICK_MODE_CONTEXT *const ctx, int mi_row,
    375                      int mi_col, BLOCK_SIZE bsize, RUN_TYPE dry_run);
    376 
    377 void av1_update_inter_mode_stats(FRAME_CONTEXT *fc, FRAME_COUNTS *counts,
    378                                 PREDICTION_MODE mode, int16_t mode_context);
    379 
    380 void av1_sum_intra_stats(const AV1_COMMON *const cm, FRAME_COUNTS *counts,
    381                         MACROBLOCKD *xd, const MB_MODE_INFO *const mbmi,
    382                         const MB_MODE_INFO *above_mi,
    383                         const MB_MODE_INFO *left_mi, const int intraonly);
    384 
    385 void av1_restore_context(MACROBLOCK *x, const RD_SEARCH_MACROBLOCK_CONTEXT *ctx,
    386                         int mi_row, int mi_col, BLOCK_SIZE bsize,
    387                         const int num_planes);
    388 
    389 void av1_save_context(const MACROBLOCK *x, RD_SEARCH_MACROBLOCK_CONTEXT *ctx,
    390                      int mi_row, int mi_col, BLOCK_SIZE bsize,
    391                      const int num_planes);
    392 
    393 void av1_set_fixed_partitioning(AV1_COMP *cpi, const TileInfo *const tile,
    394                                MB_MODE_INFO **mib, int mi_row, int mi_col,
    395                                BLOCK_SIZE bsize);
    396 
    397 int av1_is_leaf_split_partition(AV1_COMMON *cm, int mi_row, int mi_col,
    398                                BLOCK_SIZE bsize);
    399 
    400 void av1_reset_simple_motion_tree_partition(SIMPLE_MOTION_DATA_TREE *sms_tree,
    401                                            BLOCK_SIZE bsize);
    402 
    403 void av1_update_picked_ref_frames_mask(MACROBLOCK *const x, int ref_type,
    404                                       BLOCK_SIZE bsize, int mib_size,
    405                                       int mi_row, int mi_col);
    406 
    407 void av1_avg_cdf_symbols(FRAME_CONTEXT *ctx_left, FRAME_CONTEXT *ctx_tr,
    408                         int wt_left, int wt_tr);
    409 
    410 void av1_source_content_sb(AV1_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data,
    411                           int mi_row, int mi_col);
    412 
    413 void av1_reset_mbmi(CommonModeInfoParams *const mi_params, BLOCK_SIZE sb_size,
    414                    int mi_row, int mi_col);
    415 
    416 void av1_backup_sb_state(SB_FIRST_PASS_STATS *sb_fp_stats, const AV1_COMP *cpi,
    417                         ThreadData *td, const TileDataEnc *tile_data,
    418                         int mi_row, int mi_col);
    419 
    420 void av1_restore_sb_state(const SB_FIRST_PASS_STATS *sb_fp_stats, AV1_COMP *cpi,
    421                          ThreadData *td, TileDataEnc *tile_data, int mi_row,
    422                          int mi_col);
    423 
    424 void av1_set_cost_upd_freq(AV1_COMP *cpi, ThreadData *td,
    425                           const TileInfo *const tile_info, const int mi_row,
    426                           const int mi_col);
    427 
    428 void av1_dealloc_src_diff_buf(struct macroblock *mb, int num_planes);
    429 
    430 static inline void av1_dealloc_mb_data(struct macroblock *mb, int num_planes) {
    431  aom_free(mb->txfm_search_info.mb_rd_record);
    432  mb->txfm_search_info.mb_rd_record = NULL;
    433 
    434  aom_free(mb->inter_modes_info);
    435  mb->inter_modes_info = NULL;
    436 
    437  av1_dealloc_src_diff_buf(mb, num_planes);
    438 
    439  aom_free(mb->e_mbd.seg_mask);
    440  mb->e_mbd.seg_mask = NULL;
    441 
    442  aom_free(mb->winner_mode_stats);
    443  mb->winner_mode_stats = NULL;
    444 
    445  aom_free(mb->dqcoeff_buf);
    446  mb->dqcoeff_buf = NULL;
    447 }
    448 
    449 static inline void allocate_winner_mode_stats(const AV1_COMP *cpi,
    450                                              struct macroblock *mb) {
    451  const SPEED_FEATURES *sf = &cpi->sf;
    452  // The winner_mode_stats buffer is not required in these cases.
    453  if (is_stat_generation_stage(cpi) ||
    454      (sf->rt_sf.use_nonrd_pick_mode && !sf->rt_sf.hybrid_intra_pickmode) ||
    455      (sf->winner_mode_sf.multi_winner_mode_type == MULTI_WINNER_MODE_OFF))
    456    return;
    457 
    458  const AV1_COMMON *cm = &cpi->common;
    459  const int winner_mode_count =
    460      winner_mode_count_allowed[sf->winner_mode_sf.multi_winner_mode_type];
    461  CHECK_MEM_ERROR(cm, mb->winner_mode_stats,
    462                  (WinnerModeStats *)aom_malloc(
    463                      winner_mode_count * sizeof(mb->winner_mode_stats[0])));
    464 }
    465 
    466 void av1_alloc_src_diff_buf(const struct AV1Common *cm, struct macroblock *mb);
    467 
    468 static inline void av1_alloc_mb_data(const AV1_COMP *cpi,
    469                                     struct macroblock *mb) {
    470  const AV1_COMMON *cm = &cpi->common;
    471  const SPEED_FEATURES *sf = &cpi->sf;
    472  if (!sf->rt_sf.use_nonrd_pick_mode) {
    473    // Memory for mb_rd_record is allocated only when use_mb_rd_hash sf is
    474    // enabled.
    475    if (sf->rd_sf.use_mb_rd_hash)
    476      CHECK_MEM_ERROR(cm, mb->txfm_search_info.mb_rd_record,
    477                      (MB_RD_RECORD *)aom_malloc(sizeof(MB_RD_RECORD)));
    478    if (!frame_is_intra_only(cm))
    479      CHECK_MEM_ERROR(
    480          cm, mb->inter_modes_info,
    481          (InterModesInfo *)aom_malloc(sizeof(*mb->inter_modes_info)));
    482  }
    483 
    484  av1_alloc_src_diff_buf(cm, mb);
    485 
    486  CHECK_MEM_ERROR(cm, mb->e_mbd.seg_mask,
    487                  (uint8_t *)aom_memalign(
    488                      16, 2 * MAX_SB_SQUARE * sizeof(mb->e_mbd.seg_mask[0])));
    489 
    490  allocate_winner_mode_stats(cpi, mb);
    491 
    492  const int max_sb_square_y = 1
    493                              << num_pels_log2_lookup[cm->seq_params->sb_size];
    494  CHECK_MEM_ERROR(
    495      cm, mb->dqcoeff_buf,
    496      (tran_low_t *)aom_memalign(32, max_sb_square_y * sizeof(tran_low_t)));
    497 }
    498 
    499 // This function will compute the number of reference frames to be disabled
    500 // based on selective_ref_frame speed feature.
    501 static inline unsigned int get_num_refs_to_disable(
    502    const AV1_COMP *cpi, const int *ref_frame_flags,
    503    const unsigned int *ref_display_order_hint,
    504    unsigned int cur_frame_display_index) {
    505  unsigned int num_refs_to_disable = 0;
    506  if (cpi->sf.inter_sf.selective_ref_frame >= 3) {
    507    num_refs_to_disable++;
    508    if (cpi->sf.inter_sf.selective_ref_frame >= 6) {
    509      // Disable LAST2_FRAME  and ALTREF2_FRAME
    510      num_refs_to_disable += 2;
    511    } else if (cpi->sf.inter_sf.selective_ref_frame == 5 &&
    512               *ref_frame_flags & av1_ref_frame_flag_list[LAST2_FRAME]) {
    513      const int last2_frame_dist = av1_encoder_get_relative_dist(
    514          ref_display_order_hint[LAST2_FRAME - LAST_FRAME],
    515          cur_frame_display_index);
    516      // Disable LAST2_FRAME if it is a temporally distant frame
    517      if (abs(last2_frame_dist) > 2) {
    518        num_refs_to_disable++;
    519      }
    520 #if !CONFIG_REALTIME_ONLY
    521      else if (is_stat_consumption_stage_twopass(cpi)) {
    522        const FIRSTPASS_STATS *const this_frame_stats =
    523            read_one_frame_stats(&cpi->ppi->twopass, cur_frame_display_index);
    524        const double coded_error_per_mb = this_frame_stats->coded_error;
    525        // Disable LAST2_FRAME if the coded error of the current frame based on
    526        // first pass stats is very low.
    527        if (coded_error_per_mb < 100.0) num_refs_to_disable++;
    528      }
    529 #endif  // CONFIG_REALTIME_ONLY
    530    }
    531  }
    532  return num_refs_to_disable;
    533 }
    534 
    535 static inline int get_max_allowed_ref_frames(
    536    const AV1_COMP *cpi, const int *ref_frame_flags,
    537    const unsigned int *ref_display_order_hint,
    538    unsigned int cur_frame_display_index) {
    539  const unsigned int max_reference_frames =
    540      cpi->oxcf.ref_frm_cfg.max_reference_frames;
    541  const unsigned int num_refs_to_disable = get_num_refs_to_disable(
    542      cpi, ref_frame_flags, ref_display_order_hint, cur_frame_display_index);
    543  const unsigned int max_allowed_refs_for_given_speed =
    544      INTER_REFS_PER_FRAME - num_refs_to_disable;
    545  return AOMMIN(max_allowed_refs_for_given_speed, max_reference_frames);
    546 }
    547 
    548 // Enforce the number of references for each arbitrary frame based on user
    549 // options and speed.
    550 static inline void enforce_max_ref_frames(
    551    AV1_COMP *cpi, int *ref_frame_flags,
    552    const unsigned int *ref_display_order_hint,
    553    unsigned int cur_frame_display_index) {
    554  MV_REFERENCE_FRAME ref_frame;
    555  int total_valid_refs = 0;
    556 
    557  for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
    558    if (*ref_frame_flags & av1_ref_frame_flag_list[ref_frame]) {
    559      total_valid_refs++;
    560    }
    561  }
    562 
    563  const int max_allowed_refs = get_max_allowed_ref_frames(
    564      cpi, ref_frame_flags, ref_display_order_hint, cur_frame_display_index);
    565 
    566  for (int i = 0; i < 4 && total_valid_refs > max_allowed_refs; ++i) {
    567    const MV_REFERENCE_FRAME ref_frame_to_disable = disable_order[i];
    568 
    569    if (!(*ref_frame_flags & av1_ref_frame_flag_list[ref_frame_to_disable])) {
    570      continue;
    571    }
    572 
    573    switch (ref_frame_to_disable) {
    574      case LAST3_FRAME: *ref_frame_flags &= ~AOM_LAST3_FLAG; break;
    575      case LAST2_FRAME: *ref_frame_flags &= ~AOM_LAST2_FLAG; break;
    576      case ALTREF2_FRAME: *ref_frame_flags &= ~AOM_ALT2_FLAG; break;
    577      case BWDREF_FRAME: *ref_frame_flags &= ~AOM_GOLD_FLAG; break;
    578      default: assert(0);
    579    }
    580    --total_valid_refs;
    581  }
    582  assert(total_valid_refs <= max_allowed_refs);
    583 }
    584 
    585 #ifdef __cplusplus
    586 }  // extern "C"
    587 #endif
    588 
    589 #endif  // AOM_AV1_ENCODER_ENCODEFRAME_UTILS_H_