Porting VP9 nonRD mode to AV1
Port NonRD Inter Mode selection process to AV1 from VP9. Several things
are missing. Among them: no interpolation filter search, no intra mode
search, only LAST_FRAME is used for reference, no extra checks for large
SBs, no chroma RDCost, no compount mode search. Speed is at 60-70% of
VP9 speed 8.
Change-Id: Icadc3008e1f24d9d520f1fd812901cfa245d1741
diff --git a/av1/av1.cmake b/av1/av1.cmake
index fb9678a..d5b4413 100644
--- a/av1/av1.cmake
+++ b/av1/av1.cmake
@@ -188,6 +188,7 @@
"${AOM_ROOT}/av1/encoder/rd.c"
"${AOM_ROOT}/av1/encoder/rd.h"
"${AOM_ROOT}/av1/encoder/rdopt.c"
+ "${AOM_ROOT}/av1/encoder/nonrd_pickmode.c"
"${AOM_ROOT}/av1/encoder/rdopt.h"
"${AOM_ROOT}/av1/encoder/reconinter_enc.c"
"${AOM_ROOT}/av1/encoder/reconinter_enc.h"
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index 0dfd7e2..f079d90 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -142,6 +142,8 @@
128 * 16, 128 * 16
};
+enum { PICK_MODE_RD = 0, PICK_MODE_NONRD, PICK_MODE_FAST_NONRD };
+
unsigned int av1_get_sby_perpixel_variance(const AV1_COMP *cpi,
const struct buf_2d *ref,
BLOCK_SIZE bs) {
@@ -507,7 +509,7 @@
MACROBLOCK *const x, int mi_row, int mi_col,
RD_STATS *rd_cost, PARTITION_TYPE partition,
BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx,
- int64_t best_rd, int use_nonrd_pick_mode) {
+ int64_t best_rd, int pick_mode_type) {
AV1_COMMON *const cm = &cpi->common;
const int num_planes = av1_num_planes(cm);
TileInfo *const tile_info = &tile_data->tile_info;
@@ -655,12 +657,19 @@
} else {
// TODO(kyslov): do the same for pick_intra_mode and
// pick_inter_mode_sb_seg_skip
- if (use_nonrd_pick_mode) {
- av1_nonrd_pick_inter_mode_sb(cpi, tile_data, x, mi_row, mi_col, rd_cost,
- bsize, ctx, best_rd);
- } else {
- av1_rd_pick_inter_mode_sb(cpi, tile_data, x, mi_row, mi_col, rd_cost,
- bsize, ctx, best_rd);
+ switch (pick_mode_type) {
+ case PICK_MODE_RD:
+ av1_rd_pick_inter_mode_sb(cpi, tile_data, x, mi_row, mi_col, rd_cost,
+ bsize, ctx, best_rd);
+ break;
+ case PICK_MODE_NONRD:
+ av1_nonrd_pick_inter_mode_sb(cpi, tile_data, x, mi_row, mi_col,
+ rd_cost, bsize, ctx, best_rd);
+ break;
+ case PICK_MODE_FAST_NONRD:
+ av1_fast_nonrd_pick_inter_mode_sb(cpi, tile_data, x, mi_row, mi_col,
+ rd_cost, bsize, ctx, best_rd);
+ break;
}
}
#if CONFIG_COLLECT_COMPONENT_TIMING
@@ -1758,7 +1767,7 @@
mi_row + hbs < cm->mi_rows && mi_col + hbs < cm->mi_cols) {
pc_tree->partitioning = PARTITION_NONE;
pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &none_rdc,
- PARTITION_NONE, bsize, ctx_none, INT64_MAX, 0);
+ PARTITION_NONE, bsize, ctx_none, INT64_MAX, PICK_MODE_RD);
if (none_rdc.rate < INT_MAX) {
none_rdc.rate += x->partition_cost[pl][PARTITION_NONE];
@@ -1774,12 +1783,12 @@
switch (partition) {
case PARTITION_NONE:
pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &last_part_rdc,
- PARTITION_NONE, bsize, ctx_none, INT64_MAX, 0);
+ PARTITION_NONE, bsize, ctx_none, INT64_MAX, PICK_MODE_RD);
break;
case PARTITION_HORZ:
pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &last_part_rdc,
PARTITION_HORZ, subsize, &pc_tree->horizontal[0], INT64_MAX,
- 0);
+ PICK_MODE_RD);
if (last_part_rdc.rate != INT_MAX && bsize >= BLOCK_8X8 &&
mi_row + hbs < cm->mi_rows) {
RD_STATS tmp_rdc;
@@ -1790,7 +1799,7 @@
mi_col, subsize, NULL);
pick_sb_modes(cpi, tile_data, x, mi_row + hbs, mi_col, &tmp_rdc,
PARTITION_HORZ, subsize, &pc_tree->horizontal[1],
- INT64_MAX, 0);
+ INT64_MAX, PICK_MODE_RD);
if (tmp_rdc.rate == INT_MAX || tmp_rdc.dist == INT64_MAX) {
av1_invalid_rd_stats(&last_part_rdc);
break;
@@ -1803,7 +1812,7 @@
case PARTITION_VERT:
pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &last_part_rdc,
PARTITION_VERT, subsize, &pc_tree->vertical[0], INT64_MAX,
- 0);
+ PICK_MODE_RD);
if (last_part_rdc.rate != INT_MAX && bsize >= BLOCK_8X8 &&
mi_col + hbs < cm->mi_cols) {
RD_STATS tmp_rdc;
@@ -1814,7 +1823,8 @@
mi_col, subsize, NULL);
pick_sb_modes(cpi, tile_data, x, mi_row, mi_col + hbs, &tmp_rdc,
PARTITION_VERT, subsize,
- &pc_tree->vertical[bsize > BLOCK_8X8], INT64_MAX, 0);
+ &pc_tree->vertical[bsize > BLOCK_8X8], INT64_MAX,
+ PICK_MODE_RD);
if (tmp_rdc.rate == INT_MAX || tmp_rdc.dist == INT64_MAX) {
av1_invalid_rd_stats(&last_part_rdc);
break;
@@ -1890,7 +1900,7 @@
pc_tree->split[i]->partitioning = PARTITION_NONE;
pick_sb_modes(cpi, tile_data, x, mi_row + y_idx, mi_col + x_idx, &tmp_rdc,
PARTITION_SPLIT, split_subsize, &pc_tree->split[i]->none,
- INT64_MAX, 0);
+ INT64_MAX, PICK_MODE_RD);
restore_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes);
if (tmp_rdc.rate == INT_MAX || tmp_rdc.dist == INT64_MAX) {
@@ -1957,6 +1967,7 @@
BLOCK_SIZE bsize, PC_TREE *pc_tree) {
AV1_COMMON *const cm = &cpi->common;
TileInfo *const tile_info = &tile_data->tile_info;
+ const SPEED_FEATURES *const sf = &cpi->sf;
MACROBLOCK *const x = &td->mb;
MACROBLOCKD *const xd = &x->e_mbd;
const int bs = mi_size_wide[bsize];
@@ -1980,7 +1991,9 @@
switch (partition) {
case PARTITION_NONE:
pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &dummy_cost,
- PARTITION_NONE, bsize, &pc_tree->none, INT64_MAX, 1);
+ PARTITION_NONE, bsize, &pc_tree->none, INT64_MAX,
+ sf->use_fast_nonrd_pick_mode ? PICK_MODE_FAST_NONRD
+ : PICK_MODE_NONRD);
encode_b(cpi, tile_data, td, tp, mi_row, mi_col, 0, bsize, partition,
&pc_tree->none, NULL);
break;
@@ -4632,11 +4645,11 @@
av1_zero(x->txb_rd_record_32X32);
av1_zero(x->txb_rd_record_64X64);
av1_zero(x->txb_rd_record_intra);
+
+ av1_zero(x->picked_ref_frames_mask);
+
+ av1_zero(x->pred_mv);
}
-
- av1_zero(x->picked_ref_frames_mask);
-
- av1_zero(x->pred_mv);
PC_TREE *const pc_root = td->pc_root[mib_size_log2 - MIN_MIB_SIZE_LOG2];
pc_root->index = 0;
@@ -4644,7 +4657,7 @@
sf->simple_motion_search_prune_rect ||
sf->simple_motion_search_early_term_none ||
sf->firstpass_simple_motion_search_early_term) &&
- !frame_is_intra_only(cm)) {
+ !frame_is_intra_only(cm) && !use_nonrd_mode) {
init_simple_motion_search_mvs(pc_root);
}
@@ -4690,7 +4703,6 @@
td->mb.cb_offset = 0;
nonrd_use_partition(cpi, td, tile_data, mi, tp, mi_row, mi_col, sb_size,
pc_root);
-
} else {
const int orig_rdmult = cpi->rd.RDMULT;
x->cb_rdmult = orig_rdmult;
@@ -5210,7 +5222,8 @@
av1_zero(rdc->comp_pred_diff);
// Two pass partition search can be enabled/disabled for different frames.
// Reset this data at frame level to avoid any incorrect usage.
- init_first_partition_pass_stats_tables(cpi, x->first_partition_pass_stats);
+ if (!cpi->sf.use_nonrd_pick_mode)
+ init_first_partition_pass_stats_tables(cpi, x->first_partition_pass_stats);
// Reset the flag.
cpi->intrabc_used = 0;
@@ -5221,7 +5234,8 @@
cm->allow_intrabc &= (cpi->oxcf.enable_intrabc);
- if (cpi->oxcf.pass != 1 && av1_use_hash_me(cm)) {
+ if (cpi->oxcf.pass != 1 && av1_use_hash_me(cm) &&
+ !cpi->sf.use_nonrd_pick_mode) {
// add to hash table
const int pic_width = cpi->source->y_crop_width;
const int pic_height = cpi->source->y_crop_height;
diff --git a/av1/encoder/nonrd_pickmode.c b/av1/encoder/nonrd_pickmode.c
new file mode 100644
index 0000000..dbb9b0b
--- /dev/null
+++ b/av1/encoder/nonrd_pickmode.c
@@ -0,0 +1,1362 @@
+/*
+ * Copyright (c) 2016, Alliance for Open Media. All rights reserved
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "config/aom_dsp_rtcd.h"
+#include "config/av1_rtcd.h"
+
+#include "aom_dsp/aom_dsp_common.h"
+#include "aom_dsp/blend.h"
+#include "aom_mem/aom_mem.h"
+#include "aom_ports/aom_timer.h"
+#include "aom_ports/mem.h"
+#include "aom_ports/system_state.h"
+
+#include "av1/common/mvref_common.h"
+#include "av1/common/pred_common.h"
+#include "av1/common/reconinter.h"
+
+#include "av1/encoder/encodemv.h"
+#include "av1/encoder/rdopt.h"
+#include "av1/encoder/reconinter_enc.h"
+
+extern int g_pick_inter_mode_cnt;
+typedef struct {
+ uint8_t *data;
+ int stride;
+ int in_use;
+} PRED_BUFFER;
+
+typedef struct {
+ PRED_BUFFER *best_pred;
+ PREDICTION_MODE best_mode;
+ TX_SIZE best_tx_size;
+ TX_SIZE best_intra_tx_size;
+ MV_REFERENCE_FRAME best_ref_frame;
+ MV_REFERENCE_FRAME best_second_ref_frame;
+ uint8_t best_mode_skip_txfm;
+ InterpFilters best_pred_filter;
+} BEST_PICKMODE;
+
+typedef struct {
+ MV_REFERENCE_FRAME ref_frame;
+ PREDICTION_MODE pred_mode;
+} REF_MODE;
+
+#define RT_INTER_MODES 9
+static const REF_MODE ref_mode_set[RT_INTER_MODES] = {
+ { LAST_FRAME, NEARESTMV }, { LAST_FRAME, NEARMV },
+ { LAST_FRAME, NEWMV }, { GOLDEN_FRAME, NEARESTMV },
+ { GOLDEN_FRAME, NEARMV }, { GOLDEN_FRAME, NEWMV },
+ { ALTREF_FRAME, NEARESTMV }, { ALTREF_FRAME, NEARMV },
+ { ALTREF_FRAME, NEWMV }
+};
+
+static const THR_MODES mode_idx[REF_FRAMES][4] = {
+ { THR_DC, THR_V_PRED, THR_H_PRED, THR_SMOOTH },
+ { THR_NEARESTMV, THR_NEARMV, THR_GLOBALMV, THR_NEWMV },
+ { THR_NEARESTG, THR_NEARG, THR_GLOBALMV, THR_NEWG },
+ { THR_NEARESTA, THR_NEARA, THR_GLOBALMV, THR_NEWA },
+};
+
+typedef struct {
+ PREDICTION_MODE mode;
+ MV_REFERENCE_FRAME ref_frame[2];
+} MODE_DEFINITION;
+
+static const MODE_DEFINITION av1_mode_order[MAX_MODES] = {
+ { NEARESTMV, { LAST_FRAME, NONE_FRAME } },
+ { NEARESTMV, { LAST2_FRAME, NONE_FRAME } },
+ { NEARESTMV, { LAST3_FRAME, NONE_FRAME } },
+ { NEARESTMV, { BWDREF_FRAME, NONE_FRAME } },
+ { NEARESTMV, { ALTREF2_FRAME, NONE_FRAME } },
+ { NEARESTMV, { ALTREF_FRAME, NONE_FRAME } },
+ { NEARESTMV, { GOLDEN_FRAME, NONE_FRAME } },
+
+ { NEWMV, { LAST_FRAME, NONE_FRAME } },
+ { NEWMV, { LAST2_FRAME, NONE_FRAME } },
+ { NEWMV, { LAST3_FRAME, NONE_FRAME } },
+ { NEWMV, { BWDREF_FRAME, NONE_FRAME } },
+ { NEWMV, { ALTREF2_FRAME, NONE_FRAME } },
+ { NEWMV, { ALTREF_FRAME, NONE_FRAME } },
+ { NEWMV, { GOLDEN_FRAME, NONE_FRAME } },
+
+ { NEARMV, { LAST_FRAME, NONE_FRAME } },
+ { NEARMV, { LAST2_FRAME, NONE_FRAME } },
+ { NEARMV, { LAST3_FRAME, NONE_FRAME } },
+ { NEARMV, { BWDREF_FRAME, NONE_FRAME } },
+ { NEARMV, { ALTREF2_FRAME, NONE_FRAME } },
+ { NEARMV, { ALTREF_FRAME, NONE_FRAME } },
+ { NEARMV, { GOLDEN_FRAME, NONE_FRAME } },
+
+ { GLOBALMV, { LAST_FRAME, NONE_FRAME } },
+ { GLOBALMV, { LAST2_FRAME, NONE_FRAME } },
+ { GLOBALMV, { LAST3_FRAME, NONE_FRAME } },
+ { GLOBALMV, { BWDREF_FRAME, NONE_FRAME } },
+ { GLOBALMV, { ALTREF2_FRAME, NONE_FRAME } },
+ { GLOBALMV, { GOLDEN_FRAME, NONE_FRAME } },
+ { GLOBALMV, { ALTREF_FRAME, NONE_FRAME } },
+
+ // TODO(kyslov): May need to reconsider the order on the modes to check
+
+ { NEAREST_NEARESTMV, { LAST_FRAME, ALTREF_FRAME } },
+ { NEAREST_NEARESTMV, { LAST2_FRAME, ALTREF_FRAME } },
+ { NEAREST_NEARESTMV, { LAST3_FRAME, ALTREF_FRAME } },
+ { NEAREST_NEARESTMV, { GOLDEN_FRAME, ALTREF_FRAME } },
+ { NEAREST_NEARESTMV, { LAST_FRAME, BWDREF_FRAME } },
+ { NEAREST_NEARESTMV, { LAST2_FRAME, BWDREF_FRAME } },
+ { NEAREST_NEARESTMV, { LAST3_FRAME, BWDREF_FRAME } },
+ { NEAREST_NEARESTMV, { GOLDEN_FRAME, BWDREF_FRAME } },
+ { NEAREST_NEARESTMV, { LAST_FRAME, ALTREF2_FRAME } },
+ { NEAREST_NEARESTMV, { LAST2_FRAME, ALTREF2_FRAME } },
+ { NEAREST_NEARESTMV, { LAST3_FRAME, ALTREF2_FRAME } },
+ { NEAREST_NEARESTMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
+
+ { NEAREST_NEARESTMV, { LAST_FRAME, LAST2_FRAME } },
+ { NEAREST_NEARESTMV, { LAST_FRAME, LAST3_FRAME } },
+ { NEAREST_NEARESTMV, { LAST_FRAME, GOLDEN_FRAME } },
+ { NEAREST_NEARESTMV, { BWDREF_FRAME, ALTREF_FRAME } },
+
+ { NEAR_NEARMV, { LAST_FRAME, ALTREF_FRAME } },
+ { NEW_NEARESTMV, { LAST_FRAME, ALTREF_FRAME } },
+ { NEAREST_NEWMV, { LAST_FRAME, ALTREF_FRAME } },
+ { NEW_NEARMV, { LAST_FRAME, ALTREF_FRAME } },
+ { NEAR_NEWMV, { LAST_FRAME, ALTREF_FRAME } },
+ { NEW_NEWMV, { LAST_FRAME, ALTREF_FRAME } },
+ { GLOBAL_GLOBALMV, { LAST_FRAME, ALTREF_FRAME } },
+
+ { NEAR_NEARMV, { LAST2_FRAME, ALTREF_FRAME } },
+ { NEW_NEARESTMV, { LAST2_FRAME, ALTREF_FRAME } },
+ { NEAREST_NEWMV, { LAST2_FRAME, ALTREF_FRAME } },
+ { NEW_NEARMV, { LAST2_FRAME, ALTREF_FRAME } },
+ { NEAR_NEWMV, { LAST2_FRAME, ALTREF_FRAME } },
+ { NEW_NEWMV, { LAST2_FRAME, ALTREF_FRAME } },
+ { GLOBAL_GLOBALMV, { LAST2_FRAME, ALTREF_FRAME } },
+
+ { NEAR_NEARMV, { LAST3_FRAME, ALTREF_FRAME } },
+ { NEW_NEARESTMV, { LAST3_FRAME, ALTREF_FRAME } },
+ { NEAREST_NEWMV, { LAST3_FRAME, ALTREF_FRAME } },
+ { NEW_NEARMV, { LAST3_FRAME, ALTREF_FRAME } },
+ { NEAR_NEWMV, { LAST3_FRAME, ALTREF_FRAME } },
+ { NEW_NEWMV, { LAST3_FRAME, ALTREF_FRAME } },
+ { GLOBAL_GLOBALMV, { LAST3_FRAME, ALTREF_FRAME } },
+
+ { NEAR_NEARMV, { GOLDEN_FRAME, ALTREF_FRAME } },
+ { NEW_NEARESTMV, { GOLDEN_FRAME, ALTREF_FRAME } },
+ { NEAREST_NEWMV, { GOLDEN_FRAME, ALTREF_FRAME } },
+ { NEW_NEARMV, { GOLDEN_FRAME, ALTREF_FRAME } },
+ { NEAR_NEWMV, { GOLDEN_FRAME, ALTREF_FRAME } },
+ { NEW_NEWMV, { GOLDEN_FRAME, ALTREF_FRAME } },
+ { GLOBAL_GLOBALMV, { GOLDEN_FRAME, ALTREF_FRAME } },
+
+ { NEAR_NEARMV, { LAST_FRAME, BWDREF_FRAME } },
+ { NEW_NEARESTMV, { LAST_FRAME, BWDREF_FRAME } },
+ { NEAREST_NEWMV, { LAST_FRAME, BWDREF_FRAME } },
+ { NEW_NEARMV, { LAST_FRAME, BWDREF_FRAME } },
+ { NEAR_NEWMV, { LAST_FRAME, BWDREF_FRAME } },
+ { NEW_NEWMV, { LAST_FRAME, BWDREF_FRAME } },
+ { GLOBAL_GLOBALMV, { LAST_FRAME, BWDREF_FRAME } },
+
+ { NEAR_NEARMV, { LAST2_FRAME, BWDREF_FRAME } },
+ { NEW_NEARESTMV, { LAST2_FRAME, BWDREF_FRAME } },
+ { NEAREST_NEWMV, { LAST2_FRAME, BWDREF_FRAME } },
+ { NEW_NEARMV, { LAST2_FRAME, BWDREF_FRAME } },
+ { NEAR_NEWMV, { LAST2_FRAME, BWDREF_FRAME } },
+ { NEW_NEWMV, { LAST2_FRAME, BWDREF_FRAME } },
+ { GLOBAL_GLOBALMV, { LAST2_FRAME, BWDREF_FRAME } },
+
+ { NEAR_NEARMV, { LAST3_FRAME, BWDREF_FRAME } },
+ { NEW_NEARESTMV, { LAST3_FRAME, BWDREF_FRAME } },
+ { NEAREST_NEWMV, { LAST3_FRAME, BWDREF_FRAME } },
+ { NEW_NEARMV, { LAST3_FRAME, BWDREF_FRAME } },
+ { NEAR_NEWMV, { LAST3_FRAME, BWDREF_FRAME } },
+ { NEW_NEWMV, { LAST3_FRAME, BWDREF_FRAME } },
+ { GLOBAL_GLOBALMV, { LAST3_FRAME, BWDREF_FRAME } },
+
+ { NEAR_NEARMV, { GOLDEN_FRAME, BWDREF_FRAME } },
+ { NEW_NEARESTMV, { GOLDEN_FRAME, BWDREF_FRAME } },
+ { NEAREST_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } },
+ { NEW_NEARMV, { GOLDEN_FRAME, BWDREF_FRAME } },
+ { NEAR_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } },
+ { NEW_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } },
+ { GLOBAL_GLOBALMV, { GOLDEN_FRAME, BWDREF_FRAME } },
+
+ { NEAR_NEARMV, { LAST_FRAME, ALTREF2_FRAME } },
+ { NEW_NEARESTMV, { LAST_FRAME, ALTREF2_FRAME } },
+ { NEAREST_NEWMV, { LAST_FRAME, ALTREF2_FRAME } },
+ { NEW_NEARMV, { LAST_FRAME, ALTREF2_FRAME } },
+ { NEAR_NEWMV, { LAST_FRAME, ALTREF2_FRAME } },
+ { NEW_NEWMV, { LAST_FRAME, ALTREF2_FRAME } },
+ { GLOBAL_GLOBALMV, { LAST_FRAME, ALTREF2_FRAME } },
+
+ { NEAR_NEARMV, { LAST2_FRAME, ALTREF2_FRAME } },
+ { NEW_NEARESTMV, { LAST2_FRAME, ALTREF2_FRAME } },
+ { NEAREST_NEWMV, { LAST2_FRAME, ALTREF2_FRAME } },
+ { NEW_NEARMV, { LAST2_FRAME, ALTREF2_FRAME } },
+ { NEAR_NEWMV, { LAST2_FRAME, ALTREF2_FRAME } },
+ { NEW_NEWMV, { LAST2_FRAME, ALTREF2_FRAME } },
+ { GLOBAL_GLOBALMV, { LAST2_FRAME, ALTREF2_FRAME } },
+
+ { NEAR_NEARMV, { LAST3_FRAME, ALTREF2_FRAME } },
+ { NEW_NEARESTMV, { LAST3_FRAME, ALTREF2_FRAME } },
+ { NEAREST_NEWMV, { LAST3_FRAME, ALTREF2_FRAME } },
+ { NEW_NEARMV, { LAST3_FRAME, ALTREF2_FRAME } },
+ { NEAR_NEWMV, { LAST3_FRAME, ALTREF2_FRAME } },
+ { NEW_NEWMV, { LAST3_FRAME, ALTREF2_FRAME } },
+ { GLOBAL_GLOBALMV, { LAST3_FRAME, ALTREF2_FRAME } },
+
+ { NEAR_NEARMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
+ { NEW_NEARESTMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
+ { NEAREST_NEWMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
+ { NEW_NEARMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
+ { NEAR_NEWMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
+ { NEW_NEWMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
+ { GLOBAL_GLOBALMV, { GOLDEN_FRAME, ALTREF2_FRAME } },
+
+ { NEAR_NEARMV, { LAST_FRAME, LAST2_FRAME } },
+ { NEW_NEARESTMV, { LAST_FRAME, LAST2_FRAME } },
+ { NEAREST_NEWMV, { LAST_FRAME, LAST2_FRAME } },
+ { NEW_NEARMV, { LAST_FRAME, LAST2_FRAME } },
+ { NEAR_NEWMV, { LAST_FRAME, LAST2_FRAME } },
+ { NEW_NEWMV, { LAST_FRAME, LAST2_FRAME } },
+ { GLOBAL_GLOBALMV, { LAST_FRAME, LAST2_FRAME } },
+
+ { NEAR_NEARMV, { LAST_FRAME, LAST3_FRAME } },
+ { NEW_NEARESTMV, { LAST_FRAME, LAST3_FRAME } },
+ { NEAREST_NEWMV, { LAST_FRAME, LAST3_FRAME } },
+ { NEW_NEARMV, { LAST_FRAME, LAST3_FRAME } },
+ { NEAR_NEWMV, { LAST_FRAME, LAST3_FRAME } },
+ { NEW_NEWMV, { LAST_FRAME, LAST3_FRAME } },
+ { GLOBAL_GLOBALMV, { LAST_FRAME, LAST3_FRAME } },
+
+ { NEAR_NEARMV, { LAST_FRAME, GOLDEN_FRAME } },
+ { NEW_NEARESTMV, { LAST_FRAME, GOLDEN_FRAME } },
+ { NEAREST_NEWMV, { LAST_FRAME, GOLDEN_FRAME } },
+ { NEW_NEARMV, { LAST_FRAME, GOLDEN_FRAME } },
+ { NEAR_NEWMV, { LAST_FRAME, GOLDEN_FRAME } },
+ { NEW_NEWMV, { LAST_FRAME, GOLDEN_FRAME } },
+ { GLOBAL_GLOBALMV, { LAST_FRAME, GOLDEN_FRAME } },
+
+ { NEAR_NEARMV, { BWDREF_FRAME, ALTREF_FRAME } },
+ { NEW_NEARESTMV, { BWDREF_FRAME, ALTREF_FRAME } },
+ { NEAREST_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } },
+ { NEW_NEARMV, { BWDREF_FRAME, ALTREF_FRAME } },
+ { NEAR_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } },
+ { NEW_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } },
+ { GLOBAL_GLOBALMV, { BWDREF_FRAME, ALTREF_FRAME } },
+
+ // intra modes
+ { DC_PRED, { INTRA_FRAME, NONE_FRAME } },
+ { PAETH_PRED, { INTRA_FRAME, NONE_FRAME } },
+ { SMOOTH_PRED, { INTRA_FRAME, NONE_FRAME } },
+ { SMOOTH_V_PRED, { INTRA_FRAME, NONE_FRAME } },
+ { SMOOTH_H_PRED, { INTRA_FRAME, NONE_FRAME } },
+ { H_PRED, { INTRA_FRAME, NONE_FRAME } },
+ { V_PRED, { INTRA_FRAME, NONE_FRAME } },
+ { D135_PRED, { INTRA_FRAME, NONE_FRAME } },
+ { D203_PRED, { INTRA_FRAME, NONE_FRAME } },
+ { D157_PRED, { INTRA_FRAME, NONE_FRAME } },
+ { D67_PRED, { INTRA_FRAME, NONE_FRAME } },
+ { D113_PRED, { INTRA_FRAME, NONE_FRAME } },
+ { D45_PRED, { INTRA_FRAME, NONE_FRAME } },
+};
+
+enum {
+ // INTER_ALL = (1 << NEARESTMV) | (1 << NEARMV) | (1 << NEWMV),
+ INTER_NEAREST = (1 << NEARESTMV),
+ INTER_NEAREST_NEW = (1 << NEARESTMV) | (1 << NEWMV),
+ INTER_NEAREST_NEAR = (1 << NEARESTMV) | (1 << NEARMV),
+ INTER_NEAR_NEW = (1 << NEARMV) | (1 << NEWMV),
+};
+
+static INLINE void init_best_pickmode(BEST_PICKMODE *bp) {
+ bp->best_mode = NEARESTMV;
+ bp->best_ref_frame = LAST_FRAME;
+ bp->best_tx_size = TX_SIZES;
+ bp->best_intra_tx_size = TX_SIZES;
+ bp->best_pred_filter = EIGHTTAP_REGULAR;
+ bp->best_mode_skip_txfm = 0;
+ bp->best_second_ref_frame = NONE_FRAME;
+ bp->best_pred = NULL;
+}
+
+static int combined_motion_search(AV1_COMP *cpi, MACROBLOCK *x,
+ BLOCK_SIZE bsize, int mi_row, int mi_col,
+ int_mv *tmp_mv, int *rate_mv,
+ int64_t best_rd_sofar, int use_base_mv) {
+ MACROBLOCKD *xd = &x->e_mbd;
+ const AV1_COMMON *cm = &cpi->common;
+ const int num_planes = av1_num_planes(cm);
+ MB_MODE_INFO *mi = xd->mi[0];
+ struct buf_2d backup_yv12[MAX_MB_PLANE] = { { 0, 0, 0, 0, 0 } };
+ int step_param = cpi->sf.mv.reduce_first_step_size;
+ const int sadpb = x->sadperbit16;
+ MV mvp_full;
+ const int ref = mi->ref_frame[0];
+ const MV ref_mv = av1_get_ref_mv(x, mi->ref_mv_idx).as_mv;
+ MV center_mv;
+ int dis;
+ const MvLimits tmp_mv_limits = x->mv_limits;
+ int rv = 0;
+ int cost_list[5];
+ int search_subpel = 1;
+ const YV12_BUFFER_CONFIG *scaled_ref_frame =
+ av1_get_scaled_ref_frame(cpi, ref);
+
+ step_param = AOMMIN(step_param, cpi->mv_step_param);
+ if (scaled_ref_frame) {
+ int i;
+ // Swap out the reference frame for a version that's been scaled to
+ // match the resolution of the current frame, allowing the existing
+ // motion search code to be used without additional modifications.
+ for (i = 0; i < MAX_MB_PLANE; i++) backup_yv12[i] = xd->plane[i].pre[0];
+ av1_setup_pre_planes(xd, 0, scaled_ref_frame, mi_row, mi_col, NULL,
+ num_planes);
+ }
+ av1_set_mv_search_range(&x->mv_limits, &ref_mv);
+
+ mvp_full = ref_mv;
+
+ mvp_full.col >>= 3;
+ mvp_full.row >>= 3;
+
+ if (!use_base_mv)
+ center_mv = ref_mv;
+ else
+ center_mv = tmp_mv->as_mv;
+
+ av1_full_pixel_search(
+ cpi, x, bsize, &mvp_full, step_param, cpi->sf.mv.search_method, 0, sadpb,
+ cond_cost_list(cpi, cost_list), ¢er_mv, INT_MAX, 0,
+ (MI_SIZE * mi_col), (MI_SIZE * mi_row), 0, &cpi->ss_cfg[SS_CFG_SRC]);
+
+ x->mv_limits = tmp_mv_limits;
+ *tmp_mv = x->best_mv;
+ // calculate the bit cost on motion vector
+ mvp_full.row = tmp_mv->as_mv.row * 8;
+ mvp_full.col = tmp_mv->as_mv.col * 8;
+
+ *rate_mv = av1_mv_bit_cost(&mvp_full, &ref_mv, x->nmv_vec_cost,
+ x->mv_cost_stack, MV_COST_WEIGHT);
+
+ // TODO(kyslov) Account for Rate Mode!
+ rv = !(RDCOST(x->rdmult, (*rate_mv), 0) > best_rd_sofar);
+
+ if (rv && search_subpel) {
+ SUBPEL_FORCE_STOP subpel_force_stop = cpi->sf.mv.subpel_force_stop;
+ cpi->find_fractional_mv_step(
+ x, cm, mi_row, mi_col, &ref_mv, cpi->common.allow_high_precision_mv,
+ x->errorperbit, &cpi->fn_ptr[bsize], subpel_force_stop,
+ cpi->sf.mv.subpel_iters_per_step, cond_cost_list(cpi, cost_list),
+ x->nmv_vec_cost, x->mv_cost_stack, &dis, &x->pred_sse[ref], NULL, NULL,
+ 0, 0, 0, 0, 0, 1);
+ *tmp_mv = x->best_mv;
+ *rate_mv = av1_mv_bit_cost(&tmp_mv->as_mv, &ref_mv, x->nmv_vec_cost,
+ x->mv_cost_stack, MV_COST_WEIGHT);
+ }
+
+ if (scaled_ref_frame) {
+ int i;
+ for (i = 0; i < MAX_MB_PLANE; i++) xd->plane[i].pre[0] = backup_yv12[i];
+ }
+ return rv;
+}
+
+static int search_new_mv(AV1_COMP *cpi, MACROBLOCK *x,
+ int_mv frame_mv[][REF_FRAMES],
+ MV_REFERENCE_FRAME ref_frame, int gf_temporal_ref,
+ BLOCK_SIZE bsize, int mi_row, int mi_col,
+ int best_pred_sad, int *rate_mv,
+ int64_t best_sse_sofar, RD_STATS *best_rdc) {
+ MACROBLOCKD *const xd = &x->e_mbd;
+ MB_MODE_INFO *const mi = xd->mi[0];
+ AV1_COMMON *cm = &cpi->common;
+ (void)best_sse_sofar;
+ if (ref_frame > LAST_FRAME && gf_temporal_ref &&
+ cpi->oxcf.rc_mode == AOM_CBR) {
+ int tmp_sad;
+ int dis;
+ int cost_list[5] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX };
+
+ if (bsize < BLOCK_16X16) return -1;
+
+ tmp_sad = av1_int_pro_motion_estimation(
+ cpi, x, bsize, mi_row, mi_col,
+ &x->mbmi_ext->ref_mv_stack[ref_frame][0].this_mv.as_mv);
+
+ if (tmp_sad > x->pred_mv_sad[LAST_FRAME]) return -1;
+ if (tmp_sad + (num_pels_log2_lookup[bsize] << 4) > best_pred_sad) return -1;
+
+ frame_mv[NEWMV][ref_frame].as_int = mi->mv[0].as_int;
+ MV ref_mv = av1_get_ref_mv(x, 0).as_mv;
+
+ *rate_mv =
+ av1_mv_bit_cost(&frame_mv[NEWMV][ref_frame].as_mv, &ref_mv,
+ x->nmv_vec_cost, x->mv_cost_stack, MV_COST_WEIGHT);
+ frame_mv[NEWMV][ref_frame].as_mv.row >>= 3;
+ frame_mv[NEWMV][ref_frame].as_mv.col >>= 3;
+
+ cpi->find_fractional_mv_step(
+ x, cm, mi_row, mi_col, &ref_mv, cm->allow_high_precision_mv,
+ x->errorperbit, &cpi->fn_ptr[bsize], cpi->sf.mv.subpel_force_stop,
+ cpi->sf.mv.subpel_iters_per_step, cond_cost_list(cpi, cost_list),
+ x->nmv_vec_cost, x->mv_cost_stack, &dis, &x->pred_sse[ref_frame], NULL,
+ NULL, 0, 0, 0, 0, 0, 1);
+ } else if (!combined_motion_search(cpi, x, bsize, mi_row, mi_col,
+ &frame_mv[NEWMV][ref_frame], rate_mv,
+ best_rdc->rdcost, 0)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static INLINE void find_predictors(
+ AV1_COMP *cpi, MACROBLOCK *x, MV_REFERENCE_FRAME ref_frame,
+ int_mv frame_mv[MB_MODE_COUNT][REF_FRAMES], int const_motion[REF_FRAMES],
+ int *ref_frame_skip_mask, const int flag_list[4], TileDataEnc *tile_data,
+ int mi_row, int mi_col, struct buf_2d yv12_mb[4][MAX_MB_PLANE],
+ BLOCK_SIZE bsize, int force_skip_low_temp_var, int comp_pred_allowed) {
+ AV1_COMMON *const cm = &cpi->common;
+ MACROBLOCKD *const xd = &x->e_mbd;
+ MB_MODE_INFO *const mbmi = xd->mi[0];
+ MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
+ const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_yv12_buf(cm, ref_frame);
+ const int num_planes = av1_num_planes(cm);
+ (void)tile_data;
+ (void)const_motion;
+ (void)comp_pred_allowed;
+
+ x->pred_mv_sad[ref_frame] = INT_MAX;
+ frame_mv[NEWMV][ref_frame].as_int = INVALID_MV;
+ // TODO(kyslov) this needs various further optimizations. to be continued..
+ if ((cpi->ref_frame_flags & flag_list[ref_frame]) && (yv12 != NULL)) {
+ const struct scale_factors *const sf =
+ get_ref_scale_factors_const(cm, ref_frame);
+ av1_setup_pred_block(xd, yv12_mb[ref_frame], yv12, mi_row, mi_col, sf, sf,
+ num_planes);
+ av1_find_mv_refs(cm, xd, mbmi, ref_frame, mbmi_ext->ref_mv_count,
+ mbmi_ext->ref_mv_stack, NULL, mbmi_ext->global_mvs, mi_row,
+ mi_col, mbmi_ext->mode_context);
+ av1_find_best_ref_mvs_from_stack(cm->allow_high_precision_mv, mbmi_ext,
+ ref_frame, &frame_mv[NEARESTMV][ref_frame],
+ &frame_mv[NEARMV][ref_frame], 0);
+ // Early exit for golden frame if force_skip_low_temp_var is set.
+ if (!av1_is_scaled(sf) && bsize >= BLOCK_8X8 &&
+ !(force_skip_low_temp_var && ref_frame == GOLDEN_FRAME)) {
+ av1_mv_pred(cpi, x, yv12_mb[ref_frame][0].buf, yv12->y_stride, ref_frame,
+ bsize);
+ }
+ } else {
+ *ref_frame_skip_mask |= (1 << ref_frame);
+ }
+ av1_count_overlappable_neighbors(cm, xd, mi_row, mi_col);
+ mbmi->num_proj_ref = 1;
+}
+
+static void estimate_ref_frame_costs(
+ const AV1_COMMON *cm, const MACROBLOCKD *xd, const MACROBLOCK *x,
+ int segment_id, unsigned int *ref_costs_single,
+ unsigned int (*ref_costs_comp)[REF_FRAMES]) {
+ int seg_ref_active =
+ segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME);
+ if (seg_ref_active) {
+ memset(ref_costs_single, 0, REF_FRAMES * sizeof(*ref_costs_single));
+ int ref_frame;
+ for (ref_frame = 0; ref_frame < REF_FRAMES; ++ref_frame)
+ memset(ref_costs_comp[ref_frame], 0,
+ REF_FRAMES * sizeof((*ref_costs_comp)[0]));
+ } else {
+ int intra_inter_ctx = av1_get_intra_inter_context(xd);
+ ref_costs_single[INTRA_FRAME] = x->intra_inter_cost[intra_inter_ctx][0];
+ unsigned int base_cost = x->intra_inter_cost[intra_inter_ctx][1];
+
+ for (int i = LAST_FRAME; i <= ALTREF_FRAME; ++i)
+ ref_costs_single[i] = base_cost;
+
+ const int ctx_p1 = av1_get_pred_context_single_ref_p1(xd);
+ const int ctx_p2 = av1_get_pred_context_single_ref_p2(xd);
+ const int ctx_p3 = av1_get_pred_context_single_ref_p3(xd);
+ const int ctx_p4 = av1_get_pred_context_single_ref_p4(xd);
+ const int ctx_p5 = av1_get_pred_context_single_ref_p5(xd);
+ const int ctx_p6 = av1_get_pred_context_single_ref_p6(xd);
+
+ // Determine cost of a single ref frame, where frame types are represented
+ // by a tree:
+ // Level 0: add cost whether this ref is a forward or backward ref
+ ref_costs_single[LAST_FRAME] += x->single_ref_cost[ctx_p1][0][0];
+ ref_costs_single[LAST2_FRAME] += x->single_ref_cost[ctx_p1][0][0];
+ ref_costs_single[LAST3_FRAME] += x->single_ref_cost[ctx_p1][0][0];
+ ref_costs_single[GOLDEN_FRAME] += x->single_ref_cost[ctx_p1][0][0];
+ ref_costs_single[BWDREF_FRAME] += x->single_ref_cost[ctx_p1][0][1];
+ ref_costs_single[ALTREF2_FRAME] += x->single_ref_cost[ctx_p1][0][1];
+ ref_costs_single[ALTREF_FRAME] += x->single_ref_cost[ctx_p1][0][1];
+
+ // Level 1: if this ref is forward ref,
+ // add cost whether it is last/last2 or last3/golden
+ ref_costs_single[LAST_FRAME] += x->single_ref_cost[ctx_p3][2][0];
+ ref_costs_single[LAST2_FRAME] += x->single_ref_cost[ctx_p3][2][0];
+ ref_costs_single[LAST3_FRAME] += x->single_ref_cost[ctx_p3][2][1];
+ ref_costs_single[GOLDEN_FRAME] += x->single_ref_cost[ctx_p3][2][1];
+
+ // Level 1: if this ref is backward ref
+ // then add cost whether this ref is altref or backward ref
+ ref_costs_single[BWDREF_FRAME] += x->single_ref_cost[ctx_p2][1][0];
+ ref_costs_single[ALTREF2_FRAME] += x->single_ref_cost[ctx_p2][1][0];
+ ref_costs_single[ALTREF_FRAME] += x->single_ref_cost[ctx_p2][1][1];
+
+ // Level 2: further add cost whether this ref is last or last2
+ ref_costs_single[LAST_FRAME] += x->single_ref_cost[ctx_p4][3][0];
+ ref_costs_single[LAST2_FRAME] += x->single_ref_cost[ctx_p4][3][1];
+
+ // Level 2: last3 or golden
+ ref_costs_single[LAST3_FRAME] += x->single_ref_cost[ctx_p5][4][0];
+ ref_costs_single[GOLDEN_FRAME] += x->single_ref_cost[ctx_p5][4][1];
+
+ // Level 2: bwdref or altref2
+ ref_costs_single[BWDREF_FRAME] += x->single_ref_cost[ctx_p6][5][0];
+ ref_costs_single[ALTREF2_FRAME] += x->single_ref_cost[ctx_p6][5][1];
+
+ if (cm->current_frame.reference_mode != SINGLE_REFERENCE) {
+ // Similar to single ref, determine cost of compound ref frames.
+ // cost_compound_refs = cost_first_ref + cost_second_ref
+ const int bwdref_comp_ctx_p = av1_get_pred_context_comp_bwdref_p(xd);
+ const int bwdref_comp_ctx_p1 = av1_get_pred_context_comp_bwdref_p1(xd);
+ const int ref_comp_ctx_p = av1_get_pred_context_comp_ref_p(xd);
+ const int ref_comp_ctx_p1 = av1_get_pred_context_comp_ref_p1(xd);
+ const int ref_comp_ctx_p2 = av1_get_pred_context_comp_ref_p2(xd);
+
+ const int comp_ref_type_ctx = av1_get_comp_reference_type_context(xd);
+ unsigned int ref_bicomp_costs[REF_FRAMES] = { 0 };
+
+ ref_bicomp_costs[LAST_FRAME] = ref_bicomp_costs[LAST2_FRAME] =
+ ref_bicomp_costs[LAST3_FRAME] = ref_bicomp_costs[GOLDEN_FRAME] =
+ base_cost + x->comp_ref_type_cost[comp_ref_type_ctx][1];
+ ref_bicomp_costs[BWDREF_FRAME] = ref_bicomp_costs[ALTREF2_FRAME] = 0;
+ ref_bicomp_costs[ALTREF_FRAME] = 0;
+
+ // cost of first ref frame
+ ref_bicomp_costs[LAST_FRAME] += x->comp_ref_cost[ref_comp_ctx_p][0][0];
+ ref_bicomp_costs[LAST2_FRAME] += x->comp_ref_cost[ref_comp_ctx_p][0][0];
+ ref_bicomp_costs[LAST3_FRAME] += x->comp_ref_cost[ref_comp_ctx_p][0][1];
+ ref_bicomp_costs[GOLDEN_FRAME] += x->comp_ref_cost[ref_comp_ctx_p][0][1];
+
+ ref_bicomp_costs[LAST_FRAME] += x->comp_ref_cost[ref_comp_ctx_p1][1][0];
+ ref_bicomp_costs[LAST2_FRAME] += x->comp_ref_cost[ref_comp_ctx_p1][1][1];
+
+ ref_bicomp_costs[LAST3_FRAME] += x->comp_ref_cost[ref_comp_ctx_p2][2][0];
+ ref_bicomp_costs[GOLDEN_FRAME] += x->comp_ref_cost[ref_comp_ctx_p2][2][1];
+
+ // cost of second ref frame
+ ref_bicomp_costs[BWDREF_FRAME] +=
+ x->comp_bwdref_cost[bwdref_comp_ctx_p][0][0];
+ ref_bicomp_costs[ALTREF2_FRAME] +=
+ x->comp_bwdref_cost[bwdref_comp_ctx_p][0][0];
+ ref_bicomp_costs[ALTREF_FRAME] +=
+ x->comp_bwdref_cost[bwdref_comp_ctx_p][0][1];
+
+ ref_bicomp_costs[BWDREF_FRAME] +=
+ x->comp_bwdref_cost[bwdref_comp_ctx_p1][1][0];
+ ref_bicomp_costs[ALTREF2_FRAME] +=
+ x->comp_bwdref_cost[bwdref_comp_ctx_p1][1][1];
+
+ // cost: if one ref frame is forward ref, the other ref is backward ref
+ int ref0, ref1;
+ for (ref0 = LAST_FRAME; ref0 <= GOLDEN_FRAME; ++ref0) {
+ for (ref1 = BWDREF_FRAME; ref1 <= ALTREF_FRAME; ++ref1) {
+ ref_costs_comp[ref0][ref1] =
+ ref_bicomp_costs[ref0] + ref_bicomp_costs[ref1];
+ }
+ }
+
+ // cost: if both ref frames are the same side.
+ const int uni_comp_ref_ctx_p = av1_get_pred_context_uni_comp_ref_p(xd);
+ const int uni_comp_ref_ctx_p1 = av1_get_pred_context_uni_comp_ref_p1(xd);
+ const int uni_comp_ref_ctx_p2 = av1_get_pred_context_uni_comp_ref_p2(xd);
+ ref_costs_comp[LAST_FRAME][LAST2_FRAME] =
+ base_cost + x->comp_ref_type_cost[comp_ref_type_ctx][0] +
+ x->uni_comp_ref_cost[uni_comp_ref_ctx_p][0][0] +
+ x->uni_comp_ref_cost[uni_comp_ref_ctx_p1][1][0];
+ ref_costs_comp[LAST_FRAME][LAST3_FRAME] =
+ base_cost + x->comp_ref_type_cost[comp_ref_type_ctx][0] +
+ x->uni_comp_ref_cost[uni_comp_ref_ctx_p][0][0] +
+ x->uni_comp_ref_cost[uni_comp_ref_ctx_p1][1][1] +
+ x->uni_comp_ref_cost[uni_comp_ref_ctx_p2][2][0];
+ ref_costs_comp[LAST_FRAME][GOLDEN_FRAME] =
+ base_cost + x->comp_ref_type_cost[comp_ref_type_ctx][0] +
+ x->uni_comp_ref_cost[uni_comp_ref_ctx_p][0][0] +
+ x->uni_comp_ref_cost[uni_comp_ref_ctx_p1][1][1] +
+ x->uni_comp_ref_cost[uni_comp_ref_ctx_p2][2][1];
+ ref_costs_comp[BWDREF_FRAME][ALTREF_FRAME] =
+ base_cost + x->comp_ref_type_cost[comp_ref_type_ctx][0] +
+ x->uni_comp_ref_cost[uni_comp_ref_ctx_p][0][1];
+ } else {
+ int ref0, ref1;
+ for (ref0 = LAST_FRAME; ref0 <= GOLDEN_FRAME; ++ref0) {
+ for (ref1 = BWDREF_FRAME; ref1 <= ALTREF_FRAME; ++ref1)
+ ref_costs_comp[ref0][ref1] = 512;
+ }
+ ref_costs_comp[LAST_FRAME][LAST2_FRAME] = 512;
+ ref_costs_comp[LAST_FRAME][LAST3_FRAME] = 512;
+ ref_costs_comp[LAST_FRAME][GOLDEN_FRAME] = 512;
+ ref_costs_comp[BWDREF_FRAME][ALTREF_FRAME] = 512;
+ }
+ }
+}
+
+static void model_rd_from_sse(const AV1_COMP *const cpi,
+ const MACROBLOCK *const x, BLOCK_SIZE plane_bsize,
+ int plane, int64_t sse, int num_samples,
+ int *rate, int64_t *dist) {
+ (void)num_samples;
+ (void)cpi;
+ const MACROBLOCKD *const xd = &x->e_mbd;
+ const struct macroblockd_plane *const pd = &xd->plane[plane];
+ const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3;
+
+ av1_model_rd_from_var_lapndz(sse, num_pels_log2_lookup[plane_bsize],
+ pd->dequant_Q3[1] >> dequant_shift, rate, dist);
+ *dist <<= 4;
+}
+
+static void model_rd_for_sb(const AV1_COMP *const cpi, BLOCK_SIZE bsize,
+ MACROBLOCK *x, MACROBLOCKD *xd, int plane_from,
+ int plane_to, int mi_row, int mi_col,
+ int *out_rate_sum, int64_t *out_dist_sum,
+ int *skip_txfm_sb, int64_t *skip_sse_sb,
+ int *plane_rate, int64_t *plane_sse,
+ int64_t *plane_dist) {
+ // Note our transform coeffs are 8 times an orthogonal transform.
+ // Hence quantizer step is also 8 times. To get effective quantizer
+ // we need to divide by 8 before sending to modeling function.
+ int plane;
+ (void)mi_row;
+ (void)mi_col;
+ const int ref = xd->mi[0]->ref_frame[0];
+
+ int64_t rate_sum = 0;
+ int64_t dist_sum = 0;
+ int64_t total_sse = 0;
+
+ for (plane = plane_from; plane <= plane_to; ++plane) {
+ struct macroblock_plane *const p = &x->plane[plane];
+ struct macroblockd_plane *const pd = &xd->plane[plane];
+ const BLOCK_SIZE plane_bsize =
+ get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y);
+ const int bw = block_size_wide[plane_bsize];
+ const int bh = block_size_high[plane_bsize];
+ int64_t sse;
+ int rate;
+ int64_t dist;
+
+ if (x->skip_chroma_rd && plane) continue;
+
+ if (is_cur_buf_hbd(xd)) {
+ sse = aom_highbd_sse(p->src.buf, p->src.stride, pd->dst.buf,
+ pd->dst.stride, bw, bh);
+ } else {
+ sse = aom_sse(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride, bw,
+ bh);
+ }
+ sse = ROUND_POWER_OF_TWO(sse, (xd->bd - 8) * 2);
+
+ model_rd_from_sse(cpi, x, plane_bsize, plane, sse, bw * bh, &rate, &dist);
+
+ if (plane == 0) x->pred_sse[ref] = (unsigned int)AOMMIN(sse, UINT_MAX);
+
+ total_sse += sse;
+ rate_sum += rate;
+ dist_sum += dist;
+ if (plane_rate) plane_rate[plane] = rate;
+ if (plane_sse) plane_sse[plane] = sse;
+ if (plane_dist) plane_dist[plane] = dist;
+ assert(rate_sum >= 0);
+ }
+
+ if (skip_txfm_sb) *skip_txfm_sb = total_sse == 0;
+ if (skip_sse_sb) *skip_sse_sb = total_sse << 4;
+ rate_sum = AOMMIN(rate_sum, INT_MAX);
+ *out_rate_sum = (int)rate_sum;
+ *out_dist_sum = dist_sum;
+}
+
+static void block_yrd(AV1_COMP *cpi, MACROBLOCK *x, int mi_row, int mi_col,
+ RD_STATS *this_rdc, int *skippable, int64_t *sse,
+ BLOCK_SIZE bsize, TX_SIZE tx_size, int rd_computed) {
+ MACROBLOCKD *xd = &x->e_mbd;
+ const struct macroblockd_plane *pd = &xd->plane[0];
+ struct macroblock_plane *const p = &x->plane[0];
+ const int num_4x4_w = mi_size_wide[bsize];
+ const int num_4x4_h = mi_size_high[bsize];
+ const int step = 1 << (tx_size << 1);
+ const int block_step = (1 << tx_size);
+ int block = 0, r, c;
+ const int max_blocks_wide =
+ num_4x4_w + (xd->mb_to_right_edge >= 0 ? 0 : xd->mb_to_right_edge >> 5);
+ const int max_blocks_high =
+ num_4x4_h + (xd->mb_to_bottom_edge >= 0 ? 0 : xd->mb_to_bottom_edge >> 5);
+ int eob_cost = 0;
+ const int bw = 4 * num_4x4_w;
+ const int bh = 4 * num_4x4_h;
+
+ assert(tx_size > 0 && tx_size <= 4);
+
+ (void)mi_row;
+ (void)mi_col;
+ (void)rd_computed;
+ (void)cpi;
+
+ aom_subtract_block(bh, bw, p->src_diff, bw, p->src.buf, p->src.stride,
+ pd->dst.buf, pd->dst.stride);
+ *skippable = 1;
+ // Keep track of the row and column of the blocks we use so that we know
+ // if we are in the unrestricted motion border.
+ for (r = 0; r < max_blocks_high; r += block_step) {
+ for (c = 0; c < num_4x4_w; c += block_step) {
+ if (c < max_blocks_wide) {
+ const SCAN_ORDER *const scan_order = &av1_default_scan_orders[tx_size];
+ tran_low_t *const coeff = BLOCK_OFFSET(p->coeff, block);
+ tran_low_t *const qcoeff = BLOCK_OFFSET(p->qcoeff, block);
+ tran_low_t *const dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block);
+ uint16_t *const eob = &p->eobs[block];
+ const int diff_stride = bw;
+ const int16_t *src_diff;
+ src_diff = &p->src_diff[(r * diff_stride + c) << 2];
+
+ switch (tx_size) {
+ case TX_64X64:
+ assert(0); // Not implemented
+ break;
+ case TX_32X32:
+ aom_hadamard_32x32(src_diff, diff_stride, coeff);
+ av1_quantize_fp(coeff, 32 * 32, p->zbin_QTX, p->round_fp_QTX,
+ p->quant_fp_QTX, p->quant_shift_QTX, qcoeff,
+ dqcoeff, p->dequant_QTX, eob, scan_order->scan,
+ scan_order->iscan);
+ break;
+ case TX_16X16:
+ aom_hadamard_16x16(src_diff, diff_stride, coeff);
+ av1_quantize_fp(coeff, 16 * 16, p->zbin_QTX, p->round_fp_QTX,
+ p->quant_fp_QTX, p->quant_shift_QTX, qcoeff,
+ dqcoeff, p->dequant_QTX, eob, scan_order->scan,
+ scan_order->iscan);
+ break;
+ case TX_8X8:
+ aom_hadamard_8x8(src_diff, diff_stride, coeff);
+ av1_quantize_fp(coeff, 8 * 8, p->zbin_QTX, p->round_fp_QTX,
+ p->quant_fp_QTX, p->quant_shift_QTX, qcoeff,
+ dqcoeff, p->dequant_QTX, eob, scan_order->scan,
+ scan_order->iscan);
+ break;
+ default: assert(0); break;
+ }
+ *skippable &= (*eob == 0);
+ eob_cost += 1;
+ }
+ block += step;
+ }
+ }
+
+ this_rdc->rate = 0;
+ if (*sse < INT64_MAX) {
+ *sse = (*sse << 6) >> 2;
+ if (*skippable) {
+ this_rdc->dist = *sse;
+ return;
+ }
+ }
+
+ block = 0;
+ this_rdc->dist = 0;
+ for (r = 0; r < max_blocks_high; r += block_step) {
+ for (c = 0; c < num_4x4_w; c += block_step) {
+ if (c < max_blocks_wide) {
+ int64_t dummy;
+ tran_low_t *const coeff = BLOCK_OFFSET(p->coeff, block);
+ tran_low_t *const qcoeff = BLOCK_OFFSET(p->qcoeff, block);
+ tran_low_t *const dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block);
+ uint16_t *const eob = &p->eobs[block];
+
+ if (*eob == 1)
+ this_rdc->rate += (int)abs(qcoeff[0]);
+ else if (*eob > 1)
+ this_rdc->rate += aom_satd(qcoeff, step << 4);
+
+ this_rdc->dist +=
+ av1_block_error(coeff, dqcoeff, step << 4, &dummy) >> 2;
+ }
+ block += step;
+ }
+ }
+
+ // If skippable is set, rate gets clobbered later.
+ this_rdc->rate <<= (2 + AV1_PROB_COST_SHIFT);
+ this_rdc->rate += (eob_cost << AV1_PROB_COST_SHIFT);
+}
+
+static INLINE void init_mbmi(MB_MODE_INFO *mbmi, int mode_index,
+ const AV1_COMMON *cm) {
+ PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info;
+ PREDICTION_MODE this_mode = av1_mode_order[mode_index].mode;
+ mbmi->ref_mv_idx = 0;
+ mbmi->mode = this_mode;
+ mbmi->uv_mode = UV_DC_PRED;
+ mbmi->ref_frame[0] = av1_mode_order[mode_index].ref_frame[0];
+ mbmi->ref_frame[1] = av1_mode_order[mode_index].ref_frame[1];
+ pmi->palette_size[0] = 0;
+ pmi->palette_size[1] = 0;
+ mbmi->filter_intra_mode_info.use_filter_intra = 0;
+ mbmi->mv[0].as_int = mbmi->mv[1].as_int = 0;
+ mbmi->motion_mode = SIMPLE_TRANSLATION;
+ mbmi->num_proj_ref = 1;
+ mbmi->interintra_mode = 0;
+ set_default_interp_filters(mbmi, cm->interp_filter);
+}
+
+static void store_coding_context(MACROBLOCK *x, PICK_MODE_CONTEXT *ctx,
+ int mode_index) {
+ MACROBLOCKD *const xd = &x->e_mbd;
+
+ // Take a snapshot of the coding context so it can be
+ // restored if we decide to encode this way
+ ctx->skip = x->skip;
+ memcpy(ctx->blk_skip, x->blk_skip, sizeof(x->blk_skip[0]) * ctx->num_4x4_blk);
+ ctx->skippable = x->skip;
+ ctx->best_mode_index = mode_index;
+ ctx->mic = *xd->mi[0];
+ ctx->mbmi_ext = *x->mbmi_ext;
+ ctx->comp_pred_diff = 0;
+ ctx->hybrid_pred_diff = 0;
+ ctx->single_pred_diff = 0;
+}
+
+static int get_pred_buffer(PRED_BUFFER *p, int len) {
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (!p[i].in_use) {
+ p[i].in_use = 1;
+ return i;
+ }
+ }
+ return -1;
+}
+
+static void free_pred_buffer(PRED_BUFFER *p) {
+ if (p != NULL) p->in_use = 0;
+}
+
+static int cost_mv_ref(const MACROBLOCK *const x, PREDICTION_MODE mode,
+ int16_t mode_context) {
+ if (is_inter_compound_mode(mode)) {
+ return x
+ ->inter_compound_mode_cost[mode_context][INTER_COMPOUND_OFFSET(mode)];
+ }
+
+ int mode_cost = 0;
+ int16_t mode_ctx = mode_context & NEWMV_CTX_MASK;
+
+ assert(is_inter_mode(mode));
+
+ if (mode == NEWMV) {
+ mode_cost = x->newmv_mode_cost[mode_ctx][0];
+ return mode_cost;
+ } else {
+ mode_cost = x->newmv_mode_cost[mode_ctx][1];
+ mode_ctx = (mode_context >> GLOBALMV_OFFSET) & GLOBALMV_CTX_MASK;
+
+ if (mode == GLOBALMV) {
+ mode_cost += x->zeromv_mode_cost[mode_ctx][0];
+ return mode_cost;
+ } else {
+ mode_cost += x->zeromv_mode_cost[mode_ctx][1];
+ mode_ctx = (mode_context >> REFMV_OFFSET) & REFMV_CTX_MASK;
+ mode_cost += x->refmv_mode_cost[mode_ctx][mode != NEARESTMV];
+ return mode_cost;
+ }
+ }
+}
+
+static void newmv_diff_bias(MACROBLOCKD *xd, PREDICTION_MODE this_mode,
+ RD_STATS *this_rdc, BLOCK_SIZE bsize, int mv_row,
+ int mv_col, int is_last_frame) {
+ // Bias against MVs associated with NEWMV mode that are very different from
+ // top/left neighbors.
+ if (this_mode == NEWMV) {
+ int al_mv_average_row;
+ int al_mv_average_col;
+ int left_row, left_col;
+ int row_diff, col_diff;
+ int above_mv_valid = 0;
+ int left_mv_valid = 0;
+ int above_row = 0;
+ int above_col = 0;
+
+ if (xd->above_mbmi) {
+ above_mv_valid = xd->above_mbmi->mv[0].as_int != INVALID_MV;
+ above_row = xd->above_mbmi->mv[0].as_mv.row;
+ above_col = xd->above_mbmi->mv[0].as_mv.col;
+ }
+ if (xd->left_mbmi) {
+ left_mv_valid = xd->left_mbmi->mv[0].as_int != INVALID_MV;
+ left_row = xd->left_mbmi->mv[0].as_mv.row;
+ left_col = xd->left_mbmi->mv[0].as_mv.col;
+ }
+ if (above_mv_valid && left_mv_valid) {
+ al_mv_average_row = (above_row + left_row + 1) >> 1;
+ al_mv_average_col = (above_col + left_col + 1) >> 1;
+ } else if (above_mv_valid) {
+ al_mv_average_row = above_row;
+ al_mv_average_col = above_col;
+ } else if (left_mv_valid) {
+ al_mv_average_row = left_row;
+ al_mv_average_col = left_col;
+ } else {
+ al_mv_average_row = al_mv_average_col = 0;
+ }
+ row_diff = (al_mv_average_row - mv_row);
+ col_diff = (al_mv_average_col - mv_col);
+ if (row_diff > 48 || row_diff < -48 || col_diff > 48 || col_diff < -48) {
+ if (bsize > BLOCK_32X32)
+ this_rdc->rdcost = this_rdc->rdcost << 1;
+ else
+ this_rdc->rdcost = 5 * this_rdc->rdcost >> 2;
+ }
+ }
+ if (bsize >= BLOCK_16X16 && is_last_frame && mv_row < 16 && mv_row > -16 &&
+ mv_col < 16 && mv_col > -16)
+ this_rdc->rdcost = 7 * (this_rdc->rdcost >> 3);
+}
+
+void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data,
+ MACROBLOCK *x, int mi_row, int mi_col,
+ RD_STATS *rd_cost, BLOCK_SIZE bsize,
+ PICK_MODE_CONTEXT *ctx,
+ int64_t best_rd_so_far) {
+ AV1_COMMON *const cm = &cpi->common;
+ MACROBLOCKD *const xd = &x->e_mbd;
+ MB_MODE_INFO *const mi = xd->mi[0];
+ struct macroblockd_plane *const pd = &xd->plane[0];
+
+ BEST_PICKMODE best_pickmode;
+ int inter_mode_mask[BLOCK_SIZES];
+
+ MV_REFERENCE_FRAME ref_frame;
+ MV_REFERENCE_FRAME usable_ref_frame, second_ref_frame;
+ int_mv frame_mv[MB_MODE_COUNT][REF_FRAMES];
+ uint8_t mode_checked[MB_MODE_COUNT][REF_FRAMES];
+ struct buf_2d yv12_mb[6][MAX_MB_PLANE];
+ static const int flag_list[5] = { 0, AOM_LAST_FLAG, AOM_LAST2_FLAG,
+ AOM_LAST3_FLAG, AOM_GOLD_FLAG };
+ RD_STATS this_rdc, best_rdc;
+ // var_y and sse_y are saved to be used in skipping checking
+ int64_t sse_y = UINT_MAX;
+ const int *const rd_threshes = cpi->rd.threshes[mi->segment_id][bsize];
+ const int *const rd_thresh_freq_fact = tile_data->thresh_freq_fact[bsize];
+
+ InterpFilter filter_ref;
+ int const_motion[REF_FRAMES] = { 0 };
+ int ref_frame_skip_mask = 0;
+ int idx;
+ int best_pred_sad = INT_MAX;
+ int best_early_term = 0;
+ unsigned int ref_costs_single[REF_FRAMES],
+ ref_costs_comp[REF_FRAMES][REF_FRAMES];
+ int use_golden_nonzeromv = 1;
+ int force_skip_low_temp_var = 0;
+ int skip_ref_find_pred[5] = { 0 };
+ int64_t best_sse_sofar = INT64_MAX;
+ int gf_temporal_ref = 0;
+ const struct segmentation *const seg = &cm->seg;
+ int comp_modes = 0;
+ int num_inter_modes = RT_INTER_MODES;
+ unsigned char segment_id = mi->segment_id;
+ InterpFilter best_filter = EIGHTTAP_REGULAR;
+ PRED_BUFFER tmp[4];
+ DECLARE_ALIGNED(16, uint8_t, pred_buf[3 * 64 * 64]);
+ PRED_BUFFER *this_mode_pred = NULL;
+ const int reuse_inter_pred = cpi->sf.reuse_inter_pred_nonrd;
+ const int bh = block_size_high[bsize];
+ const int bw = block_size_wide[bsize];
+ const int pixels_in_block = bh * bw;
+ struct buf_2d orig_dst = pd->dst;
+
+ (void)best_rd_so_far;
+
+ init_best_pickmode(&best_pickmode);
+
+ for (int i = 0; i < BLOCK_SIZES; ++i) inter_mode_mask[i] = INTER_ALL;
+
+ // TODO(kyslov) Move this to Speed Features
+ inter_mode_mask[BLOCK_128X128] = INTER_NEAREST_NEAR;
+
+ x->source_variance = UINT_MAX;
+
+ struct scale_factors *const sf_last = get_ref_scale_factors(cm, LAST_FRAME);
+ struct scale_factors *const sf_golden =
+ get_ref_scale_factors(cm, GOLDEN_FRAME);
+ gf_temporal_ref = 1;
+ // For temporal long term prediction, check that the golden reference
+ // is same scale as last reference, otherwise disable.
+ if ((sf_last->x_scale_fp != sf_golden->x_scale_fp) ||
+ (sf_last->y_scale_fp != sf_golden->y_scale_fp)) {
+ gf_temporal_ref = 0;
+ }
+
+ av1_collect_neighbors_ref_counts(xd);
+ av1_count_overlappable_neighbors(cm, xd, mi_row, mi_col);
+
+ estimate_ref_frame_costs(cm, xd, x, segment_id, ref_costs_single,
+ ref_costs_comp);
+
+ memset(&mode_checked[0][0], 0, MB_MODE_COUNT * REF_FRAMES);
+ if (reuse_inter_pred) {
+ int i;
+ for (i = 0; i < 3; i++) {
+ tmp[i].data = &pred_buf[pixels_in_block * i];
+ tmp[i].stride = bw;
+ tmp[i].in_use = 0;
+ }
+ tmp[3].data = pd->dst.buf;
+ tmp[3].stride = pd->dst.stride;
+ tmp[3].in_use = 0;
+ }
+
+ x->skip = 0;
+
+ // Instead of using av1_get_pred_context_switchable_interp(xd) to assign
+ // filter_ref, we use a less strict condition on assigning filter_ref.
+ // This is to reduce the probabily of entering the flow of not assigning
+ // filter_ref and then skip filter search.
+ filter_ref = cm->interp_filter;
+
+ // initialize mode decisions
+ av1_invalid_rd_stats(&best_rdc);
+ av1_invalid_rd_stats(rd_cost);
+ mi->sb_type = bsize;
+ mi->ref_frame[0] = NONE_FRAME;
+ mi->ref_frame[1] = NONE_FRAME;
+
+ x->source_variance =
+ av1_get_sby_perpixel_variance(cpi, &x->plane[0].src, bsize);
+
+// TODO(kyslov) Refine logic of selecting REF FRAME SET.
+// For now only LAST_FRAME is used
+#if 0
+ if (cpi->rc.frames_since_golden == 0 && gf_temporal_ref) {
+ usable_ref_frame = LAST_FRAME;
+ } else {
+ usable_ref_frame = GOLDEN_FRAME;
+ }
+
+ force_skip_low_temp_var = get_force_skip_low_temp_var(&x->variance_low[0],
+ mi_row, mi_col, bsize);
+ // If force_skip_low_temp_var is set, and for short circuit mode = 1 and 3,
+ // skip golden reference.
+ if (force_skip_low_temp_var) {
+ usable_ref_frame = LAST_FRAME;
+ }
+
+ if (!((cpi->ref_frame_flags & flag_list[GOLDEN_FRAME]) &&
+ !force_skip_low_temp_var))
+ use_golden_nonzeromv = 0;
+
+ // If the segment reference frame feature is enabled and it's set to GOLDEN
+ // reference, then make sure we don't skip checking GOLDEN, this is to
+ // prevent possibility of not picking any mode.
+ if (segfeature_active(seg, mi->segment_id, SEG_LVL_REF_FRAME) &&
+ get_segdata(seg, mi->segment_id, SEG_LVL_REF_FRAME) == GOLDEN_FRAME) {
+ usable_ref_frame = GOLDEN_FRAME;
+ skip_ref_find_pred[GOLDEN_FRAME] = 0;
+ }
+#endif
+ usable_ref_frame = LAST_FRAME;
+
+ for (ref_frame = LAST_FRAME; ref_frame <= usable_ref_frame; ++ref_frame) {
+ // Skip find_predictor if the reference frame is not in the
+ // ref_frame_flags (i.e., not used as a reference for this frame).
+ skip_ref_find_pred[ref_frame] =
+ !(cpi->ref_frame_flags & flag_list[ref_frame]);
+ if (!skip_ref_find_pred[ref_frame]) {
+ find_predictors(cpi, x, ref_frame, frame_mv, const_motion,
+ &ref_frame_skip_mask, flag_list, tile_data, mi_row,
+ mi_col, yv12_mb, bsize, force_skip_low_temp_var,
+ comp_modes > 0);
+ }
+ }
+
+ for (idx = 0; idx < num_inter_modes; ++idx) {
+ int rate_mv = 0;
+ int mode_rd_thresh;
+ int mode_index;
+ int i;
+ int64_t this_sse;
+ int is_skippable;
+ int this_early_term = 0;
+ int rd_computed = 0;
+ int inter_mv_mode = 0;
+ int skip_this_mv = 0;
+ int comp_pred = 0;
+ int force_mv_inter_layer = 0;
+ PREDICTION_MODE this_mode;
+ MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
+ second_ref_frame = NONE_FRAME;
+
+ this_mode = ref_mode_set[idx].pred_mode;
+ ref_frame = ref_mode_set[idx].ref_frame;
+ init_mbmi(mi, idx, cm);
+
+ mi->tx_size = AOMMIN(AOMMIN(max_txsize_lookup[bsize],
+ tx_mode_to_biggest_tx_size[cm->tx_mode]),
+ TX_16X16);
+ memset(mi->inter_tx_size, mi->tx_size, sizeof(mi->inter_tx_size));
+ memset(mi->txk_type, DCT_DCT, sizeof(mi->txk_type[0]) * TXK_TYPE_BUF_LEN);
+ av1_zero(x->blk_skip);
+
+ if (ref_frame > usable_ref_frame) continue;
+ if (skip_ref_find_pred[ref_frame]) continue;
+
+ // If the segment reference frame feature is enabled then do nothing if the
+ // current ref frame is not allowed.
+ if (segfeature_active(seg, mi->segment_id, SEG_LVL_REF_FRAME) &&
+ get_segdata(seg, mi->segment_id, SEG_LVL_REF_FRAME) != (int)ref_frame)
+ continue;
+
+ if (!(cpi->ref_frame_flags & flag_list[ref_frame])) continue;
+
+ if (x->source_variance == 0 && frame_mv[this_mode][ref_frame].as_int != 0) {
+ continue;
+ }
+
+ if (!(inter_mode_mask[bsize] & (1 << this_mode))) continue;
+
+ if (const_motion[ref_frame] && this_mode == NEARMV) continue;
+
+ // Skip non-zeromv mode search for golden frame if force_skip_low_temp_var
+ // is set. If nearestmv for golden frame is 0, zeromv mode will be skipped
+ // later.
+ if (!force_mv_inter_layer && force_skip_low_temp_var &&
+ ref_frame == GOLDEN_FRAME &&
+ frame_mv[this_mode][ref_frame].as_int != 0) {
+ continue;
+ }
+
+// TODO(kyslov) Refine logic of pruning reference .
+// For now only LAST_FRAME is used
+#if 0
+ if (x->content_state_sb != kVeryHighSad &&
+ (cpi->sf.short_circuit_low_temp_var >= 2 ||
+ (cpi->sf.short_circuit_low_temp_var == 1 && bsize == BLOCK_64X64))
+ && force_skip_low_temp_var && ref_frame == LAST_FRAME && this_mode ==
+ NEWMV) { continue;
+ }
+
+ // Disable this drop out case if the ref frame segment level feature is
+ // enabled for this segment. This is to prevent the possibility that we
+ end
+ // up unable to pick any mode.
+ if (!segfeature_active(seg, mi->segment_id, SEG_LVL_REF_FRAME)) {
+ if (sf->reference_masking &&
+ !(frame_mv[this_mode][ref_frame].as_int == 0 &&
+ ref_frame == LAST_FRAME)) {
+ if (usable_ref_frame < ALTREF_FRAME) {
+ if (!force_skip_low_temp_var && usable_ref_frame > LAST_FRAME) {
+ i = (ref_frame == LAST_FRAME) ? GOLDEN_FRAME : LAST_FRAME;
+ if ((cpi->ref_frame_flags & flag_list[i]))
+ if (x->pred_mv_sad[ref_frame] > (x->pred_mv_sad[i] << 1))
+ ref_frame_skip_mask |= (1 << ref_frame);
+ }
+ } else if (!cpi->rc.is_src_frame_alt_ref &&
+ !(frame_mv[this_mode][ref_frame].as_int == 0 &&
+ ref_frame == ALTREF_FRAME)) {
+ int ref1 = (ref_frame == GOLDEN_FRAME) ? LAST_FRAME :
+ GOLDEN_FRAME; int ref2 = (ref_frame == ALTREF_FRAME) ? LAST_FRAME :
+ ALTREF_FRAME; if (((cpi->ref_frame_flags & flag_list[ref1]) &&
+ (x->pred_mv_sad[ref_frame] > (x->pred_mv_sad[ref1] << 1))) ||
+ ((cpi->ref_frame_flags & flag_list[ref2]) &&
+ (x->pred_mv_sad[ref_frame] > (x->pred_mv_sad[ref2] << 1))))
+ ref_frame_skip_mask |= (1 << ref_frame);
+ }
+ }
+ if (ref_frame_skip_mask & (1 << ref_frame)) continue;
+ }
+#endif
+
+ // Select prediction reference frames.
+ for (i = 0; i < MAX_MB_PLANE; i++) {
+ xd->plane[i].pre[0] = yv12_mb[ref_frame][i];
+ }
+
+ mi->ref_frame[0] = ref_frame;
+ mi->ref_frame[1] = second_ref_frame;
+ set_ref_ptrs(cm, xd, ref_frame, second_ref_frame);
+
+ mode_index = mode_idx[ref_frame][INTER_OFFSET(this_mode)];
+ mode_rd_thresh = best_pickmode.best_mode_skip_txfm
+ ? rd_threshes[mode_index] << 1
+ : rd_threshes[mode_index];
+
+ if (rd_less_than_thresh(best_rdc.rdcost, mode_rd_thresh,
+ rd_thresh_freq_fact[mode_index]))
+ if (frame_mv[this_mode][ref_frame].as_int != 0) continue;
+
+ if (this_mode == NEWMV && !force_mv_inter_layer) {
+ if (search_new_mv(cpi, x, frame_mv, ref_frame, gf_temporal_ref, bsize,
+ mi_row, mi_col, best_pred_sad, &rate_mv, best_sse_sofar,
+ &best_rdc))
+ continue;
+ }
+
+ for (inter_mv_mode = NEARESTMV; inter_mv_mode <= NEWMV; inter_mv_mode++) {
+ if (inter_mv_mode == this_mode || comp_pred) continue;
+ if (mode_checked[inter_mv_mode][ref_frame] &&
+ frame_mv[this_mode][ref_frame].as_int ==
+ frame_mv[inter_mv_mode][ref_frame].as_int &&
+ frame_mv[inter_mv_mode][ref_frame].as_int == 0) {
+ skip_this_mv = 1;
+ break;
+ }
+ }
+
+ if (skip_this_mv) continue;
+
+ // If use_golden_nonzeromv is false, NEWMV mode is skipped for golden, no
+ // need to compute best_pred_sad which is only used to skip golden NEWMV.
+ if (use_golden_nonzeromv && this_mode == NEWMV && ref_frame == LAST_FRAME &&
+ frame_mv[NEWMV][LAST_FRAME].as_int != INVALID_MV) {
+ const int pre_stride = xd->plane[0].pre[0].stride;
+ const uint8_t *const pre_buf =
+ xd->plane[0].pre[0].buf +
+ (frame_mv[NEWMV][LAST_FRAME].as_mv.row >> 3) * pre_stride +
+ (frame_mv[NEWMV][LAST_FRAME].as_mv.col >> 3);
+ best_pred_sad = cpi->fn_ptr[bsize].sdf(
+ x->plane[0].src.buf, x->plane[0].src.stride, pre_buf, pre_stride);
+ x->pred_mv_sad[LAST_FRAME] = best_pred_sad;
+ }
+
+ if (this_mode != NEARESTMV && !comp_pred &&
+ frame_mv[this_mode][ref_frame].as_int ==
+ frame_mv[NEARESTMV][ref_frame].as_int)
+ continue;
+
+ mi->mode = this_mode;
+ mi->mv[0].as_int = frame_mv[this_mode][ref_frame].as_int;
+ mi->mv[1].as_int = 0;
+ if (reuse_inter_pred) {
+ if (!this_mode_pred) {
+ this_mode_pred = &tmp[3];
+ } else {
+ this_mode_pred = &tmp[get_pred_buffer(tmp, 3)];
+ pd->dst.buf = this_mode_pred->data;
+ pd->dst.stride = bw;
+ }
+ }
+
+ // TODO(kyslov) bring back filter search
+ mi->interp_filters =
+ (filter_ref == SWITCHABLE) ? EIGHTTAP_REGULAR : filter_ref;
+ av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize,
+ AOM_PLANE_Y, AOM_PLANE_Y);
+
+ // TODO(kyslov) For large partition blocks, extra testing needs to be done
+
+ rd_computed = 1;
+ model_rd_for_sb(cpi, bsize, x, xd, AOM_PLANE_Y, AOM_PLANE_Y, mi_row, mi_col,
+ &this_rdc.rate, &this_rdc.dist, &this_rdc.skip, NULL, NULL,
+ &sse_y, NULL);
+
+ if (sse_y < best_sse_sofar) best_sse_sofar = sse_y;
+
+ const int skip_ctx = av1_get_skip_context(xd);
+ const int skip_cost = x->skip_cost[skip_ctx][1];
+
+ this_sse = (int64_t)sse_y;
+
+ block_yrd(cpi, x, mi_row, mi_col, &this_rdc, &is_skippable, &this_sse,
+ bsize, mi->tx_size, rd_computed);
+
+ x->skip = is_skippable;
+ if (is_skippable) {
+ this_rdc.rate = skip_cost;
+ } else {
+ if (RDCOST(x->rdmult, this_rdc.rate, this_rdc.dist) >=
+ RDCOST(x->rdmult, 0, this_sse)) {
+ x->skip = 1;
+ this_rdc.rate = skip_cost;
+ this_rdc.dist = this_sse;
+ }
+ }
+
+ // TODO(kyslov) account for UV prediction cost
+
+ this_rdc.rate += rate_mv;
+ const int16_t mode_ctx =
+ av1_mode_context_analyzer(mbmi_ext->mode_context, mi->ref_frame);
+ this_rdc.rate += cost_mv_ref(x, this_mode, mode_ctx);
+
+ this_rdc.rate += ref_costs_single[ref_frame];
+
+ this_rdc.rdcost = RDCOST(x->rdmult, this_rdc.rate, this_rdc.dist);
+ if (cpi->oxcf.rc_mode == AOM_CBR && cpi->oxcf.speed >= 8) {
+ newmv_diff_bias(xd, this_mode, &this_rdc, bsize,
+ frame_mv[this_mode][ref_frame].as_mv.row,
+ frame_mv[this_mode][ref_frame].as_mv.col,
+ ref_frame == LAST_FRAME);
+ }
+
+ mode_checked[this_mode][ref_frame] = 1;
+
+ if (this_rdc.rdcost < best_rdc.rdcost) {
+ best_rdc = this_rdc;
+ best_early_term = this_early_term;
+ best_pickmode.best_mode = this_mode;
+ best_pickmode.best_pred_filter = mi->interp_filters;
+ best_pickmode.best_tx_size = mi->tx_size;
+ best_pickmode.best_ref_frame = ref_frame;
+ best_pickmode.best_mode_skip_txfm = x->skip;
+ best_pickmode.best_second_ref_frame = second_ref_frame;
+ if (reuse_inter_pred) {
+ free_pred_buffer(best_pickmode.best_pred);
+ best_pickmode.best_pred = this_mode_pred;
+ }
+ } else {
+ if (reuse_inter_pred) free_pred_buffer(this_mode_pred);
+ }
+ if (best_early_term && idx > 0) {
+ x->skip = 1;
+ break;
+ }
+ }
+
+ mi->mode = best_pickmode.best_mode;
+ mi->interp_filters = av1_broadcast_interp_filter(best_filter);
+ mi->tx_size = best_pickmode.best_tx_size;
+ mi->ref_frame[0] = best_pickmode.best_ref_frame;
+ mi->mv[0].as_int =
+ frame_mv[best_pickmode.best_mode][best_pickmode.best_ref_frame].as_int;
+ mi->ref_frame[1] = best_pickmode.best_second_ref_frame;
+ pd->dst = orig_dst;
+ if (reuse_inter_pred && best_pickmode.best_pred != NULL) {
+ PRED_BUFFER *const best_pred = best_pickmode.best_pred;
+ if (best_pred->data != orig_dst.buf && is_inter_mode(mi->mode)) {
+ aom_convolve_copy(best_pred->data, best_pred->stride, pd->dst.buf,
+ pd->dst.stride, 0, 0, 0, 0, bw, bh);
+ }
+ }
+
+ store_coding_context(x, ctx, mi->mode);
+ *rd_cost = best_rdc;
+}
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 4fcda5a..9a8ca7d 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -34,6 +34,8 @@
#include "av1/encoder/random.h"
#include "av1/encoder/ratectrl.h"
+#define USE_UNRESTRICTED_Q_IN_CQ_MODE 0
+
// Max rate target for 1080P and below encodes under normal circumstances
// (1920 * 1080 / (16 * 16)) * MAX_MB_RATE bits per MB
#define MAX_MB_RATE 250
@@ -1001,6 +1003,28 @@
cpi->common.seq_params.bit_depth);
}
+// This unrestricted Q selection on CQ mode is useful when testing new features,
+// but may lead to Q being out of range on current RC restrictions
+#if USE_UNRESTRICTED_Q_IN_CQ_MODE
+static int rc_pick_q_and_bounds_one_pass_cq(const AV1_COMP *cpi, int width,
+ int height, int *bottom_index,
+ int *top_index) {
+ const AV1_COMMON *const cm = &cpi->common;
+ const RATE_CONTROL *const rc = &cpi->rc;
+ const AV1EncoderConfig *const oxcf = &cpi->oxcf;
+ const int cq_level = get_active_cq_level(rc, oxcf, frame_is_intra_only(cm),
+ cm->superres_scale_denominator);
+ const int bit_depth = cm->seq_params.bit_depth;
+ const int q = (int)av1_convert_qindex_to_q(cq_level, bit_depth);
+ (void)width;
+ (void)height;
+ *top_index = q;
+ *bottom_index = q;
+
+ return q;
+}
+#endif // USE_UNRESTRICTED_Q_IN_CQ_MODE
+
#define STATIC_MOTION_THRESH 95
static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width,
int height, int *bottom_index,
@@ -1270,6 +1294,11 @@
if (cpi->oxcf.rc_mode == AOM_CBR)
q = rc_pick_q_and_bounds_one_pass_cbr(cpi, width, height, bottom_index,
top_index);
+#if USE_UNRESTRICTED_Q_IN_CQ_MODE
+ else if (cpi->oxcf.rc_mode == AOM_CQ)
+ q = rc_pick_q_and_bounds_one_pass_cq(cpi, width, height, bottom_index,
+ top_index);
+#endif // USE_UNRESTRICTED_Q_IN_CQ_MODE
else
q = rc_pick_q_and_bounds_one_pass_vbr(cpi, width, height, bottom_index,
top_index);
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index 012bee8..c3d616d 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -9414,7 +9414,8 @@
assert(mbmi->ref_frame[1] != INTRA_FRAME);
}
- if (cpi->oxcf.enable_obmc == 0 && mbmi->motion_mode == OBMC_CAUSAL)
+ if ((cpi->oxcf.enable_obmc == 0 || cpi->sf.use_fast_nonrd_pick_mode) &&
+ mbmi->motion_mode == OBMC_CAUSAL)
continue;
if (identical_obmc_mv_field_detected) {
@@ -11475,119 +11476,6 @@
x->comp_rd_stats_idx = 0;
}
-// TODO(kyslov): now this is very similar to set_params_rd_pick_inter_mode
-// (except that doesn't set ALTREF parameters)
-// consider passing a flag to select non-rd path (similar to
-// encode_sb_row)
-static void set_params_nonrd_pick_inter_mode(
- const AV1_COMP *cpi, MACROBLOCK *x, HandleInterModeArgs *args,
- BLOCK_SIZE bsize, int mi_row, int mi_col, mode_skip_mask_t *mode_skip_mask,
- int skip_ref_frame_mask, unsigned int ref_costs_single[REF_FRAMES],
- unsigned int ref_costs_comp[REF_FRAMES][REF_FRAMES],
- struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE]) {
- const AV1_COMMON *const cm = &cpi->common;
- const int num_planes = av1_num_planes(cm);
- MACROBLOCKD *const xd = &x->e_mbd;
- MB_MODE_INFO *const mbmi = xd->mi[0];
- MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
- unsigned char segment_id = mbmi->segment_id;
- int dst_width1[MAX_MB_PLANE] = { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE };
- int dst_width2[MAX_MB_PLANE] = { MAX_SB_SIZE >> 1, MAX_SB_SIZE >> 1,
- MAX_SB_SIZE >> 1 };
- int dst_height1[MAX_MB_PLANE] = { MAX_SB_SIZE >> 1, MAX_SB_SIZE >> 1,
- MAX_SB_SIZE >> 1 };
- int dst_height2[MAX_MB_PLANE] = { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE };
-
- for (int i = 0; i < MB_MODE_COUNT; ++i)
- for (int k = 0; k < REF_FRAMES; ++k) args->single_filter[i][k] = SWITCHABLE;
-
- if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
- int len = sizeof(uint16_t);
- args->above_pred_buf[0] = CONVERT_TO_BYTEPTR(x->above_pred_buf);
- args->above_pred_buf[1] =
- CONVERT_TO_BYTEPTR(x->above_pred_buf + (MAX_SB_SQUARE >> 1) * len);
- args->above_pred_buf[2] =
- CONVERT_TO_BYTEPTR(x->above_pred_buf + MAX_SB_SQUARE * len);
- args->left_pred_buf[0] = CONVERT_TO_BYTEPTR(x->left_pred_buf);
- args->left_pred_buf[1] =
- CONVERT_TO_BYTEPTR(x->left_pred_buf + (MAX_SB_SQUARE >> 1) * len);
- args->left_pred_buf[2] =
- CONVERT_TO_BYTEPTR(x->left_pred_buf + MAX_SB_SQUARE * len);
- } else {
- args->above_pred_buf[0] = x->above_pred_buf;
- args->above_pred_buf[1] = x->above_pred_buf + (MAX_SB_SQUARE >> 1);
- args->above_pred_buf[2] = x->above_pred_buf + MAX_SB_SQUARE;
- args->left_pred_buf[0] = x->left_pred_buf;
- args->left_pred_buf[1] = x->left_pred_buf + (MAX_SB_SQUARE >> 1);
- args->left_pred_buf[2] = x->left_pred_buf + MAX_SB_SQUARE;
- }
-
- av1_collect_neighbors_ref_counts(xd);
-
- estimate_ref_frame_costs(cm, xd, x, segment_id, ref_costs_single,
- ref_costs_comp);
-
- MV_REFERENCE_FRAME ref_frame;
- for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
- x->pred_mv_sad[ref_frame] = INT_MAX;
- x->mbmi_ext->mode_context[ref_frame] = 0;
- mbmi_ext->ref_mv_count[ref_frame] = UINT8_MAX;
- if (cpi->ref_frame_flags & av1_ref_frame_flag_list[ref_frame]) {
- if (mbmi->partition != PARTITION_NONE &&
- mbmi->partition != PARTITION_SPLIT) {
- if (skip_ref_frame_mask & (1 << ref_frame)) {
- int skip = 1;
- for (int r = ALTREF_FRAME + 1; r < MODE_CTX_REF_FRAMES; ++r) {
- if (!(skip_ref_frame_mask & (1 << r))) {
- const MV_REFERENCE_FRAME *rf = ref_frame_map[r - REF_FRAMES];
- if (rf[0] == ref_frame || rf[1] == ref_frame) {
- skip = 0;
- break;
- }
- }
- }
- if (skip) continue;
- }
- }
- assert(get_ref_frame_yv12_buf(cm, ref_frame) != NULL);
- setup_buffer_ref_mvs_inter(cpi, x, ref_frame, bsize, mi_row, mi_col,
- yv12_mb);
- }
- }
- av1_count_overlappable_neighbors(cm, xd, mi_row, mi_col);
-
- if (check_num_overlappable_neighbors(mbmi) &&
- is_motion_variation_allowed_bsize(bsize)) {
- av1_build_prediction_by_above_preds(cm, xd, mi_row, mi_col,
- args->above_pred_buf, dst_width1,
- dst_height1, args->above_pred_stride);
- av1_build_prediction_by_left_preds(cm, xd, mi_row, mi_col,
- args->left_pred_buf, dst_width2,
- dst_height2, args->left_pred_stride);
- av1_setup_dst_planes(xd->plane, bsize, &cm->cur_frame->buf, mi_row, mi_col,
- 0, num_planes);
- calc_target_weighted_pred(
- cm, x, xd, mi_row, mi_col, args->above_pred_buf[0],
- args->above_pred_stride[0], args->left_pred_buf[0],
- args->left_pred_stride[0]);
- }
- init_mode_skip_mask(mode_skip_mask, cpi, x, bsize);
-
- if (cpi->sf.tx_type_search.fast_intra_tx_type_search)
- x->use_default_intra_tx_type = 1;
- else
- x->use_default_intra_tx_type = 0;
-
- if (cpi->sf.tx_type_search.fast_inter_tx_type_search)
- x->use_default_inter_tx_type = 1;
- else
- x->use_default_inter_tx_type = 0;
- if (cpi->sf.skip_repeat_interpolation_filter_search) {
- x->interp_filter_stats_idx[0] = 0;
- x->interp_filter_stats_idx[1] = 0;
- }
-}
-
static void search_palette_mode(const AV1_COMP *cpi, MACROBLOCK *x, int mi_row,
int mi_col, RD_STATS *rd_cost,
PICK_MODE_CONTEXT *ctx, BLOCK_SIZE bsize,
@@ -13210,6 +13098,97 @@
}
}
+// TODO(kyslov): now this is very similar to set_params_rd_pick_inter_mode
+// (except that doesn't set ALTREF parameters)
+// consider passing a flag to select non-rd path (similar to
+// encode_sb_row)
+static void set_params_nonrd_pick_inter_mode(
+ const AV1_COMP *cpi, MACROBLOCK *x, HandleInterModeArgs *args,
+ BLOCK_SIZE bsize, int mi_row, int mi_col, mode_skip_mask_t *mode_skip_mask,
+ int skip_ref_frame_mask, unsigned int ref_costs_single[REF_FRAMES],
+ unsigned int ref_costs_comp[REF_FRAMES][REF_FRAMES],
+ struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE]) {
+ const AV1_COMMON *const cm = &cpi->common;
+ MACROBLOCKD *const xd = &x->e_mbd;
+ MB_MODE_INFO *const mbmi = xd->mi[0];
+ MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
+ unsigned char segment_id = mbmi->segment_id;
+
+ for (int i = 0; i < MB_MODE_COUNT; ++i)
+ for (int k = 0; k < REF_FRAMES; ++k) args->single_filter[i][k] = SWITCHABLE;
+
+ if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
+ int len = sizeof(uint16_t);
+ args->above_pred_buf[0] = CONVERT_TO_BYTEPTR(x->above_pred_buf);
+ args->above_pred_buf[1] =
+ CONVERT_TO_BYTEPTR(x->above_pred_buf + (MAX_SB_SQUARE >> 1) * len);
+ args->above_pred_buf[2] =
+ CONVERT_TO_BYTEPTR(x->above_pred_buf + MAX_SB_SQUARE * len);
+ args->left_pred_buf[0] = CONVERT_TO_BYTEPTR(x->left_pred_buf);
+ args->left_pred_buf[1] =
+ CONVERT_TO_BYTEPTR(x->left_pred_buf + (MAX_SB_SQUARE >> 1) * len);
+ args->left_pred_buf[2] =
+ CONVERT_TO_BYTEPTR(x->left_pred_buf + MAX_SB_SQUARE * len);
+ } else {
+ args->above_pred_buf[0] = x->above_pred_buf;
+ args->above_pred_buf[1] = x->above_pred_buf + (MAX_SB_SQUARE >> 1);
+ args->above_pred_buf[2] = x->above_pred_buf + MAX_SB_SQUARE;
+ args->left_pred_buf[0] = x->left_pred_buf;
+ args->left_pred_buf[1] = x->left_pred_buf + (MAX_SB_SQUARE >> 1);
+ args->left_pred_buf[2] = x->left_pred_buf + MAX_SB_SQUARE;
+ }
+
+ av1_collect_neighbors_ref_counts(xd);
+
+ estimate_ref_frame_costs(cm, xd, x, segment_id, ref_costs_single,
+ ref_costs_comp);
+
+ MV_REFERENCE_FRAME ref_frame;
+ for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
+ x->pred_mv_sad[ref_frame] = INT_MAX;
+ x->mbmi_ext->mode_context[ref_frame] = 0;
+ mbmi_ext->ref_mv_count[ref_frame] = UINT8_MAX;
+ if (cpi->ref_frame_flags & av1_ref_frame_flag_list[ref_frame]) {
+ if (mbmi->partition != PARTITION_NONE &&
+ mbmi->partition != PARTITION_SPLIT) {
+ if (skip_ref_frame_mask & (1 << ref_frame)) {
+ int skip = 1;
+ for (int r = ALTREF_FRAME + 1; r < MODE_CTX_REF_FRAMES; ++r) {
+ if (!(skip_ref_frame_mask & (1 << r))) {
+ const MV_REFERENCE_FRAME *rf = ref_frame_map[r - REF_FRAMES];
+ if (rf[0] == ref_frame || rf[1] == ref_frame) {
+ skip = 0;
+ break;
+ }
+ }
+ }
+ if (skip) continue;
+ }
+ }
+ assert(get_ref_frame_yv12_buf(cm, ref_frame) != NULL);
+ setup_buffer_ref_mvs_inter(cpi, x, ref_frame, bsize, mi_row, mi_col,
+ yv12_mb);
+ }
+ }
+
+ av1_count_overlappable_neighbors(cm, xd, mi_row, mi_col);
+ init_mode_skip_mask(mode_skip_mask, cpi, x, bsize);
+
+ if (cpi->sf.tx_type_search.fast_intra_tx_type_search)
+ x->use_default_intra_tx_type = 1;
+ else
+ x->use_default_intra_tx_type = 0;
+
+ if (cpi->sf.tx_type_search.fast_inter_tx_type_search)
+ x->use_default_inter_tx_type = 1;
+ else
+ x->use_default_inter_tx_type = 0;
+ if (cpi->sf.skip_repeat_interpolation_filter_search) {
+ x->interp_filter_stats_idx[0] = 0;
+ x->interp_filter_stats_idx[1] = 0;
+ }
+}
+
// TODO(kyslov): now this is very similar to av1_rd_pick_inter_mode_sb except:
// it only checks non-compound mode and
// it doesn't check palette mode
@@ -13240,10 +13219,6 @@
InterModeSearchState search_state;
init_inter_mode_search_state(&search_state, cpi, tile_data, x, bsize,
best_rd_so_far);
- INTERINTRA_MODE interintra_modes[REF_FRAMES] = {
- INTERINTRA_MODES, INTERINTRA_MODES, INTERINTRA_MODES, INTERINTRA_MODES,
- INTERINTRA_MODES, INTERINTRA_MODES, INTERINTRA_MODES, INTERINTRA_MODES
- };
HandleInterModeArgs args = {
{ NULL }, { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE },
{ NULL }, { MAX_SB_SIZE >> 1, MAX_SB_SIZE >> 1, MAX_SB_SIZE >> 1 },
@@ -13251,7 +13226,7 @@
NULL, search_state.modelled_rd,
{ { 0 } }, INT_MAX,
INT_MAX, search_state.simple_rd,
- 0, interintra_modes,
+ 0, NULL,
1, NULL
};
for (i = 0; i < REF_FRAMES; ++i) x->pred_sse[i] = INT_MAX;
diff --git a/av1/encoder/rdopt.h b/av1/encoder/rdopt.h
index 7ba1b18..3293834 100644
--- a/av1/encoder/rdopt.h
+++ b/av1/encoder/rdopt.h
@@ -123,6 +123,13 @@
struct RD_STATS *rd_cost, BLOCK_SIZE bsize,
PICK_MODE_CONTEXT *ctx, int64_t best_rd_so_far);
+void av1_fast_nonrd_pick_inter_mode_sb(struct AV1_COMP *cpi,
+ struct TileDataEnc *tile_data,
+ struct macroblock *x, int mi_row,
+ int mi_col, struct RD_STATS *rd_cost,
+ BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx,
+ int64_t best_rd_so_far);
+
void av1_nonrd_pick_inter_mode_sb(struct AV1_COMP *cpi,
struct TileDataEnc *tile_data,
struct macroblock *x, int mi_row, int mi_col,
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 624d713..688bc16 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -459,6 +459,9 @@
sf->cb_pred_filter_search = 0;
sf->use_nonrd_pick_mode = 0;
sf->use_real_time_ref_set = 0;
+ sf->use_fast_nonrd_pick_mode = 0;
+ sf->reuse_inter_pred_nonrd = 0;
+ sf->estimate_motion_for_var_based_partition = 1;
if (speed >= 1) {
sf->gm_erroradv_type = GM_ERRORADV_TR_1;
@@ -597,21 +600,14 @@
sf->simple_model_rd_from_var = 1;
}
if (speed >= 7) {
- sf->default_max_partition_size = BLOCK_32X32;
- sf->default_min_partition_size = BLOCK_8X8;
- sf->intra_y_mode_mask[TX_64X64] = INTRA_DC;
- sf->intra_y_mode_mask[TX_32X32] = INTRA_DC;
- sf->frame_parameter_update = 0;
- sf->mv.search_method = FAST_HEX;
- sf->partition_search_type = REFERENCE_PARTITION;
- sf->mode_search_skip_flags |= FLAG_SKIP_INTRA_DIRMISMATCH;
- }
- if (speed >= 8) {
- sf->mv.search_method = FAST_DIAMOND;
sf->lpf_pick = LPF_PICK_FROM_Q;
+ sf->mv.subpel_force_stop = QUARTER_PEL;
sf->default_max_partition_size = BLOCK_128X128;
sf->default_min_partition_size = BLOCK_8X8;
+ sf->frame_parameter_update = 0;
+ sf->mv.search_method = FAST_DIAMOND;
sf->partition_search_type = VAR_BASED_PARTITION;
+ sf->mode_search_skip_flags |= FLAG_SKIP_INTRA_DIRMISMATCH;
sf->use_real_time_ref_set = 1;
// Can't use LARGEST TX mode with pre-calculated partition
// and disabled TX64
@@ -619,6 +615,12 @@
sf->use_nonrd_pick_mode = 1;
sf->inter_mode_rd_model_estimation = 2;
}
+ if (speed >= 8) {
+ sf->use_fast_nonrd_pick_mode = 1;
+ sf->mv.subpel_search_method = SUBPEL_TREE;
+ sf->tx_size_search_method = USE_FAST_RD;
+ sf->estimate_motion_for_var_based_partition = 0;
+ }
}
void av1_set_speed_features_framesize_dependent(AV1_COMP *cpi, int speed) {
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index a5a2a01..59c0015 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -701,6 +701,16 @@
// inter-mode RD model for others. Only enabled when
// inter_mode_rd_model_estimation != 0
int inter_mode_rd_model_estimation_adaptive;
+
+ // Use very reduced set of inter mode checks and fast non-rd mode cost
+ // estimation Only enabled when use_nonrd_pick_mode is != 0
+ int use_fast_nonrd_pick_mode;
+
+ // Reuse inter prediction in fast non-rd mode.
+ int reuse_inter_pred_nonrd;
+
+ // Perform croase ME before calculating variance in variance-based partition
+ int estimate_motion_for_var_based_partition;
} SPEED_FEATURES;
struct AV1_COMP;
diff --git a/av1/encoder/var_based_part.c b/av1/encoder/var_based_part.c
index 84c3ac4..461bdd3 100644
--- a/av1/encoder/var_based_part.c
+++ b/av1/encoder/var_based_part.c
@@ -348,7 +348,6 @@
thresholds[2] = (5 * threshold_base) >> 2;
} else if (cm->width < 1920 && cm->height < 1080) {
thresholds[2] = threshold_base << 1;
- thresholds[3] <<= 2;
} else {
thresholds[2] = (5 * threshold_base) >> 1;
}
@@ -477,10 +476,12 @@
mi->sb_type = cm->seq_params.sb_size;
mi->mv[0].as_int = 0;
mi->interp_filters = av1_make_interp_filters(BILINEAR, BILINEAR);
- if (xd->mb_to_right_edge >= 0 && xd->mb_to_bottom_edge >= 0) {
- const MV dummy_mv = { 0, 0 };
- av1_int_pro_motion_estimation(cpi, x, cm->seq_params.sb_size, mi_row,
- mi_col, &dummy_mv);
+ if (cpi->sf.estimate_motion_for_var_based_partition) {
+ if (xd->mb_to_right_edge >= 0 && xd->mb_to_bottom_edge >= 0) {
+ const MV dummy_mv = { 0, 0 };
+ av1_int_pro_motion_estimation(cpi, x, cm->seq_params.sb_size, mi_row,
+ mi_col, &dummy_mv);
+ }
}
// TODO(kyslov): bring the small SAD functionality back
diff --git a/test/rt_end_to_end_test.cc b/test/rt_end_to_end_test.cc
index 9c3e96b..8eeed4b 100644
--- a/test/rt_end_to_end_test.cc
+++ b/test/rt_end_to_end_test.cc
@@ -26,7 +26,7 @@
// List of psnr thresholds for speed settings 0-8
const double kPsnrThreshold[9] = { 36.9, 36.9, 36.85, 36.8, 36.6,
- 36.4, 36.0, 35.5, 35.0 };
+ 36.3, 36.0, 35.3, 35.0 };
typedef struct {
const char *filename;