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_segment_rdmult(const AV1_COMP * const cpi,MACROBLOCK * const x,int8_t segment_id)300 static AOM_INLINE int set_segment_rdmult(const AV1_COMP *const cpi,
301 MACROBLOCK *const x,
302 int8_t segment_id) {
303 const AV1_COMMON *const cm = &cpi->common;
304 av1_init_plane_quantizers(cpi, x, segment_id);
305 const int segment_qindex =
306 av1_get_qindex(&cm->seg, segment_id, cm->quant_params.base_qindex);
307 return av1_compute_rd_mult(cpi,
308 segment_qindex + cm->quant_params.y_dc_delta_q);
309 }
310
do_split_check(BLOCK_SIZE bsize)311 static AOM_INLINE int do_split_check(BLOCK_SIZE bsize) {
312 return (bsize == BLOCK_16X16 || bsize == BLOCK_32X32);
313 }
314
315 #if !CONFIG_REALTIME_ONLY
read_one_frame_stats(const TWO_PASS * p,int frm)316 static AOM_INLINE const FIRSTPASS_STATS *read_one_frame_stats(const TWO_PASS *p,
317 int frm) {
318 assert(frm >= 0);
319 if (frm < 0 ||
320 p->stats_buf_ctx->stats_in_start + frm > p->stats_buf_ctx->stats_in_end) {
321 return NULL;
322 }
323
324 return &p->stats_buf_ctx->stats_in_start[frm];
325 }
326
327 int av1_get_rdmult_delta(AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row,
328 int mi_col, int orig_rdmult);
329
330 int av1_active_h_edge(const AV1_COMP *cpi, int mi_row, int mi_step);
331
332 int av1_active_v_edge(const AV1_COMP *cpi, int mi_col, int mi_step);
333
334 void av1_get_tpl_stats_sb(AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row,
335 int mi_col, SuperBlockEnc *sb_enc);
336
337 int av1_get_q_for_deltaq_objective(AV1_COMP *const cpi, BLOCK_SIZE bsize,
338 int mi_row, int mi_col);
339
340 int av1_get_hier_tpl_rdmult(const AV1_COMP *const cpi, MACROBLOCK *const x,
341 const BLOCK_SIZE bsize, const int mi_row,
342 const int mi_col, int orig_rdmult);
343 #endif // !CONFIG_REALTIME_ONLY
344
345 void av1_set_ssim_rdmult(const AV1_COMP *const cpi, int *errorperbit,
346 const BLOCK_SIZE bsize, const int mi_row,
347 const int mi_col, int *const rdmult);
348
349 void av1_update_state(const AV1_COMP *const cpi, ThreadData *td,
350 const PICK_MODE_CONTEXT *const ctx, int mi_row,
351 int mi_col, BLOCK_SIZE bsize, RUN_TYPE dry_run);
352
353 void av1_update_inter_mode_stats(FRAME_CONTEXT *fc, FRAME_COUNTS *counts,
354 PREDICTION_MODE mode, int16_t mode_context);
355
356 void av1_sum_intra_stats(const AV1_COMMON *const cm, FRAME_COUNTS *counts,
357 MACROBLOCKD *xd, const MB_MODE_INFO *const mbmi,
358 const MB_MODE_INFO *above_mi,
359 const MB_MODE_INFO *left_mi, const int intraonly);
360
361 void av1_restore_context(MACROBLOCK *x, const RD_SEARCH_MACROBLOCK_CONTEXT *ctx,
362 int mi_row, int mi_col, BLOCK_SIZE bsize,
363 const int num_planes);
364
365 void av1_save_context(const MACROBLOCK *x, RD_SEARCH_MACROBLOCK_CONTEXT *ctx,
366 int mi_row, int mi_col, BLOCK_SIZE bsize,
367 const int num_planes);
368
369 void av1_set_fixed_partitioning(AV1_COMP *cpi, const TileInfo *const tile,
370 MB_MODE_INFO **mib, int mi_row, int mi_col,
371 BLOCK_SIZE bsize);
372
373 int av1_is_leaf_split_partition(AV1_COMMON *cm, int mi_row, int mi_col,
374 BLOCK_SIZE bsize);
375
376 void av1_reset_simple_motion_tree_partition(SIMPLE_MOTION_DATA_TREE *sms_tree,
377 BLOCK_SIZE bsize);
378
379 void av1_update_picked_ref_frames_mask(MACROBLOCK *const x, int ref_type,
380 BLOCK_SIZE bsize, int mib_size,
381 int mi_row, int mi_col);
382
383 void av1_avg_cdf_symbols(FRAME_CONTEXT *ctx_left, FRAME_CONTEXT *ctx_tr,
384 int wt_left, int wt_tr);
385
386 void av1_source_content_sb(AV1_COMP *cpi, MACROBLOCK *x, int offset);
387
388 void av1_reset_mbmi(CommonModeInfoParams *const mi_params, BLOCK_SIZE sb_size,
389 int mi_row, int mi_col);
390
391 void av1_backup_sb_state(SB_FIRST_PASS_STATS *sb_fp_stats, const AV1_COMP *cpi,
392 ThreadData *td, const TileDataEnc *tile_data,
393 int mi_row, int mi_col);
394
395 void av1_restore_sb_state(const SB_FIRST_PASS_STATS *sb_fp_stats, AV1_COMP *cpi,
396 ThreadData *td, TileDataEnc *tile_data, int mi_row,
397 int mi_col);
398
399 void av1_set_cost_upd_freq(AV1_COMP *cpi, ThreadData *td,
400 const TileInfo *const tile_info, const int mi_row,
401 const int mi_col);
402
av1_dealloc_mb_data(struct AV1Common * cm,struct macroblock * mb)403 static AOM_INLINE void av1_dealloc_mb_data(struct AV1Common *cm,
404 struct macroblock *mb) {
405 aom_free(mb->txfm_search_info.txb_rd_records);
406 mb->txfm_search_info.txb_rd_records = NULL;
407
408 aom_free(mb->inter_modes_info);
409 mb->inter_modes_info = NULL;
410
411 const int num_planes = av1_num_planes(cm);
412 for (int plane = 0; plane < num_planes; plane++) {
413 aom_free(mb->plane[plane].src_diff);
414 mb->plane[plane].src_diff = NULL;
415 }
416
417 aom_free(mb->e_mbd.seg_mask);
418 mb->e_mbd.seg_mask = NULL;
419
420 aom_free(mb->winner_mode_stats);
421 mb->winner_mode_stats = NULL;
422 }
423
av1_alloc_mb_data(struct AV1Common * cm,struct macroblock * mb,int use_nonrd_pick_mode)424 static AOM_INLINE void av1_alloc_mb_data(struct AV1Common *cm,
425 struct macroblock *mb,
426 int use_nonrd_pick_mode) {
427 if (!use_nonrd_pick_mode) {
428 mb->txfm_search_info.txb_rd_records =
429 (TxbRdRecords *)aom_malloc(sizeof(TxbRdRecords));
430 if (!frame_is_intra_only(cm))
431 CHECK_MEM_ERROR(
432 cm, mb->inter_modes_info,
433 (InterModesInfo *)aom_malloc(sizeof(*mb->inter_modes_info)));
434 }
435 const int num_planes = av1_num_planes(cm);
436 for (int plane = 0; plane < num_planes; plane++) {
437 const int subsampling_xy =
438 plane ? cm->seq_params->subsampling_x + cm->seq_params->subsampling_y
439 : 0;
440 const int sb_size = MAX_SB_SQUARE >> subsampling_xy;
441 CHECK_MEM_ERROR(cm, mb->plane[plane].src_diff,
442 (int16_t *)aom_memalign(
443 32, sizeof(*mb->plane[plane].src_diff) * sb_size));
444 }
445 CHECK_MEM_ERROR(cm, mb->e_mbd.seg_mask,
446 (uint8_t *)aom_memalign(
447 16, 2 * MAX_SB_SQUARE * sizeof(mb->e_mbd.seg_mask[0])));
448 const int winner_mode_count = frame_is_intra_only(cm)
449 ? MAX_WINNER_MODE_COUNT_INTRA
450 : MAX_WINNER_MODE_COUNT_INTER;
451 CHECK_MEM_ERROR(cm, mb->winner_mode_stats,
452 (WinnerModeStats *)aom_malloc(
453 winner_mode_count * sizeof(mb->winner_mode_stats[0])));
454 }
455
456 // This function will compute the number of reference frames to be disabled
457 // 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)458 static AOM_INLINE unsigned int get_num_refs_to_disable(
459 const AV1_COMP *cpi, const int *ref_frame_flags,
460 const unsigned int *ref_display_order_hint,
461 unsigned int cur_frame_display_index) {
462 unsigned int num_refs_to_disable = 0;
463 if (cpi->sf.inter_sf.selective_ref_frame >= 3) {
464 num_refs_to_disable++;
465 if (cpi->sf.inter_sf.selective_ref_frame >= 6) {
466 // Disable LAST2_FRAME and ALTREF2_FRAME
467 num_refs_to_disable += 2;
468 } else if (cpi->sf.inter_sf.selective_ref_frame == 5 &&
469 *ref_frame_flags & av1_ref_frame_flag_list[LAST2_FRAME]) {
470 const int last2_frame_dist = av1_encoder_get_relative_dist(
471 ref_display_order_hint[LAST2_FRAME - LAST_FRAME],
472 cur_frame_display_index);
473 // Disable LAST2_FRAME if it is a temporally distant frame
474 if (abs(last2_frame_dist) > 2) {
475 num_refs_to_disable++;
476 }
477 #if !CONFIG_REALTIME_ONLY
478 else if (is_stat_consumption_stage_twopass(cpi)) {
479 const FIRSTPASS_STATS *const this_frame_stats =
480 read_one_frame_stats(&cpi->ppi->twopass, cur_frame_display_index);
481 const double coded_error_per_mb = this_frame_stats->coded_error;
482 // Disable LAST2_FRAME if the coded error of the current frame based on
483 // first pass stats is very low.
484 if (coded_error_per_mb < 100.0) num_refs_to_disable++;
485 }
486 #endif // CONFIG_REALTIME_ONLY
487 }
488 }
489 return num_refs_to_disable;
490 }
491
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)492 static INLINE int get_max_allowed_ref_frames(
493 const AV1_COMP *cpi, const int *ref_frame_flags,
494 const unsigned int *ref_display_order_hint,
495 unsigned int cur_frame_display_index) {
496 const unsigned int max_reference_frames =
497 cpi->oxcf.ref_frm_cfg.max_reference_frames;
498 const unsigned int num_refs_to_disable = get_num_refs_to_disable(
499 cpi, ref_frame_flags, ref_display_order_hint, cur_frame_display_index);
500 const unsigned int max_allowed_refs_for_given_speed =
501 INTER_REFS_PER_FRAME - num_refs_to_disable;
502 return AOMMIN(max_allowed_refs_for_given_speed, max_reference_frames);
503 }
504
505 // Enforce the number of references for each arbitrary frame based on user
506 // 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)507 static AOM_INLINE void enforce_max_ref_frames(
508 AV1_COMP *cpi, int *ref_frame_flags,
509 const unsigned int *ref_display_order_hint,
510 unsigned int cur_frame_display_index) {
511 MV_REFERENCE_FRAME ref_frame;
512 int total_valid_refs = 0;
513
514 for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
515 if (*ref_frame_flags & av1_ref_frame_flag_list[ref_frame]) {
516 total_valid_refs++;
517 }
518 }
519
520 const int max_allowed_refs = get_max_allowed_ref_frames(
521 cpi, ref_frame_flags, ref_display_order_hint, cur_frame_display_index);
522
523 for (int i = 0; i < 4 && total_valid_refs > max_allowed_refs; ++i) {
524 const MV_REFERENCE_FRAME ref_frame_to_disable = disable_order[i];
525
526 if (!(*ref_frame_flags & av1_ref_frame_flag_list[ref_frame_to_disable])) {
527 continue;
528 }
529
530 switch (ref_frame_to_disable) {
531 case LAST3_FRAME: *ref_frame_flags &= ~AOM_LAST3_FLAG; break;
532 case LAST2_FRAME: *ref_frame_flags &= ~AOM_LAST2_FLAG; break;
533 case ALTREF2_FRAME: *ref_frame_flags &= ~AOM_ALT2_FLAG; break;
534 case GOLDEN_FRAME: *ref_frame_flags &= ~AOM_GOLD_FLAG; break;
535 default: assert(0);
536 }
537 --total_valid_refs;
538 }
539 assert(total_valid_refs <= max_allowed_refs);
540 }
541
542 #ifdef __cplusplus
543 } // extern "C"
544 #endif
545
546 #endif // AOM_AV1_ENCODER_ENCODEFRAME_UTILS_H_
547