Adds an inter-intra combination mode

A smooth weighting scheme is used to put more weight
on the intra predictor samples near the left/top boundaries
and decaying it to favor the inter predictor samples more as
we move away from these boundaries in the direction of
prediction.

Results:
derflr: +0.609% with only this experiment
derflr: +3.901% with all experiments

Change-Id: Ic9dbe599ad6162fb05900059cbd6fc88b203a09c
This commit is contained in:
Deb Mukherjee 2015-01-08 00:24:37 -08:00
parent 695c4bc321
commit 2dba1221b4
16 changed files with 783 additions and 11 deletions

1
configure vendored
View File

@ -288,6 +288,7 @@ EXPERIMENT_LIST="
tx_skip
supertx
copy_mode
interintra
"
CONFIG_LIST="
external_build

View File

@ -161,6 +161,10 @@ typedef struct {
COPY_MODE copy_mode;
int inter_ref_count;
#endif // CONFIG_COPY_MODE
#if CONFIG_INTERINTRA
PREDICTION_MODE interintra_mode;
PREDICTION_MODE interintra_uv_mode;
#endif // CONFIG_INTERINTRA
} MB_MODE_INFO;
typedef struct MODE_INFO {
@ -429,6 +433,12 @@ void vp9_set_contexts(const MACROBLOCKD *xd, struct macroblockd_plane *pd,
BLOCK_SIZE plane_bsize, TX_SIZE tx_size, int has_eob,
int aoff, int loff);
#if CONFIG_INTERINTRA
static INLINE int is_interintra_allowed(BLOCK_SIZE sb_type) {
return ((sb_type >= BLOCK_8X8) && (sb_type < BLOCK_64X64));
}
#endif // CONFIG_INTERINTRA
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -13,10 +13,17 @@
#include "vp9/common/vp9_onyxc_int.h"
#include "vp9/common/vp9_seg_common.h"
#if CONFIG_INTERINTRA
static const vp9_prob default_interintra_prob[BLOCK_SIZES] = {
192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192
};
#endif // CONFIG_INTERINTRA
#if CONFIG_TX_SKIP
static const vp9_prob default_y_tx_skip_prob[2] = {190, 210};
static const vp9_prob default_uv_tx_skip_prob[2] = {250, 160};
#endif
#endif // CONFIG_TX_SKIP
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
@ -456,6 +463,9 @@ void vp9_init_mode_probs(FRAME_CONTEXT *fc) {
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
#if CONFIG_INTERINTRA
vp9_copy(fc->interintra_prob, default_interintra_prob);
#endif // CONFIG_INTERINTRA
}
const vp9_tree_index vp9_switchable_interp_tree
@ -598,6 +608,13 @@ void vp9_adapt_mode_probs(VP9_COMMON *cm) {
counts->copy_mode[i], fc->copy_mode_probs[i]);
}
#endif // CONFIG_COPY_MODE
#if CONFIG_INTERINTRA
for (i = 0; i < BLOCK_SIZES; ++i) {
if (is_interintra_allowed(i))
fc->interintra_prob[i] = adapt_prob(pre_fc->interintra_prob[i],
counts->interintra[i]);
}
#endif // CONFIG_INTERINTRA
}
static void set_default_lf_deltas(struct loopfilter *lf) {

View File

@ -74,6 +74,9 @@ typedef struct frame_contexts {
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
#if CONFIG_INTERINTRA
vp9_prob interintra_prob[BLOCK_SIZES];
#endif // CONFIG_INTERINTRA
} FRAME_CONTEXT;
typedef struct {
@ -112,6 +115,9 @@ typedef struct {
unsigned int copy_mode_l2[COPY_MODE_CONTEXTS][2];
unsigned int copy_mode[COPY_MODE_CONTEXTS][COPY_MODE_COUNT - 1];
#endif // CONFIG_COPY_MODE
#if CONFIG_INTERINTRA
unsigned int interintra[BLOCK_SIZES][2];
#endif // CONFIG_INTERINTRA
} FRAME_COUNTS;
extern const vp9_prob vp9_kf_uv_mode_prob[INTRA_MODES][INTRA_MODES - 1];

View File

@ -191,6 +191,15 @@ static int compare_interinfo(MB_MODE_INFO *mbmi, MB_MODE_INFO *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 // CONFIG_INTERINTRA
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)
@ -203,6 +212,10 @@ static int compare_interinfo(MB_MODE_INFO *mbmi, MB_MODE_INFO *ref_mbmi) {
} else {
is_same = 0;
}
#if CONFIG_INTERINTRA
mbmi->ref_frame[1] = mbmi_ref1_backup;
ref_mbmi->ref_frame[1] = refmbmi_ref1_backup;
#endif // CONFIG_INTERINTRA
return is_same;
}

View File

@ -353,18 +353,41 @@ static void build_inter_predictors_for_planes(MACROBLOCKD *xd, BLOCK_SIZE bsize,
void vp9_build_inter_predictors_sby(MACROBLOCKD *xd, int mi_row, int mi_col,
BLOCK_SIZE bsize) {
build_inter_predictors_for_planes(xd, bsize, mi_row, mi_col, 0, 0);
#if CONFIG_INTERINTRA
if (xd->mi[0].src_mi->mbmi.ref_frame[1] == INTRA_FRAME &&
is_interintra_allowed(xd->mi[0].src_mi->mbmi.sb_type))
vp9_build_interintra_predictors_sby(xd, xd->plane[0].dst.buf,
xd->plane[0].dst.stride, bsize);
#endif // CONFIG_INTERINTRA
}
void vp9_build_inter_predictors_sbuv(MACROBLOCKD *xd, int mi_row, int mi_col,
BLOCK_SIZE bsize) {
build_inter_predictors_for_planes(xd, bsize, mi_row, mi_col, 1,
MAX_MB_PLANE - 1);
#if CONFIG_INTERINTRA
if (xd->mi[0].src_mi->mbmi.ref_frame[1] == INTRA_FRAME &&
is_interintra_allowed(xd->mi[0].src_mi->mbmi.sb_type))
vp9_build_interintra_predictors_sbuv(xd, xd->plane[1].dst.buf,
xd->plane[2].dst.buf,
xd->plane[1].dst.stride,
xd->plane[2].dst.stride, bsize);
#endif // CONFIG_INTERINTRA
}
void vp9_build_inter_predictors_sb(MACROBLOCKD *xd, int mi_row, int mi_col,
BLOCK_SIZE bsize) {
build_inter_predictors_for_planes(xd, bsize, mi_row, mi_col, 0,
MAX_MB_PLANE - 1);
#if CONFIG_INTERINTRA
if (xd->mi[0].src_mi->mbmi.ref_frame[1] == INTRA_FRAME &&
is_interintra_allowed(xd->mi[0].src_mi->mbmi.sb_type))
vp9_build_interintra_predictors(xd, xd->plane[0].dst.buf,
xd->plane[1].dst.buf, xd->plane[2].dst.buf,
xd->plane[0].dst.stride,
xd->plane[1].dst.stride,
xd->plane[2].dst.stride, bsize);
#endif // CONFIG_INTERINTRA
}
#if CONFIG_SUPERTX
@ -765,15 +788,25 @@ void vp9_dec_build_inter_predictors_sb(MACROBLOCKD *xd, int mi_row, int mi_col,
0, 0, bw, bh, mi_x, mi_y);
}
}
#if CONFIG_INTERINTRA
if (xd->mi[0].src_mi->mbmi.ref_frame[1] == INTRA_FRAME &&
is_interintra_allowed(xd->mi[0].src_mi->mbmi.sb_type))
vp9_build_interintra_predictors(xd, xd->plane[0].dst.buf,
xd->plane[1].dst.buf, xd->plane[2].dst.buf,
xd->plane[0].dst.stride,
xd->plane[1].dst.stride,
xd->plane[2].dst.stride, bsize);
#endif // CONFIG_INTERINTRA
}
#if CONFIG_SUPERTX
void vp9_dec_build_inter_predictors_sby_sub8x8_extend(MACROBLOCKD *xd,
int mi_row, int mi_col,
int mi_row_ori,
int mi_col_ori,
BLOCK_SIZE top_bsize,
PARTITION_TYPE partition) {
void vp9_dec_build_inter_predictors_sby_sub8x8_extend(
MACROBLOCKD *xd,
int mi_row, int mi_col,
int mi_row_ori,
int mi_col_ori,
BLOCK_SIZE top_bsize,
PARTITION_TYPE partition) {
const int mi_x = mi_col_ori * MI_SIZE;
const int mi_y = mi_row_ori * MI_SIZE;
uint8_t *orig_dst;

View File

@ -924,6 +924,7 @@ static void build_intra_predictors(const MACROBLOCKD *xd, const uint8_t *ref,
pred[mode][tx_size](dst, dst_stride, const_above_row, left_col);
}
}
#if CONFIG_FILTERINTRA
static void filter_intra_predictors_4tap(uint8_t *ypred_ptr, int y_stride,
int bs,
@ -1040,7 +1041,11 @@ static void build_filter_intra_predictors(const MACROBLOCKD *xd,
int plane) {
int i;
DECLARE_ALIGNED_ARRAY(16, uint8_t, left_col, 64);
#if CONFIG_TX64X64
DECLARE_ALIGNED_ARRAY(16, uint8_t, above_data, 256 + 16);
#else
DECLARE_ALIGNED_ARRAY(16, uint8_t, above_data, 128 + 16);
#endif
uint8_t *above_row = above_data + 16;
const uint8_t *const_above_row = above_row;
const int bs = 4 << tx_size;
@ -1186,3 +1191,395 @@ void vp9_predict_intra_block(const MACROBLOCKD *xd, int block_idx, int bwl_in,
}
#endif
}
#if CONFIG_INTERINTRA
static INLINE TX_SIZE intra_size_log2_for_interintra(int bs) {
switch (bs) {
case 4:
return TX_4X4;
break;
case 8:
return TX_8X8;
break;
case 16:
return TX_16X16;
break;
case 32:
return TX_32X32;
break;
case 64:
default:
#if CONFIG_TX64X64
return TX_64X64;
#else
return TX_32X32;
#endif // CONFIG_TX64X64
break;
}
}
static void combine_interintra(PREDICTION_MODE mode,
uint8_t *comppred,
int compstride,
uint8_t *interpred,
int interstride,
uint8_t *intrapred,
int intrastride,
int bw, int bh) {
static const int scale_bits = 8;
static const int scale_max = 256;
static const int scale_round = 127;
static const int weights1d[64] = {
128, 125, 122, 119, 116, 114, 111, 109,
107, 105, 103, 101, 99, 97, 96, 94,
93, 91, 90, 89, 88, 86, 85, 84,
83, 82, 81, 81, 80, 79, 78, 78,
77, 76, 76, 75, 75, 74, 74, 73,
73, 72, 72, 71, 71, 71, 70, 70,
70, 70, 69, 69, 69, 69, 68, 68,
68, 68, 68, 67, 67, 67, 67, 67,
};
int size = MAX(bw, bh);
int size_scale = (size >= 64 ? 1 :
size == 32 ? 2 :
size == 16 ? 4 :
size == 8 ? 8 : 16);
int i, j;
switch (mode) {
case V_PRED:
for (i = 0; i < bh; ++i) {
for (j = 0; j < bw; ++j) {
int scale = weights1d[i * size_scale];
comppred[i * compstride + j] =
((scale_max - scale) * interpred[i * interstride + j] +
scale * intrapred[i * intrastride + j] + scale_round)
>> scale_bits;
}
}
break;
case H_PRED:
for (i = 0; i < bh; ++i) {
for (j = 0; j < bw; ++j) {
int scale = weights1d[j * size_scale];
comppred[i * compstride + j] =
((scale_max - scale) * interpred[i * interstride + j] +
scale * intrapred[i * intrastride + j] + scale_round)
>> scale_bits;
}
}
break;
case D63_PRED:
case D117_PRED:
for (i = 0; i < bh; ++i) {
for (j = 0; j < bw; ++j) {
int scale = (weights1d[i * size_scale] * 3 +
weights1d[j * size_scale]) >> 2;
comppred[i * compstride + j] =
((scale_max - scale) * interpred[i * interstride + j] +
scale * intrapred[i * intrastride + j] + scale_round)
>> scale_bits;
}
}
break;
case D207_PRED:
case D153_PRED:
for (i = 0; i < bh; ++i) {
for (j = 0; j < bw; ++j) {
int scale = (weights1d[j * size_scale] * 3 +
weights1d[i * size_scale]) >> 2;
comppred[i * compstride + j] =
((scale_max - scale) * interpred[i * interstride + j] +
scale * intrapred[i * intrastride + j] + scale_round)
>> scale_bits;
}
}
break;
case D135_PRED:
for (i = 0; i < bh; ++i) {
for (j = 0; j < bw; ++j) {
int scale = weights1d[(i < j ? i : j) * size_scale];
comppred[i * compstride + j] =
((scale_max - scale) * interpred[i * interstride + j] +
scale * intrapred[i * intrastride + j] + scale_round)
>> scale_bits;
}
}
break;
case D45_PRED:
for (i = 0; i < bh; ++i) {
for (j = 0; j < bw; ++j) {
int scale = (weights1d[i * size_scale] +
weights1d[j * size_scale]) >> 1;
comppred[i * compstride + j] =
((scale_max - scale) * interpred[i * interstride + j] +
scale * intrapred[i * intrastride + j] + scale_round)
>> scale_bits;
}
}
break;
case TM_PRED:
case DC_PRED:
default:
for (i = 0; i < bh; ++i) {
for (j = 0; j < bw; ++j) {
comppred[i * compstride + j] = (interpred[i * interstride + j] +
intrapred[i * intrastride + j]) >> 1;
}
}
break;
}
}
static void build_intra_predictors_for_2nd_block_interintra(
const MACROBLOCKD *xd, const uint8_t *ref,
int ref_stride, uint8_t *dst, int dst_stride,
PREDICTION_MODE mode, TX_SIZE tx_size,
int up_available, int left_available,
int right_available, int bwltbh,
int x, int y, int plane) {
int i;
DECLARE_ALIGNED_ARRAY(16, uint8_t, left_col, 64);
#if CONFIG_TX64X64
DECLARE_ALIGNED_ARRAY(16, uint8_t, above_data, 256 + 16);
#else
DECLARE_ALIGNED_ARRAY(16, uint8_t, above_data, 128 + 16);
#endif
uint8_t *above_row = above_data + 16;
const uint8_t *const_above_row = above_row;
const int bs = 4 << tx_size;
int frame_width, frame_height;
int x0, y0;
const struct macroblockd_plane *const pd = &xd->plane[plane];
const uint8_t *ref_fi;
int ref_stride_fi;
// 127 127 127 .. 127 127 127 127 127 127
// 129 A B .. Y Z
// 129 C D .. W X
// 129 E F .. U V
// 129 G H .. S T T T T T
// ..
// Get current frame pointer, width and height.
if (plane == 0) {
frame_width = xd->cur_buf->y_width;
frame_height = xd->cur_buf->y_height;
} else {
frame_width = xd->cur_buf->uv_width;
frame_height = xd->cur_buf->uv_height;
}
// Get block position in current frame.
x0 = (-xd->mb_to_left_edge >> (3 + pd->subsampling_x)) + x;
y0 = (-xd->mb_to_top_edge >> (3 + pd->subsampling_y)) + y;
vpx_memset(left_col, 129, 64);
// left
if (left_available) {
if (bwltbh) {
ref_fi = ref;
ref_stride_fi = ref_stride;
} else {
ref_fi = dst;
ref_stride_fi = dst_stride;
}
if (xd->mb_to_bottom_edge < 0) {
/* slower path if the block needs border extension */
if (y0 + bs <= frame_height) {
for (i = 0; i < bs; ++i)
left_col[i] = ref_fi[i * ref_stride_fi - 1];
} else {
const int extend_bottom = frame_height - y0;
assert(extend_bottom >= 0);
for (i = 0; i < extend_bottom; ++i)
left_col[i] = ref_fi[i * ref_stride_fi - 1];
for (; i < bs; ++i)
left_col[i] = ref_fi[(extend_bottom - 1) * ref_stride_fi - 1];
}
} else {
/* faster path if the block does not need extension */
for (i = 0; i < bs; ++i)
left_col[i] = ref_fi[i * ref_stride_fi - 1];
}
}
// TODO(hkuang) do not extend 2*bs pixels for all modes.
// above
if (up_available) {
const uint8_t *above_ref;
if (bwltbh) {
ref_fi = dst;
ref_stride_fi = dst_stride;
above_row[-1] = left_available ? ref[-ref_stride-1] : 129;
} else {
ref_fi = ref;
ref_stride_fi = ref_stride;
above_row[-1] = ref[-ref_stride-1];
}
above_ref = ref_fi - ref_stride_fi;
if (xd->mb_to_right_edge < 0) {
/* slower path if the block needs border extension */
if (x0 + 2 * bs <= frame_width) {
if (right_available && bs == 4) {
vpx_memcpy(above_row, above_ref, 2 * bs);
} else {
vpx_memcpy(above_row, above_ref, bs);
vpx_memset(above_row + bs, above_row[bs - 1], bs);
}
} else if (x0 + bs <= frame_width) {
const int r = frame_width - x0;
if (right_available && bs == 4) {
vpx_memcpy(above_row, above_ref, r);
vpx_memset(above_row + r, above_row[r - 1],
x0 + 2 * bs - frame_width);
} else {
vpx_memcpy(above_row, above_ref, bs);
vpx_memset(above_row + bs, above_row[bs - 1], bs);
}
} else if (x0 <= frame_width) {
const int r = frame_width - x0;
assert(r >= 0);
if (right_available && bs == 4) {
vpx_memcpy(above_row, above_ref, r);
vpx_memset(above_row + r, above_row[r - 1],
x0 + 2 * bs - frame_width);
} else {
vpx_memcpy(above_row, above_ref, r);
vpx_memset(above_row + r, above_row[r - 1],
x0 + 2 * bs - frame_width);
}
}
} else {
/* faster path if the block does not need extension */
if (bs == 4 && right_available && left_available) {
const_above_row = above_ref;
} else {
vpx_memcpy(above_row, above_ref, bs);
if (bs == 4 && right_available)
vpx_memcpy(above_row + bs, above_ref + bs, bs);
else
vpx_memset(above_row + bs, above_row[bs - 1], bs);
}
}
} else {
vpx_memset(above_row, 127, bs * 2);
above_row[-1] = 127;
}
// predict
if (mode == DC_PRED) {
dc_pred[left_available][up_available][tx_size](dst, dst_stride,
const_above_row, left_col);
} else {
pred[mode][tx_size](dst, dst_stride, const_above_row, left_col);
}
}
// Break down rectangular intra prediction for joint spatio-temporal prediction
// into two square intra predictions.
static void build_intra_predictors_for_interintra(
MACROBLOCKD *xd,
uint8_t *src, int src_stride,
uint8_t *pred_ptr, int stride,
PREDICTION_MODE mode,
int bw, int bh,
int up_available, int left_available,
int right_available, int plane) {
if (bw == bh) {
build_intra_predictors(xd, src, src_stride, pred_ptr, stride,
mode, intra_size_log2_for_interintra(bw),
up_available, left_available, right_available,
0, 0, plane);
} else if (bw < bh) {
const TX_SIZE tx_size = intra_size_log2_for_interintra(bw);
uint8_t *src_bottom = src + bw * src_stride;
uint8_t *pred_ptr_bottom = pred_ptr + bw * stride;
build_intra_predictors(
xd, src, src_stride, pred_ptr, stride, mode, tx_size,
up_available, left_available, right_available,
0, 0, plane);
build_intra_predictors_for_2nd_block_interintra(
xd, src_bottom, src_stride, pred_ptr_bottom, stride, mode, tx_size,
up_available, left_available, 0,
1, 0, bw, plane);
} else {
const TX_SIZE tx_size = intra_size_log2_for_interintra(bh);
uint8_t *src_right = src + bh;
uint8_t *pred_ptr_right = pred_ptr + bh;
build_intra_predictors(
xd, src, src_stride, pred_ptr, stride, mode, tx_size,
up_available, left_available, 1,
0, 0, plane);
build_intra_predictors_for_2nd_block_interintra(
xd, src_right, src_stride, pred_ptr_right, stride, mode, tx_size,
up_available, left_available, right_available,
0, bh, 0, plane);
}
}
void vp9_build_interintra_predictors_sby(MACROBLOCKD *xd,
uint8_t *ypred,
int ystride,
BLOCK_SIZE bsize) {
int bw = 4 << b_width_log2_lookup[bsize];
int bh = 4 << b_height_log2_lookup[bsize];
uint8_t intrapredictor[4096];
build_intra_predictors_for_interintra(
xd, xd->plane[0].dst.buf, xd->plane[0].dst.stride,
intrapredictor, bw,
xd->mi[0].src_mi->mbmi.interintra_mode, bw, bh,
xd->up_available, xd->left_available, 0, 0);
combine_interintra(xd->mi[0].src_mi->mbmi.interintra_mode,
xd->plane[0].dst.buf, xd->plane[0].dst.stride,
ypred, ystride, intrapredictor, bw, bw, bh);
}
void vp9_build_interintra_predictors_sbuv(MACROBLOCKD *xd,
uint8_t *upred,
uint8_t *vpred,
int ustride, int vstride,
BLOCK_SIZE bsize) {
int bwl = b_width_log2_lookup[bsize], bw = 2 << bwl;
int bhl = b_height_log2_lookup[bsize], bh = 2 << bhl;
uint8_t uintrapredictor[4096];
uint8_t vintrapredictor[4096];
build_intra_predictors_for_interintra(
xd, xd->plane[1].dst.buf, xd->plane[1].dst.stride,
uintrapredictor, bw,
xd->mi[0].src_mi->mbmi.interintra_uv_mode, bw, bh,
xd->up_available, xd->left_available, 0, 1);
build_intra_predictors_for_interintra(
xd, xd->plane[2].dst.buf, xd->plane[1].dst.stride,
vintrapredictor, bw,
xd->mi[0].src_mi->mbmi.interintra_uv_mode, bw, bh,
xd->up_available, xd->left_available, 0, 2);
combine_interintra(xd->mi[0].src_mi->mbmi.interintra_uv_mode,
xd->plane[1].dst.buf, xd->plane[1].dst.stride,
upred, ustride, uintrapredictor, bw, bw, bh);
combine_interintra(xd->mi[0].src_mi->mbmi.interintra_uv_mode,
xd->plane[2].dst.buf, xd->plane[2].dst.stride,
vpred, vstride, vintrapredictor, bw, bw, bh);
}
void vp9_build_interintra_predictors(MACROBLOCKD *xd,
uint8_t *ypred,
uint8_t *upred,
uint8_t *vpred,
int ystride, int ustride, int vstride,
BLOCK_SIZE bsize) {
vp9_build_interintra_predictors_sby(xd, ypred, ystride, bsize);
vp9_build_interintra_predictors_sbuv(xd, upred, vpred,
ustride, vstride, bsize);
}
#endif // CONFIG_INTERINTRA

View File

@ -28,6 +28,26 @@ void vp9_predict_intra_block(const MACROBLOCKD *xd, int block_idx, int bwl_in,
const uint8_t *ref, int ref_stride,
uint8_t *dst, int dst_stride,
int aoff, int loff, int plane);
#if CONFIG_INTERINTRA
void vp9_build_interintra_predictors(MACROBLOCKD *xd,
uint8_t *ypred,
uint8_t *upred,
uint8_t *vpred,
int ystride,
int ustride,
int vstride,
BLOCK_SIZE bsize);
void vp9_build_interintra_predictors_sby(MACROBLOCKD *xd,
uint8_t *ypred,
int ystride,
BLOCK_SIZE bsize);
void vp9_build_interintra_predictors_sbuv(MACROBLOCKD *xd,
uint8_t *upred,
uint8_t *vpred,
int ustride, int vstride,
BLOCK_SIZE bsize);
#endif // CONFIG_INTERINTRA
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -2116,6 +2116,15 @@ static int read_compressed_header(VP9Decoder *pbi, const uint8_t *data,
vp9_diff_update_prob(&r, &fc->copy_mode_probs[j][i]);
}
#endif
#if CONFIG_INTERINTRA
if (cm->reference_mode != COMPOUND_REFERENCE) {
for (i = 0; i < BLOCK_SIZES; i++) {
if (is_interintra_allowed(i)) {
vp9_diff_update_prob(&r, &fc->interintra_prob[i]);
}
}
}
#endif // CONFIG_INTERINTRA
}
return vp9_reader_has_error(&r);

View File

@ -685,6 +685,21 @@ static void read_inter_block_mode_info(VP9_COMMON *const cm,
? read_switchable_interp_filter(cm, xd, r)
: cm->interp_filter;
#if CONFIG_INTERINTRA
if (is_interintra_allowed(bsize) &&
is_inter_mode(mbmi->mode) &&
(mbmi->ref_frame[1] <= INTRA_FRAME)) {
mbmi->ref_frame[1] = vp9_read(r, cm->fc.interintra_prob[bsize]) ?
INTRA_FRAME : NONE;
cm->counts.interintra[bsize][mbmi->ref_frame[1] == INTRA_FRAME]++;
if (mbmi->ref_frame[1] == INTRA_FRAME) {
mbmi->interintra_mode =
read_intra_mode_y(cm, r, size_group_lookup[bsize]);
mbmi->interintra_uv_mode = mbmi->interintra_mode;
}
}
#endif // CONFIG_INTERINTRA
if (bsize < BLOCK_8X8) {
const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize]; // 1 or 2
const int num_4x4_h = num_4x4_blocks_high_lookup[bsize]; // 1 or 2
@ -779,6 +794,10 @@ static void read_inter_frame_mode_info(VP9_COMMON *const cm,
inter_block = 1;
*mbmi = *inter_ref_list[mbmi->copy_mode - REF0];
#if CONFIG_INTERINTRA
if (mbmi->ref_frame[1] == INTRA_FRAME)
mbmi->ref_frame[1] = NONE;
#endif // CONFIG_INTERINTRA
#if CONFIG_SUPERTX
mbmi->tx_size = tx_size_backup;
#endif

View File

@ -528,6 +528,19 @@ static void pack_inter_mode_mvs(VP9_COMP *cpi, const MODE_INFO *mi,
} else {
assert(mbmi->interp_filter == cm->interp_filter);
}
#if CONFIG_INTERINTRA
if (cpi->common.reference_mode != COMPOUND_REFERENCE &&
is_interintra_allowed(bsize) &&
is_inter_mode(mode) &&
(mbmi->ref_frame[1] <= INTRA_FRAME)) {
vp9_write(w, mbmi->ref_frame[1] == INTRA_FRAME,
cm->fc.interintra_prob[bsize]);
if (mbmi->ref_frame[1] == INTRA_FRAME) {
write_intra_mode(w, mbmi->interintra_mode,
cm->fc.y_mode_prob[size_group_lookup[bsize]]);
}
}
#endif // CONFIG_INTERINTRA
if (bsize < BLOCK_8X8) {
const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize];
@ -1622,6 +1635,17 @@ static size_t write_compressed_header(VP9_COMP *cpi, uint8_t *data) {
&header_bc);
}
#endif
#if CONFIG_INTERINTRA
if (cm->reference_mode != COMPOUND_REFERENCE) {
for (i = 0; i < BLOCK_SIZES; i++) {
if (is_interintra_allowed(i)) {
vp9_cond_prob_diff_update(&header_bc,
&fc->interintra_prob[i],
cm->counts.interintra[i]);
}
}
}
#endif // CONFIG_INTERINTRA
}
vp9_stop_encode(&header_bc);

View File

@ -588,6 +588,9 @@ static void choose_partitioning(VP9_COMP *cpi,
vp9_setup_pre_planes(xd, 0, yv12, mi_row, mi_col, sf);
xd->mi[0].src_mi->mbmi.ref_frame[0] = LAST_FRAME;
#if CONFIG_INTERINTRA
xd->mi[0].src_mi->mbmi.ref_frame[1] = NONE;
#endif // CONFIG_INTERINTRA
xd->mi[0].src_mi->mbmi.sb_type = BLOCK_64X64;
vp9_find_best_ref_mvs(xd, cm->allow_high_precision_mv,
xd->mi[0].src_mi->mbmi.ref_mvs[LAST_FRAME],
@ -857,6 +860,18 @@ static void update_state(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
const int ctx = vp9_get_pred_context_switchable_interp(xd);
++cm->counts.switchable_interp[ctx][mbmi->interp_filter];
}
#if CONFIG_INTERINTRA
if (is_interintra_allowed(bsize) &&
is_inter_mode(mbmi->mode) &&
(mbmi->ref_frame[1] <= INTRA_FRAME)) {
if (mbmi->ref_frame[1] == INTRA_FRAME) {
++cm->counts.y_mode[size_group_lookup[bsize]][mbmi->interintra_mode];
++cm->counts.interintra[bsize][1];
} else {
++cm->counts.interintra[bsize][0];
}
}
#endif
}
rd_opt->comp_pred_diff[SINGLE_REFERENCE] += ctx->single_pred_diff;
@ -956,6 +971,19 @@ static void update_state_supertx(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
const int ctx = vp9_get_pred_context_switchable_interp(xd);
++cm->counts.switchable_interp[ctx][mbmi->interp_filter];
}
#if CONFIG_INTERINTRA
if (is_interintra_allowed(bsize) &&
is_inter_mode(mbmi->mode) &&
(mbmi->ref_frame[1] <= INTRA_FRAME)) {
if (mbmi->ref_frame[1] == INTRA_FRAME) {
assert(0);
++cm->counts.y_mode[size_group_lookup[bsize]][mbmi->interintra_mode];
++cm->counts.interintra[bsize][1];
} else {
++cm->counts.interintra[bsize][0];
}
}
#endif // CONFIG_INTERINTRA
}
rd_opt->comp_pred_diff[SINGLE_REFERENCE] += ctx->single_pred_diff;
@ -4801,7 +4829,12 @@ static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t, int output_enabled,
#if CONFIG_SUPERTX
static int check_intra_b(PICK_MODE_CONTEXT *ctx) {
#if CONFIG_INTERINTRA
return !is_inter_mode((&ctx->mic)->mbmi.mode) ||
(ctx->mic.mbmi.ref_frame[1] == INTRA_FRAME);
#else
return !is_inter_mode((&ctx->mic)->mbmi.mode);
#endif // CONFIG_INTERINTRA
}
static int check_intra_sb(VP9_COMP *cpi, const TileInfo *const tile,

View File

@ -65,6 +65,9 @@ static unsigned int do_16x16_motion_iteration(VP9_COMP *cpi,
xd->mi[0].src_mi->mbmi.mode = NEWMV;
xd->mi[0].src_mi->mbmi.mv[0].as_mv = *dst_mv;
#if CONFIG_INTERINTRA
xd->mi[0].src_mi->mbmi.ref_frame[1] = NONE;
#endif
vp9_build_inter_predictors_sby(xd, mb_row, mb_col, BLOCK_16X16);

View File

@ -609,6 +609,24 @@ void vp9_set_rd_speed_thresholds(VP9_COMP *cpi) {
rd->thresh_mult[THR_D153_PRED] += 2500;
rd->thresh_mult[THR_D207_PRED] += 2500;
rd->thresh_mult[THR_D63_PRED] += 2500;
#if CONFIG_INTERINTRA
rd->thresh_mult[THR_COMP_INTERINTRA_ZEROL ] += 1500;
rd->thresh_mult[THR_COMP_INTERINTRA_ZEROG ] += 1500;
rd->thresh_mult[THR_COMP_INTERINTRA_ZEROA ] += 1500;
rd->thresh_mult[THR_COMP_INTERINTRA_NEARESTL] += 1500;
rd->thresh_mult[THR_COMP_INTERINTRA_NEARESTG] += 1500;
rd->thresh_mult[THR_COMP_INTERINTRA_NEARESTA] += 1500;
rd->thresh_mult[THR_COMP_INTERINTRA_NEARL ] += 1500;
rd->thresh_mult[THR_COMP_INTERINTRA_NEARG ] += 1500;
rd->thresh_mult[THR_COMP_INTERINTRA_NEARA ] += 1500;
rd->thresh_mult[THR_COMP_INTERINTRA_NEWL ] += 2000;
rd->thresh_mult[THR_COMP_INTERINTRA_NEWG ] += 2000;
rd->thresh_mult[THR_COMP_INTERINTRA_NEWA ] += 2000;
#endif
}
void vp9_set_rd_speed_thresholds_sub8x8(VP9_COMP *cpi) {

View File

@ -33,7 +33,12 @@ extern "C" {
#define INVALID_MV 0x80008000
#if CONFIG_INTERINTRA
#define MAX_MODES 42
#define INTERINTRA_START_MODE 30
#else
#define MAX_MODES 30
#endif // CONFIG_INTERINTRA
#define MAX_REFS 6
// This enumerator type needs to be kept aligned with the mode order in
@ -78,6 +83,23 @@ typedef enum {
THR_D63_PRED,
THR_D117_PRED,
THR_D45_PRED,
#if CONFIG_INTERINTRA
THR_COMP_INTERINTRA_ZEROL,
THR_COMP_INTERINTRA_NEARESTL,
THR_COMP_INTERINTRA_NEARL,
THR_COMP_INTERINTRA_NEWL,
THR_COMP_INTERINTRA_ZEROG,
THR_COMP_INTERINTRA_NEARESTG,
THR_COMP_INTERINTRA_NEARG,
THR_COMP_INTERINTRA_NEWG,
THR_COMP_INTERINTRA_ZEROA,
THR_COMP_INTERINTRA_NEARESTA,
THR_COMP_INTERINTRA_NEARA,
THR_COMP_INTERINTRA_NEWA,
#endif // CONFIG_INTERINTRA
} THR_MODES;
typedef enum {

View File

@ -122,6 +122,23 @@ static const MODE_DEFINITION vp9_mode_order[MAX_MODES] = {
{D63_PRED, {INTRA_FRAME, NONE}},
{D117_PRED, {INTRA_FRAME, NONE}},
{D45_PRED, {INTRA_FRAME, NONE}},
#if CONFIG_INTERINTRA
{ZEROMV, {LAST_FRAME, INTRA_FRAME}},
{NEARESTMV, {LAST_FRAME, INTRA_FRAME}},
{NEARMV, {LAST_FRAME, INTRA_FRAME}},
{NEWMV, {LAST_FRAME, INTRA_FRAME}},
{ZEROMV, {GOLDEN_FRAME, INTRA_FRAME}},
{NEARESTMV, {GOLDEN_FRAME, INTRA_FRAME}},
{NEARMV, {GOLDEN_FRAME, INTRA_FRAME}},
{NEWMV, {GOLDEN_FRAME, INTRA_FRAME}},
{ZEROMV, {ALTREF_FRAME, INTRA_FRAME}},
{NEARESTMV, {ALTREF_FRAME, INTRA_FRAME}},
{NEARMV, {ALTREF_FRAME, INTRA_FRAME}},
{NEWMV, {ALTREF_FRAME, INTRA_FRAME}},
#endif // CONFIG_INTERINTRA
};
static const REF_DEFINITION vp9_ref_order[MAX_REFS] = {
@ -1168,7 +1185,7 @@ static int64_t rd_pick_intra_sub_8x8_y_mode(VP9_COMP *cpi, MACROBLOCK *mb,
bmode_costs = cpi->y_mode_costs[A][L];
}
this_rd = rd_pick_intra4x4block(cpi, mb, i, &best_mode,
this_rd = rd_pick_intra4x4block(cpi, mb, i, &best_mode,
#if CONFIG_FILTERINTRA
&best_fbit,
#endif
@ -1881,6 +1898,9 @@ static int check_best_zero_mv(
if ((this_mode == NEARMV || this_mode == NEARESTMV || this_mode == ZEROMV) &&
frame_mv[this_mode][ref_frames[0]].as_int == 0 &&
(ref_frames[1] == NONE ||
#if CONFIG_INTERINTRA
ref_frames[1] == INTRA_FRAME ||
#endif
frame_mv[this_mode][ref_frames[1]].as_int == 0)) {
int rfc = mode_context[ref_frames[0]];
int c1 = cost_mv_ref(cpi, NEARMV, rfc);
@ -1893,7 +1913,11 @@ static int check_best_zero_mv(
if (c2 > c3) return 0;
} else {
assert(this_mode == ZEROMV);
if (ref_frames[1] == NONE) {
if (ref_frames[1] == NONE
#if CONFIG_INTERINTRA
|| ref_frames[1] == INTRA_FRAME
#endif
) {
if ((c3 >= c2 && frame_mv[NEARESTMV][ref_frames[0]].as_int == 0) ||
(c3 >= c1 && frame_mv[NEARMV][ref_frames[0]].as_int == 0))
return 0;
@ -2741,6 +2765,10 @@ static int64_t handle_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
int_mv single_newmv[MAX_REF_FRAMES],
INTERP_FILTER (*single_filter)[MAX_REF_FRAMES],
int (*single_skippable)[MAX_REF_FRAMES],
#if CONFIG_INTERINTRA
int *compmode_interintra_cost,
int single_newmv_rate[MAX_REF_FRAMES],
#endif
int64_t *psse,
const int64_t ref_best_rd) {
VP9_COMMON *cm = &cpi->common;
@ -2768,6 +2796,10 @@ static int64_t handle_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
uint8_t *orig_dst[MAX_MB_PLANE];
int orig_dst_stride[MAX_MB_PLANE];
int rs = 0;
#if CONFIG_INTERINTRA
int rate_mv_tmp = 0;
const int is_comp_interintra_pred = (mbmi->ref_frame[1] == INTRA_FRAME);
#endif
INTERP_FILTER best_filter = SWITCHABLE;
uint8_t skip_txfm[MAX_MB_PLANE << 2] = {0};
int64_t bsse[MAX_MB_PLANE << 2] = {0};
@ -2830,9 +2862,26 @@ static int64_t handle_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
&mbmi->ref_mvs[refs[1]][0].as_mv,
x->nmvjointcost, x->mvcost, MV_COST_WEIGHT);
}
#if !CONFIG_INTERINTRA
*rate2 += rate_mv;
#endif
} else {
int_mv tmp_mv;
#if CONFIG_INTERINTRA
if (!is_comp_interintra_pred) {
single_motion_search(cpi, x, bsize, mi_row, mi_col,
&tmp_mv, &rate_mv);
if (tmp_mv.as_int == INVALID_MV)
return INT64_MAX;
frame_mv[refs[0]].as_int =
xd->mi[0].src_mi->bmi[0].as_mv[0].as_int = tmp_mv.as_int;
single_newmv[refs[0]].as_int = tmp_mv.as_int;
single_newmv_rate[refs[0]] = rate_mv;
} else {
frame_mv[refs[0]].as_int = single_newmv[refs[0]].as_int;
rate_mv = single_newmv_rate[refs[0]];
}
#else
single_motion_search(cpi, x, bsize, mi_row, mi_col,
&tmp_mv, &rate_mv);
if (tmp_mv.as_int == INVALID_MV)
@ -2841,7 +2890,11 @@ static int64_t handle_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
frame_mv[refs[0]].as_int =
xd->mi[0].src_mi->bmi[0].as_mv[0].as_int = tmp_mv.as_int;
single_newmv[refs[0]].as_int = tmp_mv.as_int;
#endif // CONFIG_INTERINTRA
}
#if CONFIG_INTERINTRA
rate_mv_tmp = rate_mv;
#endif
}
for (i = 0; i < is_comp_pred + 1; ++i) {
@ -2925,6 +2978,10 @@ static int64_t handle_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
if ((cm->interp_filter == SWITCHABLE &&
(!i || best_needs_copy)) ||
#if CONFIG_INTERINTRA
(is_inter_mode(this_mode) && is_comp_interintra_pred &&
is_interintra_allowed(mbmi->sb_type)) ||
#endif
(cm->interp_filter != SWITCHABLE &&
(cm->interp_filter == mbmi->interp_filter ||
(i == 0 && intpel_mv)))) {
@ -2988,6 +3045,61 @@ static int64_t handle_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
cm->interp_filter : best_filter;
rs = cm->interp_filter == SWITCHABLE ? vp9_get_switchable_rate(cpi) : 0;
#if CONFIG_INTERINTRA
if ((!is_comp_pred) && is_comp_interintra_pred &&
is_interintra_allowed(mbmi->sb_type)) {
PREDICTION_MODE interintra_mode, best_interintra_mode = DC_PRED;
int64_t best_interintra_rd = INT64_MAX;
int rmode, rate_sum;
int64_t dist_sum;
int j;
mbmi->ref_frame[1] = NONE;
for (j = 0; j < MAX_MB_PLANE; j++) {
xd->plane[j].dst.buf = tmp_buf + j * 64 * 64;
xd->plane[j].dst.stride = 64;
}
vp9_build_inter_predictors_sb(xd, mi_row, mi_col, bsize);
restore_dst_buf(xd, orig_dst, orig_dst_stride);
mbmi->ref_frame[1] = INTRA_FRAME;
for (interintra_mode = DC_PRED; interintra_mode <= TM_PRED;
++interintra_mode) {
mbmi->interintra_mode = interintra_mode;
mbmi->interintra_uv_mode = interintra_mode;
rmode = cpi->mbmode_cost[mbmi->interintra_mode];
vp9_build_interintra_predictors(xd, tmp_buf, tmp_buf + 64 * 64,
tmp_buf + 2* 64 * 64, 64, 64, 64, bsize);
model_rd_for_sb(cpi, bsize, x, xd, &rate_sum, &dist_sum,
&skip_txfm_sb, &skip_sse_sb);
rd = RDCOST(x->rdmult, x->rddiv, rmode + rate_sum, dist_sum);
if (rd < best_interintra_rd) {
best_interintra_rd = rd;
best_interintra_mode = interintra_mode;
}
}
mbmi->interintra_mode = best_interintra_mode;
mbmi->interintra_uv_mode = best_interintra_mode;
if (ref_best_rd < INT64_MAX &&
best_interintra_rd / 2 > ref_best_rd) {
return INT64_MAX;
}
pred_exists = 0;
tmp_rd = best_interintra_rd;
}
if (!is_comp_pred && is_interintra_allowed(mbmi->sb_type)) {
*compmode_interintra_cost = vp9_cost_bit(cm->fc.interintra_prob[bsize],
is_comp_interintra_pred);
if (is_comp_interintra_pred) {
*compmode_interintra_cost += cpi->mbmode_cost[mbmi->interintra_mode];
}
}
#endif // CONFIG_INTERINTRA
#if CONFIG_INTERINTRA
*rate2 += rate_mv_tmp;
#endif
if (pred_exists) {
if (best_needs_copy) {
// again temporarily set the buffers to local memory to prevent a memcpy
@ -3310,6 +3422,9 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x,
#if CONFIG_FILTERINTRA
int fbit_uv[TX_SIZES];
#endif
#if CONFIG_INTERINTRA
int single_newmv_rate[MAX_REF_FRAMES] = { 0 };
#endif // CONFIG_INTERINTRA
const int intra_cost_penalty = vp9_get_intra_cost_penalty(
cm->base_qindex, cm->y_dc_delta_q, cm->bit_depth);
int best_skip2 = 0;
@ -3471,6 +3586,9 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x,
int64_t this_rd = INT64_MAX;
int disable_skip = 0;
int compmode_cost = 0;
#if CONFIG_INTERINTRA
int compmode_interintra_cost = 0;
#endif
int rate2 = 0, rate_y = 0, rate_uv = 0;
int64_t distortion2 = 0, distortion_y = 0, distortion_uv = 0;
int skippable = 0;
@ -3626,6 +3744,11 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x,
this_mode, ref_frames))
continue;
}
#if CONFIG_INTERINTRA
if (ref_frame > INTRA_FRAME && second_ref_frame == INTRA_FRAME &&
!is_interintra_allowed(bsize))
continue;
#endif
mbmi->mode = this_mode;
mbmi->uv_mode = DC_PRED;
@ -3656,6 +3779,10 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x,
for (i = 0; i < TX_MODES; ++i)
tx_cache[i] = INT64_MAX;
#if CONFIG_INTERINTRA
mbmi->interintra_mode = (PREDICTION_MODE)(DC_PRED - 1);
mbmi->interintra_uv_mode = (PREDICTION_MODE)(DC_PRED - 1);
#endif
if (ref_frame == INTRA_FRAME) {
TX_SIZE uv_tx;
@ -3773,6 +3900,12 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x,
rate2 += intra_cost_penalty;
distortion2 = distortion_y + distortion_uv;
} else {
#if CONFIG_INTERINTRA
if (second_ref_frame == INTRA_FRAME) {
mbmi->interintra_mode = best_intra_mode;
mbmi->interintra_uv_mode = best_intra_mode;
}
#endif
#if CONFIG_EXT_TX
mbmi->ext_txfrm = NORM;
#endif
@ -3782,8 +3915,14 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x,
&rate_y, &rate_uv,
&disable_skip, frame_mv,
mi_row, mi_col,
single_newmv, single_inter_filter,
single_skippable, &total_sse, best_rd);
single_newmv,
single_inter_filter,
single_skippable,
#if CONFIG_INTERINTRA
&compmode_interintra_cost,
single_newmv_rate,
#endif
&total_sse, best_rd);
if (this_rd == INT64_MAX)
continue;
@ -3793,6 +3932,10 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x,
rate2 += compmode_cost;
}
#if CONFIG_INTERINTRA
rate2 += compmode_interintra_cost;
#endif // CONFIG_INTERINTRA
// Estimate the reference frame signaling cost and add it
// to the rolling cost variable.
if (comp_pred) {
@ -4113,6 +4256,10 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x,
#endif
*mbmi = *inter_ref_list[copy_mode - REF0];
#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;