From 9aa76fdb693dee19428ec1fede4f51f9e7fed6da Mon Sep 17 00:00:00 2001 From: Deb Mukherjee Date: Mon, 15 Dec 2014 16:39:52 -0800 Subject: [PATCH] Adds a copy mode experiment Experiment to copy motion and mode from block neighbors. Results: -------- --enable-experimental --enable-copy-mode: derflr: +0.727% With other expts: --enable-experimental --enable-copy-mode --enable-supertx --enable-ext-tx --enable-filterintra --enable-tx-skip --enable-tx64x64 derflr: +3.43% Change-Id: Iae74b9a855a1a690bf76131b42d247bbc54dec17 --- configure | 1 + vp9/common/vp9_blockd.h | 18 ++ vp9/common/vp9_entropymode.c | 66 ++++++- vp9/common/vp9_entropymode.h | 22 ++- vp9/common/vp9_mvref_common.c | 161 +++++++++++++++++ vp9/common/vp9_mvref_common.h | 6 + vp9/common/vp9_pred_common.c | 44 +++++ vp9/common/vp9_pred_common.h | 4 + vp9/decoder/vp9_decodeframe.c | 8 + vp9/decoder/vp9_decodemv.c | 103 ++++++++++- vp9/encoder/vp9_bitstream.c | 55 +++++- vp9/encoder/vp9_encodeframe.c | 40 +++++ vp9/encoder/vp9_encoder.h | 4 + vp9/encoder/vp9_rd.c | 9 + vp9/encoder/vp9_rdopt.c | 320 +++++++++++++++++++++++++++------- 15 files changed, 784 insertions(+), 77 deletions(-) diff --git a/configure b/configure index 7695c281d..6d0c97639 100755 --- a/configure +++ b/configure @@ -287,6 +287,7 @@ EXPERIMENT_LIST=" ext_tx tx_skip supertx + copy_mode " CONFIG_LIST=" external_build diff --git a/vp9/common/vp9_blockd.h b/vp9/common/vp9_blockd.h index 6037d93d0..e174f6aeb 100644 --- a/vp9/common/vp9_blockd.h +++ b/vp9/common/vp9_blockd.h @@ -30,6 +30,10 @@ extern "C" { #define SKIP_CONTEXTS 3 #define INTER_MODE_CONTEXTS 7 +#if CONFIG_COPY_MODE +#define COPY_MODE_CONTEXTS 5 +#endif // CONFIG_COPY_MODE + /* Segment Feature Masks */ #define MAX_MV_REF_CANDIDATES 2 @@ -76,6 +80,16 @@ typedef enum { MB_MODE_COUNT } PREDICTION_MODE; +#if CONFIG_COPY_MODE +typedef enum { + NOREF, + REF0, + REF1, + REF2, + COPY_MODE_COUNT +} COPY_MODE; +#endif // CONFIG_COPY_MODE + static INLINE int is_inter_mode(PREDICTION_MODE mode) { return mode >= NEARESTMV && mode <= NEWMV; } @@ -143,6 +157,10 @@ typedef struct { int tx_skip[PLANE_TYPES]; int tx_skip_shift; #endif +#if CONFIG_COPY_MODE + COPY_MODE copy_mode; + int inter_ref_count; +#endif // CONFIG_COPY_MODE } MB_MODE_INFO; typedef struct MODE_INFO { diff --git a/vp9/common/vp9_entropymode.c b/vp9/common/vp9_entropymode.c index a017c4a55..e44bd59fe 100644 --- a/vp9/common/vp9_entropymode.c +++ b/vp9/common/vp9_entropymode.c @@ -259,7 +259,11 @@ const vp9_tree_index vp9_partition_tree[TREE_SIZE(PARTITION_TYPES)] = { }; static const vp9_prob default_intra_inter_p[INTRA_INTER_CONTEXTS] = { +#if CONFIG_COPY_MODE + 35, 112, 187, 225 +#else 9, 102, 187, 225 +#endif }; static const vp9_prob default_comp_inter_p[COMP_INTER_CONTEXTS] = { @@ -326,6 +330,43 @@ static const vp9_prob default_supertx_prob[PARTITION_SUPERTX_CONTEXTS] }; #endif // CONFIG_SUPERTX +#if CONFIG_COPY_MODE +static const vp9_prob default_copy_noref_prob[COPY_MODE_CONTEXTS] + [BLOCK_SIZES] = { + {255, 255, 255, 82, 148, 182, 65, 193, 158, 70, 138, 101, 23}, + {255, 255, 255, 118, 153, 161, 123, 169, 157, 82, 101, 123, 88}, + {255, 255, 255, 130, 178, 226, 194, 196, 174, 173, 135, 144, 141}, + {255, 255, 255, 178, 218, 225, 197, 230, 222, 215, 220, 220, 220}, + {255, 255, 255, 243, 248, 241, 233, 249, 249, 249, 249, 249, 249} +}; + +static const vp9_prob default_copy_mode_probs_l2[COPY_MODE_CONTEXTS][1] = { + {207}, + {135}, + {141}, + {189}, + {209} +}; + +const vp9_tree_index vp9_copy_mode_tree_l2[TREE_SIZE(2)] = { + -(REF0 - REF0), -(REF1 - REF0) +}; + +static const vp9_prob default_copy_mode_probs[COPY_MODE_CONTEXTS] + [COPY_MODE_COUNT - 2] = { + {130, 159}, + {126, 176}, + {120, 150}, + {158, 183}, + {149, 125} +}; + +const vp9_tree_index vp9_copy_mode_tree[TREE_SIZE(COPY_MODE_COUNT - 1)] = { + -(REF0 - REF0), 2, + -(REF1 - REF0), -(REF2 - REF0) +}; +#endif // CONFIG_COPY_MODE + #if CONFIG_TX64X64 void tx_counts_to_branch_counts_64x64(const unsigned int *tx_count_64x64p, unsigned int (*ct_64x64p)[2]) { @@ -399,17 +440,22 @@ void vp9_init_mode_probs(FRAME_CONTEXT *fc) { vp9_copy(fc->inter_mode_probs, default_inter_mode_probs); #if CONFIG_FILTERINTRA vp9_copy(fc->filterintra_prob, default_filterintra_prob); -#endif +#endif // CONFIG_FILTERINTRA #if CONFIG_EXT_TX vp9_copy(fc->ext_tx_prob, default_ext_tx_prob); -#endif +#endif // CONFIG_EXT_TX #if CONFIG_SUPERTX vp9_copy(fc->supertx_prob, default_supertx_prob); -#endif +#endif // CONFIG_SUPERTX #if CONFIG_TX_SKIP vp9_copy(fc->y_tx_skip_prob, default_y_tx_skip_prob); vp9_copy(fc->uv_tx_skip_prob, default_uv_tx_skip_prob); -#endif +#endif // CONFIG_TX_SKIP +#if CONFIG_COPY_MODE + vp9_copy(fc->copy_noref_prob, default_copy_noref_prob); + vp9_copy(fc->copy_mode_probs_l2, default_copy_mode_probs_l2); + vp9_copy(fc->copy_mode_probs, default_copy_mode_probs); +#endif // CONFIG_COPY_MODE } const vp9_tree_index vp9_switchable_interp_tree @@ -540,6 +586,18 @@ void vp9_adapt_mode_probs(VP9_COMMON *cm) { fc->uv_tx_skip_prob[i] = adapt_prob(pre_fc->uv_tx_skip_prob[i], counts->uv_tx_skip[i]); #endif // CONFIG_TX_SKIP +#if CONFIG_COPY_MODE + for (i = 0; i < COPY_MODE_CONTEXTS; i++) { + for (j = BLOCK_8X8; j < BLOCK_SIZES; j++) { + fc->copy_noref_prob[i][j] = + adapt_prob(pre_fc->copy_noref_prob[i][j], counts->copy_noref[i][j]); + } + adapt_probs(vp9_copy_mode_tree_l2, pre_fc->copy_mode_probs_l2[i], + counts->copy_mode_l2[i], fc->copy_mode_probs_l2[i]); + adapt_probs(vp9_copy_mode_tree, pre_fc->copy_mode_probs[i], + counts->copy_mode[i], fc->copy_mode_probs[i]); + } +#endif // CONFIG_COPY_MODE } static void set_default_lf_deltas(struct loopfilter *lf) { diff --git a/vp9/common/vp9_entropymode.h b/vp9/common/vp9_entropymode.h index ccb70f85a..068f95e55 100644 --- a/vp9/common/vp9_entropymode.h +++ b/vp9/common/vp9_entropymode.h @@ -58,17 +58,22 @@ typedef struct frame_contexts { nmv_context nmvc; #if CONFIG_FILTERINTRA vp9_prob filterintra_prob[TX_SIZES][INTRA_MODES]; -#endif +#endif // CONFIG_FILTERINTRA #if CONFIG_EXT_TX vp9_prob ext_tx_prob[3][EXT_TX_TYPES - 1]; -#endif +#endif // CONFIG_EXT_TX #if CONFIG_SUPERTX vp9_prob supertx_prob[PARTITION_SUPERTX_CONTEXTS][TX_SIZES]; -#endif +#endif // CONFIG_SUPERTX #if CONFIG_TX_SKIP vp9_prob y_tx_skip_prob[2]; vp9_prob uv_tx_skip_prob[2]; -#endif +#endif // CONFIG_TX_SKIP +#if CONFIG_COPY_MODE + vp9_prob copy_noref_prob[COPY_MODE_CONTEXTS][BLOCK_SIZES]; + vp9_prob copy_mode_probs_l2[COPY_MODE_CONTEXTS][1]; + vp9_prob copy_mode_probs[COPY_MODE_CONTEXTS][COPY_MODE_COUNT - 2]; +#endif // CONFIG_COPY_MODE } FRAME_CONTEXT; typedef struct { @@ -102,6 +107,11 @@ typedef struct { unsigned int y_tx_skip[2][2]; unsigned int uv_tx_skip[2][2]; #endif +#if CONFIG_COPY_MODE + unsigned int copy_noref[COPY_MODE_CONTEXTS][BLOCK_SIZES][2]; + unsigned int copy_mode_l2[COPY_MODE_CONTEXTS][2]; + unsigned int copy_mode[COPY_MODE_CONTEXTS][COPY_MODE_COUNT - 1]; +#endif // CONFIG_COPY_MODE } FRAME_COUNTS; extern const vp9_prob vp9_kf_uv_mode_prob[INTRA_MODES][INTRA_MODES - 1]; @@ -117,6 +127,10 @@ extern const vp9_tree_index vp9_switchable_interp_tree #if CONFIG_EXT_TX extern const vp9_tree_index vp9_ext_tx_tree[TREE_SIZE(EXT_TX_TYPES)]; #endif +#if CONFIG_COPY_MODE +extern const vp9_tree_index vp9_copy_mode_tree_l2[TREE_SIZE(2)]; +extern const vp9_tree_index vp9_copy_mode_tree[TREE_SIZE(COPY_MODE_COUNT - 1)]; +#endif // CONFIG_COPY_MODE void vp9_setup_past_independence(struct VP9Common *cm); diff --git a/vp9/common/vp9_mvref_common.c b/vp9/common/vp9_mvref_common.c index 3b34050a8..9f044be33 100644 --- a/vp9/common/vp9_mvref_common.c +++ b/vp9/common/vp9_mvref_common.c @@ -184,3 +184,164 @@ void vp9_append_sub8x8_mvs_for_idx(VP9_COMMON *cm, MACROBLOCKD *xd, assert("Invalid block index."); } } + +#if CONFIG_COPY_MODE +static int compare_interinfo(MB_MODE_INFO *mbmi, MB_MODE_INFO *ref_mbmi) { + if (mbmi == ref_mbmi) { + return 1; + } else { + int is_same; + if (mbmi->ref_frame[0] == ref_mbmi->ref_frame[0] && + mbmi->ref_frame[1] == ref_mbmi->ref_frame[1]) { + if (mbmi->ref_frame[1] > INTRA_FRAME) + is_same = mbmi->mv[0].as_int == ref_mbmi->mv[0].as_int && + mbmi->mv[1].as_int == ref_mbmi->mv[1].as_int && + mbmi->interp_filter == ref_mbmi->interp_filter; + else + is_same = mbmi->mv[0].as_int == ref_mbmi->mv[0].as_int && + mbmi->interp_filter == ref_mbmi->interp_filter; + } else { + is_same = 0; + } + + return is_same; + } +} + +static int check_inside(VP9_COMMON *cm, int mi_row, int mi_col) { + return mi_row >= 0 && mi_col >= 0 && + mi_row < cm->mi_rows && mi_col < cm->mi_cols; +} + +static int is_right_available(BLOCK_SIZE bsize, int mi_row, int mi_col) { + int depth, max_depth = 4 - MIN(b_width_log2_lookup[bsize], + b_height_log2_lookup[bsize]); + int block[4] = {0}; + + if (bsize == BLOCK_64X64) + return 1; + mi_row = mi_row % 8; + mi_col = mi_col % 8; + for (depth = 1; depth <= max_depth; depth++) { + block[depth] = (mi_row >> (3 - depth)) * 2 + (mi_col >> (3 - depth)); + mi_row = mi_row % (8 >> depth); + mi_col = mi_col % (8 >> depth); + } + + if (b_width_log2_lookup[bsize] < b_height_log2_lookup[bsize]) { + if (block[max_depth] == 0) + return 1; + } else if (b_width_log2_lookup[bsize] > b_height_log2_lookup[bsize]) { + if (block[max_depth] > 0) + return 0; + } else { + if (block[max_depth] == 0 || block[max_depth] == 2) + return 1; + else if (block[max_depth] == 3) + return 0; + } + + for (depth = max_depth - 1; depth > 0; depth--) { + if (block[depth] == 0 || block[depth] == 2) + return 1; + else if (block[depth] == 3) + return 0; + } + return 1; +} + +static int is_second_rec(int mi_row, int mi_col, BLOCK_SIZE bsize) { + int bw = 4 << b_width_log2_lookup[bsize]; + int bh = 4 << b_height_log2_lookup[bsize]; + + if (bw < bh) + return (mi_col << 3) % (bw << 1) == 0 ? 0 : 1; + else if (bh < bw) + return (mi_row << 3) % (bh << 1) == 0 ? 0 : 2; + else + return 0; +} + +int vp9_construct_ref_inter_list(VP9_COMMON *cm, MACROBLOCKD *xd, + BLOCK_SIZE bsize, int mi_row, int mi_col, + MB_MODE_INFO *ref_list[18]) { + int bw = 4 << b_width_log2_lookup[bsize]; + int bh = 4 << b_height_log2_lookup[bsize]; + int row_offset, col_offset; + int mi_offset; + MB_MODE_INFO *ref_mbmi; + int ref_index, ref_num = 0; + int row_offset_cand[18], col_offset_cand[18]; + int offset_num = 0, i, switchflag; + int is_sec_rec = is_second_rec(mi_row, mi_col, bsize); + + if (is_sec_rec != 2) { + row_offset_cand[offset_num] = -1; col_offset_cand[offset_num] = 0; + offset_num++; + } + if (is_sec_rec != 1) { + row_offset_cand[offset_num] = bh / 16; col_offset_cand[offset_num] = -1; + offset_num++; + } + + row_offset = bh / 8 - 1; + col_offset = 1; + if (is_sec_rec < 2) + switchflag = 1; + else + switchflag = 0; + while ((is_sec_rec == 0 && ((row_offset >=0) || col_offset < (bw / 8 + 1))) || + (is_sec_rec == 1 && col_offset < (bw / 8 + 1)) || + (is_sec_rec == 2 && row_offset >=0)) { + switch (switchflag) { + case 0: + if (row_offset >= 0) { + if (row_offset != bh / 16) { + row_offset_cand[offset_num] = row_offset; + col_offset_cand[offset_num] = -1; + offset_num++; + } + row_offset--; + } + break; + case 1: + if (col_offset < (bw / 8 + 1)) { + row_offset_cand[offset_num] = -1; + col_offset_cand[offset_num] = col_offset; + offset_num++; + col_offset++; + } + break; + default: + assert(0); + } + if (is_sec_rec == 0) + switchflag = 1 - switchflag; + } + row_offset_cand[offset_num] = -1; + col_offset_cand[offset_num] = -1; + offset_num++; + + for (i = 0; i < offset_num; i++) { + row_offset = row_offset_cand[i]; + col_offset = col_offset_cand[i]; + if ((col_offset < (bw / 8) || + (col_offset == (bw / 8) && is_right_available(bsize, mi_row, mi_col))) + && check_inside(cm, mi_row + row_offset, mi_col + col_offset)) { + mi_offset = row_offset * cm->mi_stride + col_offset; + ref_mbmi = &xd->mi[mi_offset].src_mi->mbmi; + if (is_inter_block(ref_mbmi)) { + for (ref_index = 0; ref_index < ref_num; ref_index++) { + if (compare_interinfo(ref_mbmi, ref_list[ref_index])) + break; + } + if (ref_index == ref_num) { + ref_list[ref_num] = ref_mbmi; + ref_num++; + } + } + } + } + return ref_num; +} +#endif // CONFIG_COPY_MODE diff --git a/vp9/common/vp9_mvref_common.h b/vp9/common/vp9_mvref_common.h index a937b7823..a6103d99d 100644 --- a/vp9/common/vp9_mvref_common.h +++ b/vp9/common/vp9_mvref_common.h @@ -220,6 +220,12 @@ void vp9_append_sub8x8_mvs_for_idx(VP9_COMMON *cm, MACROBLOCKD *xd, int block, int ref, int mi_row, int mi_col, int_mv *nearest, int_mv *near); +#if CONFIG_COPY_MODE +int vp9_construct_ref_inter_list(VP9_COMMON *cm, MACROBLOCKD *xd, + BLOCK_SIZE bsize, int mi_row, int mi_col, + MB_MODE_INFO *ref_list[18]); +#endif // CONFIG_COPY_MODE + #ifdef __cplusplus } // extern "C" #endif diff --git a/vp9/common/vp9_pred_common.c b/vp9/common/vp9_pred_common.c index 901a043f6..90f8f56bc 100644 --- a/vp9/common/vp9_pred_common.c +++ b/vp9/common/vp9_pred_common.c @@ -383,3 +383,47 @@ int vp9_get_segment_id(const VP9_COMMON *cm, const uint8_t *segment_ids, assert(segment_id >= 0 && segment_id < MAX_SEGMENTS); return segment_id; } + +#if CONFIG_COPY_MODE +int vp9_get_copy_mode_context(const MACROBLOCKD *xd) { + const MB_MODE_INFO *const above_mbmi = get_mbmi(get_above_mi(xd)); + const MB_MODE_INFO *const left_mbmi = get_mbmi(get_left_mi(xd)); + const int has_above = above_mbmi != NULL; + const int has_left = left_mbmi != NULL; + + if (has_above && has_left) { + const int above_intra = !is_inter_block(above_mbmi); + const int left_intra = !is_inter_block(left_mbmi); + + if (above_intra && left_intra) { + return 4; + } else if (above_intra || left_intra) { + return 3; + } else { + const int above_predict = above_mbmi->copy_mode != NOREF; + const int left_predict = left_mbmi->copy_mode != NOREF; + if (above_predict && left_predict) + return 0; + else if (above_predict || left_predict) + return 1; + else + return 2; + } + } else if (has_above || has_left) { + const MB_MODE_INFO *const ref_mbmi = has_above ? above_mbmi : left_mbmi; + const int ref_intra = !is_inter_block(ref_mbmi); + + if (ref_intra) { + return 3; + } else { + const int ref_predict = ref_mbmi != NOREF; + if (ref_predict) + return 0; + else + return 1; + } + } else { + return 0; + } +} +#endif // CONFIG_COPY_MODE diff --git a/vp9/common/vp9_pred_common.h b/vp9/common/vp9_pred_common.h index 5738d5063..4a5e2026f 100644 --- a/vp9/common/vp9_pred_common.h +++ b/vp9/common/vp9_pred_common.h @@ -142,6 +142,10 @@ static INLINE unsigned int *get_tx_counts(TX_SIZE max_tx_size, int ctx, } } +#if CONFIG_COPY_MODE +int vp9_get_copy_mode_context(const MACROBLOCKD *xd); +#endif // CONFIG_COPY_MODE + #ifdef __cplusplus } // extern "C" #endif diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c index 057a62291..c92fe65ba 100644 --- a/vp9/decoder/vp9_decodeframe.c +++ b/vp9/decoder/vp9_decodeframe.c @@ -2100,6 +2100,14 @@ static int read_compressed_header(VP9Decoder *pbi, const uint8_t *data, vp9_diff_update_prob(&r, &fc->y_tx_skip_prob[i]); for (i = 0; i < 2; i++) vp9_diff_update_prob(&r, &fc->uv_tx_skip_prob[i]); +#endif +#if CONFIG_COPY_MODE + for (j = 0; j < COPY_MODE_CONTEXTS; j++) { + for (i = 0; i < 1; i++) + vp9_diff_update_prob(&r, &fc->copy_mode_probs_l2[j][i]); + for (i = 0; i < COPY_MODE_COUNT - 2; i++) + vp9_diff_update_prob(&r, &fc->copy_mode_probs[j][i]); + } #endif } diff --git a/vp9/decoder/vp9_decodemv.c b/vp9/decoder/vp9_decodemv.c index 9fae17723..4e9cc6430 100644 --- a/vp9/decoder/vp9_decodemv.c +++ b/vp9/decoder/vp9_decodemv.c @@ -54,6 +54,36 @@ static PREDICTION_MODE read_inter_mode(VP9_COMMON *cm, vp9_reader *r, int ctx) { return NEARESTMV + mode; } +#if CONFIG_COPY_MODE +static COPY_MODE read_copy_mode(VP9_COMMON *cm, vp9_reader *r, + int num_candidate, int ctx) { + COPY_MODE mode; + + switch (num_candidate) { + case 0: + assert(0); + break; + case 1: + mode = REF0; + break; + case 2: + mode = REF0 + vp9_read_tree(r, vp9_copy_mode_tree_l2, + cm->fc.copy_mode_probs_l2[ctx]); + if (!cm->frame_parallel_decoding_mode) + ++cm->counts.copy_mode_l2[ctx][mode - REF0]; + break; + default: + mode = REF0 + vp9_read_tree(r, vp9_copy_mode_tree, + cm->fc.copy_mode_probs[ctx]); + if (!cm->frame_parallel_decoding_mode) + ++cm->counts.copy_mode[ctx][mode - REF0]; + break; + } + + return mode; +} +#endif // CONFIG_COPY_MODE + static int read_segment_id(vp9_reader *r, const struct segmentation *seg) { return vp9_read_tree(r, vp9_segment_tree, seg->tree_probs); } @@ -587,7 +617,10 @@ static void read_inter_block_mode_info(VP9_COMMON *const cm, int_mv nearestmv[2], nearmv[2]; int inter_mode_ctx, ref, is_compound; - read_ref_frames(cm, xd, r, mbmi->segment_id, mbmi->ref_frame); +#if CONFIG_COPY_MODE + if (mbmi->copy_mode == NOREF) +#endif + read_ref_frames(cm, xd, r, mbmi->segment_id, mbmi->ref_frame); is_compound = has_second_ref(mbmi); for (ref = 0; ref < 1 + is_compound; ++ref) { @@ -602,9 +635,16 @@ static void read_inter_block_mode_info(VP9_COMMON *const cm, "Block reference is corrupt"); vp9_setup_pre_planes(xd, ref, ref_buf->buf, mi_row, mi_col, &ref_buf->sf); - vp9_find_mv_refs(cm, xd, tile, mi, frame, mbmi->ref_mvs[frame], - mi_row, mi_col); +#if CONFIG_COPY_MODE + if (mbmi->copy_mode == NOREF) +#endif + vp9_find_mv_refs(cm, xd, tile, mi, frame, mbmi->ref_mvs[frame], + mi_row, mi_col); } +#if CONFIG_COPY_MODE + if (mbmi->copy_mode != NOREF) + return; +#endif inter_mode_ctx = mbmi->mode_context[mbmi->ref_frame[0]]; @@ -687,16 +727,66 @@ static void read_inter_frame_mode_info(VP9_COMMON *const cm, MODE_INFO *const mi = xd->mi[0].src_mi; MB_MODE_INFO *const mbmi = &mi->mbmi; int inter_block; +#if CONFIG_COPY_MODE + int num_candidate = 0; + MB_MODE_INFO *inter_ref_list[18] = {NULL}; +#endif mbmi->mv[0].as_int = 0; mbmi->mv[1].as_int = 0; +#if CONFIG_COPY_MODE + if (mbmi->sb_type >= BLOCK_8X8) + num_candidate = vp9_construct_ref_inter_list( + cm, xd, mbmi->sb_type, mi_row, mi_col, inter_ref_list); + if (mbmi->sb_type >= BLOCK_8X8 && num_candidate > 0) { + int ctx = vp9_get_copy_mode_context(xd); + int is_copy = vp9_read(r, cm->fc.copy_noref_prob[ctx][mbmi->sb_type]); + + ++cm->counts.copy_noref[ctx][mbmi->sb_type][is_copy]; + if (!is_copy) { + mbmi->copy_mode = NOREF; + } else { + mbmi->copy_mode = read_copy_mode(cm, r, num_candidate, ctx); + } + } else { + mbmi->copy_mode = NOREF; + } + if (mbmi->copy_mode != NOREF) { + BLOCK_SIZE bsize_backup = mbmi->sb_type; + int skip_backup = mbmi->skip; + COPY_MODE copy_mode_backup = mbmi->copy_mode; +#if CONFIG_SUPERTX + TX_SIZE tx_size_backup = mbmi->tx_size; +#endif +#if CONFIG_EXT_TX + EXT_TX_TYPE ext_txfrm_backup = mbmi->ext_txfrm; +#endif + + inter_block = 1; + *mbmi = *inter_ref_list[mbmi->copy_mode - REF0]; +#if CONFIG_SUPERTX + mbmi->tx_size = tx_size_backup; +#endif +#if CONFIG_EXT_TX + mbmi->ext_txfrm = ext_txfrm_backup; +#endif + mbmi->sb_type = bsize_backup; + mbmi->mode = NEARESTMV; + mbmi->skip = skip_backup; + mbmi->copy_mode = copy_mode_backup; + } +#endif // CONFIG_COPY_MODE + #if CONFIG_SUPERTX if (!supertx_enabled) { #endif mbmi->segment_id = read_inter_segment_id(cm, xd, mi_row, mi_col, r); mbmi->skip = read_skip(cm, xd, mbmi->segment_id, r); - inter_block = read_is_inter_block(cm, xd, mbmi->segment_id, r); +#if CONFIG_COPY_MODE + if (mbmi->copy_mode == NOREF) +#endif + inter_block = read_is_inter_block(cm, xd, mbmi->segment_id, r); mbmi->tx_size = read_tx_size(cm, xd, cm->tx_mode, mbmi->sb_type, !mbmi->skip || !inter_block, r); #if CONFIG_EXT_TX @@ -720,7 +810,10 @@ static void read_inter_frame_mode_info(VP9_COMMON *const cm, mbmi->segment_id = 0; inter_block = 1; if (!cm->frame_parallel_decoding_mode) - ++cm->counts.intra_inter[ctx][1]; +#if CONFIG_COPY_MODE + if (mbmi->copy_mode == NOREF) +#endif + ++cm->counts.intra_inter[ctx][1]; } #endif // CONFIG_SUPERTX diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c index 919789ffe..92682dc9f 100644 --- a/vp9/encoder/vp9_bitstream.c +++ b/vp9/encoder/vp9_bitstream.c @@ -41,6 +41,10 @@ static struct vp9_token inter_mode_encodings[INTER_MODES]; #if CONFIG_EXT_TX static struct vp9_token ext_tx_encodings[EXT_TX_TYPES]; #endif +#if CONFIG_COPY_MODE +static struct vp9_token copy_mode_encodings_l2[2]; +static struct vp9_token copy_mode_encodings[COPY_MODE_COUNT - 1]; +#endif #if CONFIG_SUPERTX static int vp9_check_supertx(VP9_COMMON *cm, int mi_row, int mi_col, @@ -62,6 +66,10 @@ void vp9_entropy_mode_init() { #if CONFIG_EXT_TX vp9_tokens_from_tree(ext_tx_encodings, vp9_ext_tx_tree); #endif +#if CONFIG_COPY_MODE + vp9_tokens_from_tree(copy_mode_encodings_l2, vp9_copy_mode_tree_l2); + vp9_tokens_from_tree(copy_mode_encodings, vp9_copy_mode_tree); +#endif // CONFIG_COPY_MODE } static void write_intra_mode(vp9_writer *w, PREDICTION_MODE mode, @@ -76,6 +84,21 @@ static void write_inter_mode(vp9_writer *w, PREDICTION_MODE mode, &inter_mode_encodings[INTER_OFFSET(mode)]); } +#if CONFIG_COPY_MODE +static void write_copy_mode(VP9_COMMON *cm, vp9_writer *w, COPY_MODE mode, + int inter_ref_count, int copy_mode_context) { + if (inter_ref_count == 2) { + vp9_write_token(w, vp9_copy_mode_tree_l2, + cm->fc.copy_mode_probs_l2[copy_mode_context], + ©_mode_encodings_l2[mode - REF0]); + } else if (inter_ref_count > 2) { + vp9_write_token(w, vp9_copy_mode_tree, + cm->fc.copy_mode_probs[copy_mode_context], + ©_mode_encodings[mode - REF0]); + } +} +#endif // CONFIG_COPY_MODE + static void encode_unsigned_max(struct vp9_write_bit_buffer *wb, int data, int max) { vp9_wb_write_literal(wb, data, get_unsigned_bits(max)); @@ -341,6 +364,16 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi, const int is_inter = is_inter_block(mbmi); const int is_compound = has_second_ref(mbmi); int skip, ref; +#if CONFIG_COPY_MODE + int copy_mode_context = vp9_get_copy_mode_context(xd); + if (bsize >= BLOCK_8X8 && mbmi->inter_ref_count > 0) { + vp9_write(w, mbmi->copy_mode != NOREF, + cm->fc.copy_noref_prob[copy_mode_context][bsize]); + if (mbmi->copy_mode != NOREF) + write_copy_mode(cm, w, mbmi->copy_mode, mbmi->inter_ref_count, + copy_mode_context); + } +#endif if (seg->update_map) { if (seg->temporal_update) { @@ -366,8 +399,11 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi, #if CONFIG_SUPERTX if (!supertx_enabled) { #endif - if (!vp9_segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME)) - vp9_write(w, is_inter, vp9_get_intra_inter_prob(cm, xd)); +#if CONFIG_COPY_MODE + if (mbmi->copy_mode == NOREF) +#endif + if (!vp9_segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME)) + vp9_write(w, is_inter, vp9_get_intra_inter_prob(cm, xd)); #if CONFIG_SUPERTX } #endif @@ -409,7 +445,7 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi, vp9_write(w, mbmi->tx_skip[1], cm->fc.uv_tx_skip_prob[mbmi->tx_skip[0]]); } } -#endif +#endif // CONFIG_TX_SKIP if (!is_inter) { if (bsize >= BLOCK_8X8) { @@ -445,7 +481,11 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi, cm->fc.filterintra_prob[get_uv_tx_size(mbmi, &xd->plane[1])][mbmi->uv_mode]); } #endif +#if CONFIG_COPY_MODE + } else if (mbmi->copy_mode == NOREF) { +#else } else { +#endif const int mode_ctx = mbmi->mode_context[mbmi->ref_frame[0]]; const vp9_prob *const inter_probs = cm->fc.inter_mode_probs[mode_ctx]; write_ref_frames(cm, xd, w); @@ -1534,6 +1574,15 @@ static size_t write_compressed_header(VP9_COMP *cpi, uint8_t *data) { for (i = 0; i < 2; i++) vp9_cond_prob_diff_update(&header_bc, &fc->uv_tx_skip_prob[i], cm->counts.uv_tx_skip[i]); +#endif +#if CONFIG_COPY_MODE + for (i = 0; i < COPY_MODE_CONTEXTS; i++) { + prob_diff_update(vp9_copy_mode_tree_l2, cm->fc.copy_mode_probs_l2[i], + cm->counts.copy_mode_l2[i], 2, &header_bc); + prob_diff_update(vp9_copy_mode_tree, cm->fc.copy_mode_probs[i], + cm->counts.copy_mode[i], COPY_MODE_COUNT - 1, + &header_bc); + } #endif } diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 7b2bf698f..505654125 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -832,7 +832,25 @@ static void update_state(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx, } #endif if (!frame_is_intra_only(cm)) { +#if CONFIG_COPY_MODE + COPY_MODE copy_mode = mbmi->copy_mode; + if (mbmi->sb_type >= BLOCK_8X8) { + int copy_mode_context = vp9_get_copy_mode_context(xd); + if (mbmi->inter_ref_count > 0) { + ++cm->counts.copy_noref[copy_mode_context][mbmi->sb_type] + [copy_mode != NOREF]; + if (copy_mode != NOREF) { + if (mbmi->inter_ref_count == 2) + ++cm->counts.copy_mode_l2[copy_mode_context][copy_mode - REF0]; + else if (mbmi->inter_ref_count > 2) + ++cm->counts.copy_mode[copy_mode_context][copy_mode - REF0]; + } + } + } + if (is_inter_block(mbmi) && copy_mode == NOREF) { +#else if (is_inter_block(mbmi)) { +#endif // CONFIG_COPY_MODE vp9_update_mv_count(cm, xd); if (cm->interp_filter == SWITCHABLE) { @@ -913,7 +931,25 @@ static void update_state_supertx(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx, return; if (!frame_is_intra_only(cm)) { +#if CONFIG_COPY_MODE + COPY_MODE copy_mode = mbmi->copy_mode; + if (mbmi->sb_type >= BLOCK_8X8) { + int copy_mode_context = vp9_get_copy_mode_context(xd); + if (mbmi->inter_ref_count > 0) { + ++cm->counts.copy_noref[copy_mode_context][mbmi->sb_type] + [copy_mode != NOREF]; + if (copy_mode != NOREF) { + if (mbmi->inter_ref_count == 2) + ++cm->counts.copy_mode_l2[copy_mode_context][copy_mode - REF0]; + else if (mbmi->inter_ref_count > 2) + ++cm->counts.copy_mode[copy_mode_context][copy_mode - REF0]; + } + } + } + if (is_inter_block(mbmi) && copy_mode == NOREF) { +#else if (is_inter_block(mbmi)) { +#endif // CONFIG_COPY_MODE vp9_update_mv_count(cm, xd); if (cm->interp_filter == SWITCHABLE) { @@ -1300,7 +1336,11 @@ static void update_stats(VP9_COMMON *cm, const MACROBLOCK *x) { const MODE_INFO *const mi = xd->mi[0].src_mi; const MB_MODE_INFO *const mbmi = &mi->mbmi; +#if CONFIG_COPY_MODE + if (!frame_is_intra_only(cm) && mbmi->copy_mode == NOREF) { +#else if (!frame_is_intra_only(cm)) { +#endif const int seg_ref_active = vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_REF_FRAME); if (!seg_ref_active) { diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h index 144431a8e..a1545cbea 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h @@ -397,6 +397,10 @@ typedef struct VP9_COMP { #if CONFIG_EXT_TX int ext_tx_costs[3][EXT_TX_TYPES]; #endif +#if CONFIG_COPY_MODE + int copy_mode_cost_l2[COPY_MODE_CONTEXTS][2]; + int copy_mode_cost[COPY_MODE_CONTEXTS][COPY_MODE_COUNT - 1]; +#endif PICK_MODE_CONTEXT *leaf_tree; PC_TREE *pc_tree; diff --git a/vp9/encoder/vp9_rd.c b/vp9/encoder/vp9_rd.c index f1c7d9e3e..1a43d134e 100644 --- a/vp9/encoder/vp9_rd.c +++ b/vp9/encoder/vp9_rd.c @@ -306,6 +306,15 @@ void vp9_initialize_rd_consts(VP9_COMP *cpi) { cm->fc.inter_mode_probs[i], vp9_inter_mode_tree); } } + +#if CONFIG_COPY_MODE + for (i = 0; i < COPY_MODE_CONTEXTS; ++i) { + vp9_cost_tokens((int *)cpi->copy_mode_cost_l2[i], + cm->fc.copy_mode_probs_l2[i], vp9_copy_mode_tree_l2); + vp9_cost_tokens((int *)cpi->copy_mode_cost[i], + cm->fc.copy_mode_probs[i], vp9_copy_mode_tree); + } +#endif // CONFIG_COPY_MODE } static void model_rd_norm(int xsq_q10, int *r_q10, int *d_q10) { diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c index 6cfb06987..914d1fa68 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -52,6 +52,10 @@ #define MIN_EARLY_TERM_INDEX 3 +#if CONFIG_EXT_TX +const double ext_tx_th = 0.99; +#endif + typedef struct { PREDICTION_MODE mode; MV_REFERENCE_FRAME ref_frame[2]; @@ -3035,7 +3039,6 @@ static int64_t handle_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, int dummy; int64_t best_rdcost_tx = INT64_MAX; int best_ext_tx = NORM; - double th = 0.99; for (i = 0; i < EXT_TX_TYPES; i++) { mbmi->ext_txfrm = i; @@ -3046,7 +3049,7 @@ static int64_t handle_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, rdcost_tx = RDCOST(x->rdmult, x->rddiv, rate_y_tx, distortion_y_tx); rdcost_tx = MIN(rdcost_tx, RDCOST(x->rdmult, x->rddiv, 0, *psse)); assert(rdcost_tx >= 0); - if (rdcost_tx < best_rdcost_tx * th) { + if (rdcost_tx < best_rdcost_tx * ext_tx_th) { best_ext_tx = i; best_rdcost_tx = rdcost_tx; } @@ -3306,12 +3309,23 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, int q_idx = vp9_get_qindex(seg, segment_id, cm->base_qindex); int try_tx_skip = q_idx <= TX_SKIP_Q_THRESH_INTRA; #endif +#if CONFIG_COPY_MODE + COPY_MODE copy_mode; + int inter_ref_count; + MB_MODE_INFO *inter_ref_list[18]; + int copy_mode_context = vp9_get_copy_mode_context(xd); +#endif // CONFIG_COPY_MODE vp9_zero(best_mbmode); x->skip_encode = sf->skip_encode_frame && x->q_index < QIDX_SKIP_THRESH; estimate_ref_frame_costs(cm, xd, segment_id, ref_costs_single, ref_costs_comp, &comp_mode_p); +#if CONFIG_COPY_MODE + inter_ref_count = + vp9_construct_ref_inter_list(cm, xd, bsize, mi_row, mi_col, inter_ref_list); + mbmi->inter_ref_count = inter_ref_count; +#endif // CONFIG_COPY_MODE for (i = 0; i < REFERENCE_MODES; ++i) best_pred_rd[i] = INT64_MAX; @@ -3603,6 +3617,9 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, #if CONFIG_TX_SKIP mbmi->tx_skip[0] = 0; mbmi->tx_skip[1] = 0; +#endif +#if CONFIG_COPY_MODE + mbmi->copy_mode = NOREF; #endif // Evaluate all sub-pel filters irrespective of whether we can use // them for this frame. @@ -3766,6 +3783,11 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, } else { rate2 += ref_costs_single[ref_frame]; } +#if CONFIG_COPY_MODE + if (inter_ref_count > 0) + rate2 += vp9_cost_bit(cm->fc.copy_noref_prob[copy_mode_context][bsize], + 0); +#endif if (!disable_skip) { if (skippable) { @@ -3971,89 +3993,262 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, } if (best_mode_index < 0 || best_rd >= best_rd_so_far) { +#if !CONFIG_COPY_MODE rd_cost->rate = INT_MAX; rd_cost->rdcost = INT64_MAX; return; - } +#endif + } else { + // If we used an estimate for the uv intra rd in the loop above... + if (sf->use_uv_intra_rd_estimate) { + // Do Intra UV best rd mode selection if best mode choice above was intra. + if (best_mbmode.ref_frame[0] == INTRA_FRAME) { + TX_SIZE uv_tx_size; + *mbmi = best_mbmode; + uv_tx_size = get_uv_tx_size(mbmi, &xd->plane[1]); + rd_pick_intra_sbuv_mode(cpi, x, ctx, &rate_uv_intra[uv_tx_size], + &rate_uv_tokenonly[uv_tx_size], + &dist_uv[uv_tx_size], + &skip_uv[uv_tx_size], + bsize < BLOCK_8X8 ? BLOCK_8X8 : bsize, + uv_tx_size); + } + } - // If we used an estimate for the uv intra rd in the loop above... - if (sf->use_uv_intra_rd_estimate) { - // Do Intra UV best rd mode selection if best mode choice above was intra. - if (best_mbmode.ref_frame[0] == INTRA_FRAME) { - TX_SIZE uv_tx_size; - *mbmi = best_mbmode; - uv_tx_size = get_uv_tx_size(mbmi, &xd->plane[1]); - rd_pick_intra_sbuv_mode(cpi, x, ctx, &rate_uv_intra[uv_tx_size], - &rate_uv_tokenonly[uv_tx_size], - &dist_uv[uv_tx_size], - &skip_uv[uv_tx_size], - bsize < BLOCK_8X8 ? BLOCK_8X8 : bsize, - uv_tx_size); + assert((cm->interp_filter == SWITCHABLE) || + (cm->interp_filter == best_mbmode.interp_filter) || + !is_inter_block(&best_mbmode)); + + if (!cpi->rc.is_src_frame_alt_ref) + update_rd_thresh_fact(cpi, bsize, best_mode_index); + + // macroblock modes + *mbmi = best_mbmode; + x->skip |= best_skip2; + + for (i = 0; i < REFERENCE_MODES; ++i) { + if (best_pred_rd[i] == INT64_MAX) + best_pred_diff[i] = INT_MIN; + else + best_pred_diff[i] = best_rd - best_pred_rd[i]; + } + + if (!x->skip) { + for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++) { + if (best_filter_rd[i] == INT64_MAX) + best_filter_diff[i] = 0; + else + best_filter_diff[i] = best_rd - best_filter_rd[i]; + } + if (cm->interp_filter == SWITCHABLE) + assert(best_filter_diff[SWITCHABLE_FILTERS] == 0); + for (i = 0; i < TX_MODES; i++) { + if (best_tx_rd[i] == INT64_MAX) + best_tx_diff[i] = 0; + else + best_tx_diff[i] = best_rd - best_tx_rd[i]; + } + } else { + vp9_zero(best_filter_diff); + vp9_zero(best_tx_diff); + } + + // TODO(yunqingwang): Moving this line in front of the above + // best_filter_diff updating code causes PSNR loss. Need to + // figure out the confliction. + x->skip |= best_mode_skippable; + + if (!x->skip && !x->select_tx_size) { + int has_high_freq_coeff = 0; + int plane; + int max_plane = is_inter_block(&xd->mi[0].src_mi->mbmi) + ? MAX_MB_PLANE : 1; + for (plane = 0; plane < max_plane; ++plane) { + x->plane[plane].eobs = ctx->eobs_pbuf[plane][1]; + has_high_freq_coeff |= vp9_has_high_freq_in_plane(x, bsize, plane); + } + + for (plane = max_plane; plane < MAX_MB_PLANE; ++plane) { + x->plane[plane].eobs = ctx->eobs_pbuf[plane][2]; + has_high_freq_coeff |= vp9_has_high_freq_in_plane(x, bsize, plane); + } + + best_mode_skippable |= !has_high_freq_coeff; } + + store_coding_context(x, ctx, best_mode_index, best_pred_diff, + best_tx_diff, best_filter_diff, best_mode_skippable); } +#if CONFIG_COPY_MODE + for (copy_mode = REF0; + copy_mode < (COPY_MODE)(MIN(REF0 + inter_ref_count, COPY_MODE_COUNT)); + copy_mode++) { + int i, rate2, rate_y, rate_uv, rate_copy_mode, this_skip2, + skippable, skippable_y, skippable_uv; + int64_t distortion2, distortion_y, distortion_uv, this_rd, + ssey, sseuv, total_sse, tx_cache[TX_MODES]; +#if CONFIG_EXT_TX + EXT_TX_TYPE tx_type, best_tx_type; + TX_SIZE best_tx_size; + int rate2_tx, this_skip2_tx; + int64_t distortion2_tx, bestrd_tx = INT64_MAX; + uint8_t tmp_zcoeff_blk[256]; +#endif - assert((cm->interp_filter == SWITCHABLE) || - (cm->interp_filter == best_mbmode.interp_filter) || - !is_inter_block(&best_mbmode)); + *mbmi = *inter_ref_list[copy_mode - REF0]; + mbmi->sb_type = bsize; + mbmi->inter_ref_count = inter_ref_count; + mbmi->copy_mode = copy_mode; + mbmi->mode = NEARESTMV; + x->skip = 0; + set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); + for (i = 0; i < MAX_MB_PLANE; i++) { + xd->plane[i].pre[0] = yv12_mb[mbmi->ref_frame[0]][i]; + if (mbmi->ref_frame[1] > INTRA_FRAME) + xd->plane[i].pre[1] = yv12_mb[mbmi->ref_frame[1]][i]; + } + vp9_build_inter_predictors_sb(xd, mi_row, mi_col, bsize); + vp9_subtract_plane(x, bsize, 0); - if (!cpi->rc.is_src_frame_alt_ref) - update_rd_thresh_fact(cpi, bsize, best_mode_index); + for (i = 0; i < TX_MODES; ++i) + tx_cache[i] = INT64_MAX; +#if CONFIG_EXT_TX + for (tx_type = NORM; tx_type < EXT_TX_TYPES; tx_type++) { + mbmi->ext_txfrm = tx_type; +#endif + super_block_yrd(cpi, x, &rate_y, &distortion_y, &skippable_y, &ssey, + bsize, tx_cache, INT64_MAX); + super_block_uvrd(cpi, x, &rate_uv, &distortion_uv, &skippable_uv, &sseuv, + bsize, INT64_MAX); - // macroblock modes - *mbmi = best_mbmode; - x->skip |= best_skip2; + rate2 = rate_y + rate_uv; + distortion2 = distortion_y + distortion_uv; + skippable = skippable_y && skippable_uv; + total_sse = ssey + sseuv; - for (i = 0; i < REFERENCE_MODES; ++i) { - if (best_pred_rd[i] == INT64_MAX) - best_pred_diff[i] = INT_MIN; + if (skippable) { + rate2 -= (rate_y + rate_uv); + rate_y = 0; + rate_uv = 0; + rate2 += vp9_cost_bit(vp9_get_skip_prob(cm, xd), 1); + this_skip2 = 1; + } else if (!xd->lossless) { +#if CONFIG_EXT_TX + if (mbmi->tx_size < TX_32X32) + rate2 += cpi->ext_tx_costs[mbmi->tx_size][mbmi->ext_txfrm]; +#endif // CONFIG_EXT_TX + if (RDCOST(x->rdmult, x->rddiv, rate2, distortion2) < + RDCOST(x->rdmult, x->rddiv, 0, total_sse)) { + rate2 += vp9_cost_bit(vp9_get_skip_prob(cm, xd), 0); + this_skip2 = 0; + } else { + rate2 = vp9_cost_bit(vp9_get_skip_prob(cm, xd), 1); + distortion2 = total_sse; + rate_y = 0; + rate_uv = 0; + this_skip2 = 1; + } + } else { + rate2 += vp9_cost_bit(vp9_get_skip_prob(cm, xd), 0); + this_skip2 = 0; + } +#if CONFIG_EXT_TX + this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); + if (tx_type == NORM || this_rd < (bestrd_tx * ext_tx_th)) { + bestrd_tx = this_rd; + best_tx_type = tx_type; + best_tx_size = mbmi->tx_size; + rate2_tx = rate2; + distortion2_tx = distortion2; + this_skip2_tx = this_skip2; + vpx_memcpy(tmp_zcoeff_blk, x->zcoeff_blk[mbmi->tx_size], + sizeof(uint8_t) * ctx->num_4x4_blk); + } + } + if (best_tx_size < TX_32X32) + mbmi->ext_txfrm = best_tx_type; else - best_pred_diff[i] = best_rd - best_pred_rd[i]; + mbmi->ext_txfrm = NORM; + mbmi->tx_size = best_tx_size; + vpx_memcpy(x->zcoeff_blk[mbmi->tx_size], tmp_zcoeff_blk, + sizeof(uint8_t) * ctx->num_4x4_blk); + + rate2 = rate2_tx; + distortion2 = distortion2_tx; + this_skip2 = this_skip2_tx; +#endif // CONFIG_EXT_TX + + rate_copy_mode = + vp9_cost_bit(cm->fc.copy_noref_prob[copy_mode_context][bsize], 1); + if (inter_ref_count == 2) + rate_copy_mode += + cpi->copy_mode_cost_l2[copy_mode_context][copy_mode - REF0]; + else if (inter_ref_count > 2) + rate_copy_mode += + cpi->copy_mode_cost[copy_mode_context][copy_mode - REF0]; + rate2 += rate_copy_mode; + this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); + + if (this_rd < best_rd) { + rd_cost->rate = rate2; + rd_cost->dist = distortion2; + rd_cost->rdcost = this_rd; +#if CONFIG_SUPERTX + *returnrate_nocoef = rate_copy_mode; +#endif + best_rd = this_rd; + best_mbmode = *mbmi; + best_skip2 = this_skip2; + best_mode_skippable = skippable; + // if (!x->select_tx_size) swap_block_ptr(x, ctx, 1, 0, 0, MAX_MB_PLANE); + vpx_memcpy(ctx->zcoeff_blk, x->zcoeff_blk[mbmi->tx_size], + sizeof(uint8_t) * ctx->num_4x4_blk); + } + + if (bsize < BLOCK_32X32) { + if (bsize < BLOCK_16X16) + tx_cache[ALLOW_16X16] = tx_cache[ALLOW_8X8]; + tx_cache[ALLOW_32X32] = tx_cache[ALLOW_16X16]; + } + if (this_rd != INT64_MAX) { + for (i = 0; i < TX_MODES && tx_cache[i] < INT64_MAX; i++) { + int64_t adj_rd = INT64_MAX; + adj_rd = this_rd + tx_cache[i] - tx_cache[cm->tx_mode]; + + if (adj_rd < best_tx_rd[i]) + best_tx_rd[i] = adj_rd; + } + } + } + if ((best_mode_index < 0 && best_mbmode.copy_mode == NOREF) + || best_rd >= best_rd_so_far) { + rd_cost->rate = INT_MAX; + rd_cost->rdcost = INT64_MAX; + return; + } + + *mbmi = best_mbmode; + if (mbmi->copy_mode != NOREF) { + x->skip = best_skip2; + ctx->skip = x->skip; + ctx->skippable = best_mode_skippable; + ctx->mic = *xd->mi[0].src_mi; } + set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); if (!x->skip) { - for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++) { - if (best_filter_rd[i] == INT64_MAX) - best_filter_diff[i] = 0; - else - best_filter_diff[i] = best_rd - best_filter_rd[i]; - } - if (cm->interp_filter == SWITCHABLE) - assert(best_filter_diff[SWITCHABLE_FILTERS] == 0); for (i = 0; i < TX_MODES; i++) { if (best_tx_rd[i] == INT64_MAX) best_tx_diff[i] = 0; else best_tx_diff[i] = best_rd - best_tx_rd[i]; } + vpx_memcpy(ctx->tx_rd_diff, best_tx_diff, sizeof(ctx->tx_rd_diff)); } else { vp9_zero(best_filter_diff); vp9_zero(best_tx_diff); } - - // TODO(yunqingwang): Moving this line in front of the above best_filter_diff - // updating code causes PSNR loss. Need to figure out the confliction. - x->skip |= best_mode_skippable; - - if (!x->skip && !x->select_tx_size) { - int has_high_freq_coeff = 0; - int plane; - int max_plane = is_inter_block(&xd->mi[0].src_mi->mbmi) - ? MAX_MB_PLANE : 1; - for (plane = 0; plane < max_plane; ++plane) { - x->plane[plane].eobs = ctx->eobs_pbuf[plane][1]; - has_high_freq_coeff |= vp9_has_high_freq_in_plane(x, bsize, plane); - } - - for (plane = max_plane; plane < MAX_MB_PLANE; ++plane) { - x->plane[plane].eobs = ctx->eobs_pbuf[plane][2]; - has_high_freq_coeff |= vp9_has_high_freq_in_plane(x, bsize, plane); - } - - best_mode_skippable |= !has_high_freq_coeff; - } - - store_coding_context(x, ctx, best_mode_index, best_pred_diff, - best_tx_diff, best_filter_diff, best_mode_skippable); +#endif } void vp9_rd_pick_inter_mode_sb_seg_skip(VP9_COMP *cpi, MACROBLOCK *x, @@ -4218,6 +4413,9 @@ void vp9_rd_pick_inter_mode_sub8x8(VP9_COMP *cpi, MACROBLOCK *x, best_rd = best_rd_so_far; best_yrd = best_rd_so_far; #endif +#if CONFIG_COPY_MODE + mbmi->copy_mode = NOREF; +#endif x->skip_encode = sf->skip_encode_frame && x->q_index < QIDX_SKIP_THRESH; vpx_memset(x->zcoeff_blk[TX_4X4], 0, 4); -- 2.40.0