diff --git a/configure b/configure index b9ce9aab3..e8be3ac9b 100755 --- a/configure +++ b/configure @@ -279,6 +279,7 @@ EXPERIMENT_LIST=" filterintra ext_tx supertx + copy_coding " CONFIG_LIST=" external_build diff --git a/vp9/common/vp9_blockd.h b/vp9/common/vp9_blockd.h index baa46f37b..9766b0982 100644 --- a/vp9/common/vp9_blockd.h +++ b/vp9/common/vp9_blockd.h @@ -32,6 +32,9 @@ extern "C" { #define BLOCK_SIZE_GROUPS 4 #define SKIP_CONTEXTS 3 #define INTER_MODE_CONTEXTS 7 +#if CONFIG_COPY_CODING +#define COPY_MODE_CONTEXTS 5 +#endif /* Segment Feature Masks */ #define MAX_MV_REF_CANDIDATES 2 @@ -79,6 +82,16 @@ typedef enum { MB_MODE_COUNT } PREDICTION_MODE; +#if CONFIG_COPY_CODING +typedef enum { + NOREF, + REF0, + REF1, + REF2, + COPY_MODE_COUNT +} COPY_MODE; +#endif + static INLINE int is_inter_mode(PREDICTION_MODE mode) { return mode >= NEARESTMV && mode <= NEWMV; } @@ -218,6 +231,10 @@ typedef struct { int use_masked_interintra; #endif #endif +#if CONFIG_COPY_CODING + COPY_MODE copy_mode; + int inter_ref_count; +#endif } MB_MODE_INFO; typedef struct { diff --git a/vp9/common/vp9_entropymode.c b/vp9/common/vp9_entropymode.c index 532a96e48..5479c41db 100644 --- a/vp9/common/vp9_entropymode.c +++ b/vp9/common/vp9_entropymode.c @@ -54,6 +54,43 @@ static const vp9_prob default_supertxsplit_prob[TX_SIZES] = { }; #endif +#if CONFIG_COPY_CODING +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 + const vp9_prob vp9_kf_y_mode_prob[INTRA_MODES][INTRA_MODES][INTRA_MODES - 1] = { { // above = dc { 137, 30, 42, 148, 151, 207, 70, 52, 91 }, // left = dc @@ -286,7 +323,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_CODING 9, 102, 187, 225 +#else + 35, 112, 187, 225 +#endif }; static const vp9_prob default_comp_inter_p[COMP_INTER_CONTEXTS] = { @@ -386,6 +427,11 @@ void vp9_init_mode_probs(FRAME_CONTEXT *fc) { vp9_copy(fc->supertx_prob, default_supertx_prob); vp9_copy(fc->supertxsplit_prob, default_supertxsplit_prob); #endif +#if CONFIG_COPY_CODING + 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 } const vp9_tree_index vp9_switchable_interp_tree @@ -523,17 +569,25 @@ void vp9_adapt_mode_probs(VP9_COMMON *cm) { for (i = 1; i < TX_SIZES; ++i) { fc->supertx_prob[i] = adapt_prob(pre_fc->supertx_prob[i], counts->supertx[i]); -/* fprintf(stderr, "%d(%d %d) ", fc->supertx_prob[i], - counts->supertx[i][0], counts->supertx[i][1]);*/ } for (i = 1; i < TX_SIZES; ++i) { fc->supertxsplit_prob[i] = adapt_prob(pre_fc->supertxsplit_prob[i], counts->supertxsplit[i]); -/* fprintf(stderr, "%d(%d %d) ", fc->supertxsplit_prob[i], - counts->supertxsplit[i][0], counts->supertxsplit[i][1]);*/ } -/* fprintf(stderr, "\n");*/ +#endif + +#if CONFIG_COPY_CODING + 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 } diff --git a/vp9/common/vp9_entropymode.h b/vp9/common/vp9_entropymode.h index 7d5209e5a..d66649400 100644 --- a/vp9/common/vp9_entropymode.h +++ b/vp9/common/vp9_entropymode.h @@ -71,6 +71,11 @@ typedef struct frame_contexts { vp9_prob supertx_prob[TX_SIZES]; vp9_prob supertxsplit_prob[TX_SIZES]; #endif +#if CONFIG_COPY_CODING + 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 } FRAME_CONTEXT; typedef struct { @@ -110,6 +115,11 @@ typedef struct { unsigned int supertxsplit[TX_SIZES][2]; unsigned int supertx_size[BLOCK_SIZES]; #endif +#if CONFIG_COPY_CODING + 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 } FRAME_COUNTS; extern const vp9_prob vp9_kf_uv_mode_prob[INTRA_MODES][INTRA_MODES - 1]; @@ -122,6 +132,10 @@ extern const vp9_tree_index vp9_inter_mode_tree[TREE_SIZE(INTER_MODES)]; extern const vp9_tree_index vp9_partition_tree[TREE_SIZE(PARTITION_TYPES)]; extern const vp9_tree_index vp9_switchable_interp_tree [TREE_SIZE(SWITCHABLE_FILTERS)]; +#if CONFIG_COPY_CODING +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 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 0fe58c5c8..1d415439b 100644 --- a/vp9/common/vp9_mvref_common.c +++ b/vp9/common/vp9_mvref_common.c @@ -188,3 +188,176 @@ void vp9_append_sub8x8_mvs_for_idx(VP9_COMMON *cm, MACROBLOCKD *xd, assert("Invalid block index."); } } + +#if CONFIG_COPY_CODING +static int compare_interinfo(MB_MODE_INFO *mbmi, MB_MODE_INFO *ref_mbmi) { + if (mbmi == ref_mbmi) { + return 1; + } else { + int is_same; +#if CONFIG_INTERINTRA + MV_REFERENCE_FRAME mbmi_ref1_backup = mbmi->ref_frame[1]; + MV_REFERENCE_FRAME refmbmi_ref1_backup = ref_mbmi->ref_frame[1]; + + if (mbmi->ref_frame[1] == INTRA_FRAME) + mbmi->ref_frame[1] = NONE; + if (ref_mbmi->ref_frame[1] == INTRA_FRAME) + ref_mbmi->ref_frame[1] = NONE; +#endif + 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; + } +#if CONFIG_INTERINTRA + mbmi->ref_frame[1] = mbmi_ref1_backup; + ref_mbmi->ref_frame[1] = refmbmi_ref1_backup; +#endif + + 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(bsize), b_height_log2(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(bsize) < b_height_log2(bsize)) { + if (block[max_depth] == 0) + return 1; + } else if (b_width_log2(bsize) > b_height_log2(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(bsize); + int bh = 4 << b_height_log2(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(bsize); + int bh = 4 << b_height_log2(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]->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 diff --git a/vp9/common/vp9_mvref_common.h b/vp9/common/vp9_mvref_common.h index 7bce3fa37..60e5143f0 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_CODING +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 + #ifdef __cplusplus } // extern "C" #endif diff --git a/vp9/common/vp9_pred_common.c b/vp9/common/vp9_pred_common.c index bc9d6ef5e..b95e5885d 100644 --- a/vp9/common/vp9_pred_common.c +++ b/vp9/common/vp9_pred_common.c @@ -383,3 +383,47 @@ int vp9_get_segment_id(VP9_COMMON *cm, const uint8_t *segment_ids, assert(segment_id >= 0 && segment_id < MAX_SEGMENTS); return segment_id; } + +#if CONFIG_COPY_CODING +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 diff --git a/vp9/common/vp9_pred_common.h b/vp9/common/vp9_pred_common.h index 1a7ba86e4..b815d8ce2 100644 --- a/vp9/common/vp9_pred_common.h +++ b/vp9/common/vp9_pred_common.h @@ -134,6 +134,10 @@ static INLINE unsigned int *get_tx_counts(TX_SIZE max_tx_size, int ctx, } } +#if CONFIG_COPY_CODING +int vp9_get_copy_mode_context(const MACROBLOCKD *xd); +#endif + #ifdef __cplusplus } // extern "C" #endif diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c index c9c9ce81f..621d64932 100644 --- a/vp9/decoder/vp9_decodeframe.c +++ b/vp9/decoder/vp9_decodeframe.c @@ -1742,6 +1742,15 @@ static int read_compressed_header(VP9Decoder *pbi, const uint8_t *data, #endif } #endif + +#if CONFIG_COPY_CODING + 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 < 2; i++) + vp9_diff_update_prob(&r, &fc->copy_mode_probs[j][i]); + } +#endif } return vp9_reader_has_error(&r); diff --git a/vp9/decoder/vp9_decodemv.c b/vp9/decoder/vp9_decodemv.c index 549d08450..cabc8dd4f 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_CODING +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 + static int read_segment_id(vp9_reader *r, const struct segmentation *seg) { return vp9_read_tree(r, vp9_segment_tree, seg->tree_probs); } @@ -568,22 +598,6 @@ static void read_inter_block_mode_info(VP9_COMMON *const cm, read_ref_frames(cm, xd, r, mbmi->segment_id, mbmi->ref_frame); is_compound = has_second_ref(mbmi); -#if CONFIG_EXT_TX - if (mbmi->tx_size <= TX_16X16 && - bsize >= BLOCK_8X8 && -#if CONFIG_SUPERTX - !supertx_enabled && -#endif - !vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP) && - !mbmi->skip) { - mbmi->ext_txfrm = vp9_read(r, cm->fc.ext_tx_prob); - if (!cm->frame_parallel_decoding_mode) - ++cm->counts.ext_tx[mbmi->ext_txfrm]; - } else { - mbmi->ext_txfrm = NORM; - } -#endif - for (ref = 0; ref < 1 + is_compound; ++ref) { const MV_REFERENCE_FRAME frame = mbmi->ref_frame[ref]; vp9_find_mv_refs(cm, xd, tile, mi, frame, mbmi->ref_mvs[frame], @@ -717,27 +731,108 @@ static void read_inter_frame_mode_info(VP9_COMMON *const cm, MODE_INFO *const mi = xd->mi[0]; MB_MODE_INFO *const mbmi = &mi->mbmi; int inter_block; +#if CONFIG_COPY_CODING + 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_CODING + 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_MASKED_INTERINTER + mbmi->use_masked_interinter = 0; +#endif +#if CONFIG_INTERINTRA + if (mbmi->ref_frame[1] == INTRA_FRAME) + mbmi->ref_frame[1] = NONE; +#endif +#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 + #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); + +#if CONFIG_COPY_CODING + 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 + if (inter_block && + mbmi->tx_size <= TX_16X16 && + mbmi->sb_type >= BLOCK_8X8 && +#if CONFIG_SUPERTX + !supertx_enabled && +#endif + !vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP) && + !mbmi->skip) { + mbmi->ext_txfrm = vp9_read(r, cm->fc.ext_tx_prob); + if (!cm->frame_parallel_decoding_mode) + ++cm->counts.ext_tx[mbmi->ext_txfrm]; + } else { + mbmi->ext_txfrm = NORM; + } +#endif #if CONFIG_SUPERTX } else { const int ctx = vp9_get_intra_inter_context(xd); mbmi->segment_id = 0; inter_block = 1; if (!cm->frame_parallel_decoding_mode) +#if CONFIG_COPY_CODING + if (mbmi->copy_mode == NOREF) +#endif ++cm->counts.intra_inter[ctx][1]; } #endif +#if CONFIG_COPY_CODING + if (mbmi->copy_mode == NOREF) { +#endif if (inter_block) read_inter_block_mode_info(cm, xd, tile, mi, #if CONFIG_SUPERTX && CONFIG_EXT_TX @@ -746,6 +841,9 @@ static void read_inter_frame_mode_info(VP9_COMMON *const cm, mi_row, mi_col, r); else read_intra_block_mode_info(cm, mi, r); +#if CONFIG_COPY_CODING + } +#endif } void vp9_read_mode_info(VP9_COMMON *cm, MACROBLOCKD *xd, diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c index 8f3620136..27d651a41 100644 --- a/vp9/encoder/vp9_bitstream.c +++ b/vp9/encoder/vp9_bitstream.c @@ -38,6 +38,10 @@ static struct vp9_token intra_mode_encodings[INTRA_MODES]; static struct vp9_token switchable_interp_encodings[SWITCHABLE_FILTERS]; static struct vp9_token partition_encodings[PARTITION_TYPES]; static struct vp9_token inter_mode_encodings[INTER_MODES]; +#if CONFIG_COPY_CODING +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, @@ -56,6 +60,10 @@ void vp9_entropy_mode_init() { vp9_tokens_from_tree(switchable_interp_encodings, vp9_switchable_interp_tree); vp9_tokens_from_tree(partition_encodings, vp9_partition_tree); vp9_tokens_from_tree(inter_mode_encodings, vp9_inter_mode_tree); +#if CONFIG_COPY_CODING + 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 } static void write_intra_mode(vp9_writer *w, PREDICTION_MODE mode, @@ -70,6 +78,21 @@ static void write_inter_mode(vp9_writer *w, PREDICTION_MODE mode, &inter_mode_encodings[INTER_OFFSET(mode)]); } +#if CONFIG_COPY_CODING +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 + 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)); @@ -254,7 +277,19 @@ 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_CODING + int copy_mode_context = vp9_get_copy_mode_context(xd); +#endif +#if CONFIG_COPY_CODING + 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) { const int pred_flag = mbmi->seg_id_predicted; @@ -278,6 +313,9 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi, #if CONFIG_SUPERTX if (!supertx_enabled) { +#endif +#if CONFIG_COPY_CODING + 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)); @@ -293,6 +331,18 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi, (skip || vp9_segfeature_active(seg, segment_id, SEG_LVL_SKIP)))) { write_selected_tx_size(cpi, mbmi->tx_size, bsize, w); } +#if CONFIG_EXT_TX + if (is_inter && + mbmi->tx_size <= TX_16X16 && + bsize >= BLOCK_8X8 && +#if CONFIG_SUPERTX + !supertx_enabled && +#endif + !mbmi->skip && + !vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) { + vp9_write(w, mbmi->ext_txfrm, cm->fc.ext_tx_prob); + } +#endif if (!is_inter) { if (bsize >= BLOCK_8X8) { @@ -328,23 +378,15 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi, cm->fc.filterintra_prob[get_uv_tx_size(mbmi)][mbmi->uv_mode]); } #endif +#if !CONFIG_COPY_CODING } else { +#else + } else if (mbmi->copy_mode == NOREF) { +#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(cpi, w); -#if CONFIG_EXT_TX - if (mbmi->tx_size <= TX_16X16 && - bsize >= BLOCK_8X8 && -#if CONFIG_SUPERTX - !supertx_enabled && -#endif - !mbmi->skip && - !vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) { - vp9_write(w, mbmi->ext_txfrm, cm->fc.ext_tx_prob); - } -#endif - // If segment skip is not enabled code the mode. if (!vp9_segfeature_active(seg, segment_id, SEG_LVL_SKIP)) { if (bsize >= BLOCK_8X8) { @@ -1470,6 +1512,15 @@ static size_t write_compressed_header(VP9_COMP *cpi, uint8_t *data) { #endif } #endif + +#if CONFIG_COPY_CODING + 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], 3, &header_bc); + } +#endif } vp9_stop_encode(&header_bc); diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index cd6862f4c..8696b2eab 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -736,7 +736,25 @@ static void update_state(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx, } #endif if (!frame_is_intra_only(cm)) { +#if CONFIG_COPY_CODING + 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 vp9_update_mv_count(cm, xd); if (cm->interp_filter == SWITCHABLE) { @@ -842,7 +860,25 @@ static void update_state_supertx(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx, return; if (!frame_is_intra_only(cm)) { +#if CONFIG_COPY_CODING + 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 vp9_update_mv_count(cm, xd); if (cm->interp_filter == SWITCHABLE) { @@ -1259,7 +1295,11 @@ static void update_stats(VP9_COMP *cpi) { const MODE_INFO *const mi = xd->mi[0]; const MB_MODE_INFO *const mbmi = &mi->mbmi; +#if !CONFIG_COPY_CODING if (!frame_is_intra_only(cm)) { +#else + if (!frame_is_intra_only(cm) && mbmi->copy_mode == NOREF) { +#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 f70b99546..21742d555 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h @@ -409,6 +409,10 @@ typedef struct VP9_COMP { int intra_uv_mode_cost[FRAME_TYPES][INTRA_MODES]; int y_mode_costs[INTRA_MODES][INTRA_MODES][INTRA_MODES]; int switchable_interp_costs[SWITCHABLE_FILTER_CONTEXTS][SWITCHABLE_FILTERS]; +#if CONFIG_COPY_CODING + 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_rdopt.c b/vp9/encoder/vp9_rdopt.c index 4beddffa9..82a14ae64 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -356,6 +356,15 @@ void vp9_initialize_rd_consts(VP9_COMP *cpi) { cm->fc.inter_mode_probs[i], vp9_inter_mode_tree); } } + +#if CONFIG_COPY_CODING + 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 } static const int MAX_XSQ_Q10 = 245727; @@ -3793,12 +3802,23 @@ int64_t vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, int is_best_interintra = 0; int start_skip = 0; int mode_skip_mask_interintra = 0; +#endif +#if CONFIG_COPY_CODING + 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 vp9_zero(best_mbmode); x->skip_encode = cpi->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_CODING + 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 for (i = 0; i < REFERENCE_MODES; ++i) best_pred_rd[i] = INT64_MAX; @@ -4064,6 +4084,9 @@ int64_t vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, // them for this frame. mbmi->interp_filter = cm->interp_filter == SWITCHABLE ? EIGHTTAP : cm->interp_filter; +#if CONFIG_COPY_CODING + mbmi->copy_mode = NOREF; +#endif x->skip = 0; set_ref_ptrs(cm, xd, ref_frame, second_ref_frame); @@ -4217,6 +4240,12 @@ int64_t vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, rate2 += ref_costs_single[ref_frame]; } +#if CONFIG_COPY_CODING + 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) { vp9_prob skip_prob = vp9_get_skip_prob(cm, xd); @@ -4423,10 +4452,15 @@ int64_t vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, ++cpi->interintra_select_count[is_best_interintra]; #endif +#if !CONFIG_COPY_CODING if (best_mode_index < 0 || best_rd >= best_rd_so_far) return INT64_MAX; +#endif // If we used an estimate for the uv intra rd in the loop above... +#if CONFIG_COPY_CODING + if (!(best_mode_index < 0 || best_rd >= best_rd_so_far)) { +#endif if (cpi->sf.use_uv_intra_rd_estimate) { // Do Intra UV best rd mode selection if best mode choice above was intra. if (vp9_mode_order[best_mode_index].ref_frame[0] == INTRA_FRAME) { @@ -4482,6 +4516,188 @@ int64_t vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); store_coding_context(x, ctx, best_mode_index, best_pred_diff, best_tx_diff, best_filter_diff); +#if CONFIG_COPY_CODING + } + + for (copy_mode = REF0; + copy_mode < MIN(REF0 + inter_ref_count, COPY_MODE_COUNT); copy_mode++) { + int64_t this_rd = INT64_MAX; + int rate2 = 0, rate_y = 0, rate_uv = 0; + int64_t distortion2 = 0, distortion_y = 0, distortion_uv = 0; + int this_skip2 = 0, skippable = 0, skippable_y = 0, skippable_uv = 0; + int64_t ssey, sseuv, total_sse = INT64_MAX; + int64_t tx_cache[TX_MODES]; + int i; +#if CONFIG_EXT_TX + int tx_type, rate2_tx, this_skip2_tx, best_tx_size, best_tx_type; + int64_t distortion2_tx, bestrd_tx = INT64_MAX; +#endif + + *mbmi = *inter_ref_list[copy_mode - REF0]; +#if CONFIG_MASKED_INTERINTER + mbmi->use_masked_interinter = 0; +#endif +#if CONFIG_INTERINTRA + if (mbmi->ref_frame[1] == INTRA_FRAME) + mbmi->ref_frame[1] = NONE; +#endif + 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); + + for (i = 0; i < TX_MODES; ++i) + tx_cache[i] = INT64_MAX; +#if CONFIG_EXT_TX + for (tx_type = 0; tx_type < 2; tx_type++) { + mbmi->ext_txfrm = tx_type; +#endif + inter_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); + + rate2 = rate_y + rate_uv; + distortion2 = distortion_y + distortion_uv; + skippable = skippable_y && skippable_uv; + total_sse = ssey + sseuv; + + if (skippable) { + vp9_prob skip_prob = vp9_get_skip_prob(cm, xd); + + rate2 -= (rate_y + rate_uv); + rate_y = 0; + rate_uv = 0; + if (skip_prob) { + int prob_skip_cost = vp9_cost_bit(skip_prob, 1); + rate2 += prob_skip_cost; + } + } else if (!xd->lossless) { + if (RDCOST(x->rdmult, x->rddiv, rate_y + rate_uv, distortion2) < + RDCOST(x->rdmult, x->rddiv, 0, total_sse)) { + rate2 += vp9_cost_bit(vp9_get_skip_prob(cm, xd), 0); + } else { + rate2 += vp9_cost_bit(vp9_get_skip_prob(cm, xd), 1); + distortion2 = total_sse; + assert(total_sse >= 0); + rate2 -= (rate_y + rate_uv); + rate_y = 0; + rate_uv = 0; + this_skip2 = 1; + } + } else { + rate2 += vp9_cost_bit(vp9_get_skip_prob(cm, xd), 0); + } +#if CONFIG_EXT_TX + if (mbmi->tx_size <= TX_16X16 && !this_skip2) + rate2 += vp9_cost_bit(cm->fc.ext_tx_prob, tx_type); + this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); + if (tx_type == 0 || this_rd < (bestrd_tx * 0.97)) { + 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; + } + } + if (best_tx_size <= TX_16X16) + mbmi->ext_txfrm = best_tx_type; + else + mbmi->ext_txfrm = 0; + + inter_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); + + rate2 = rate2_tx; + distortion2 = distortion2_tx; + this_skip2 = this_skip2_tx; +#endif + + rate2 += vp9_cost_bit(cm->fc.copy_noref_prob[copy_mode_context][bsize], 1); + switch (inter_ref_count) { + case 1: + break; + case 2: + rate2 += cpi->copy_mode_cost_l2[copy_mode_context][copy_mode - REF0]; + break; + default: + rate2 += cpi->copy_mode_cost[copy_mode_context][copy_mode - REF0]; + break; + } + this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); + + if (this_rd < best_rd) { + int max_plane = MAX_MB_PLANE; + + *returnrate = rate2; + *returndistortion = distortion2; +#if CONFIG_SUPERTX + *returnrate_nocoef = + vp9_cost_bit(cm->fc.copy_noref_prob[copy_mode_context][bsize], 1); + if (inter_ref_count == 2) + *returnrate_nocoef += + cpi->copy_mode_cost_l2[copy_mode_context][copy_mode - REF0]; + else if (inter_ref_count > 2) + *returnrate_nocoef += + cpi->copy_mode_cost[copy_mode_context][copy_mode - REF0]; +#endif + best_rd = this_rd; + best_mbmode = *mbmi; + best_skip2 = this_skip2; + if (!x->select_tx_size) + swap_block_ptr(x, ctx, 1, 0, 0, max_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) + return INT64_MAX; + + *mbmi = best_mbmode; + x->skip |= best_skip2; + ctx->skip = x->skip; + ctx->mic = *xd->mi[0]; + + if (!x->skip) { + 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); + } +#endif return best_rd; } @@ -4655,6 +4871,9 @@ int64_t vp9_rd_pick_inter_mode_sub8x8(VP9_COMP *cpi, MACROBLOCK *x, #if CONFIG_EXT_TX mbmi->ext_txfrm = NORM; #endif +#if CONFIG_COPY_CODING + mbmi->copy_mode = NOREF; +#endif x->skip_encode = cpi->sf.skip_encode_frame && x->q_index < QIDX_SKIP_THRESH; vpx_memset(x->zcoeff_blk[TX_4X4], 0, 4);