Commit 28744309 authored by Alex Converse's avatar Alex Converse

intrabc: Add initial skeleton

Missing features:
* RDOPT (Forced on for certain blocks)
* Any form of border extension
* Non MI sized right and bottom edges
* MV prediction

Present features:
* Force intrabc for some blocks
* Carry intrabc in the bitstream
* Validate DV is causal
* Reconstruct intrabc block assuming border extension is unnecessary

Change-Id: Ib1f6868e89bfacc2a4edfc876485bad1b347263b
parent de8f8f7a
...@@ -324,6 +324,9 @@ typedef struct { ...@@ -324,6 +324,9 @@ typedef struct {
#if CONFIG_PALETTE #if CONFIG_PALETTE
PALETTE_MODE_INFO palette_mode_info; PALETTE_MODE_INFO palette_mode_info;
#endif // CONFIG_PALETTE #endif // CONFIG_PALETTE
#if CONFIG_INTRABC
uint8_t use_intrabc;
#endif // CONFIG_INTRABC
// Only for INTER blocks // Only for INTER blocks
#if CONFIG_DUAL_FILTER #if CONFIG_DUAL_FILTER
...@@ -396,6 +399,12 @@ typedef struct MODE_INFO { ...@@ -396,6 +399,12 @@ typedef struct MODE_INFO {
b_mode_info bmi[4]; b_mode_info bmi[4];
} MODE_INFO; } MODE_INFO;
#if CONFIG_INTRABC
static INLINE int is_intrabc_block(const MB_MODE_INFO *mbmi) {
return mbmi->use_intrabc;
}
#endif
static INLINE PREDICTION_MODE get_y_mode(const MODE_INFO *mi, int block) { static INLINE PREDICTION_MODE get_y_mode(const MODE_INFO *mi, int block) {
#if CONFIG_CB4X4 #if CONFIG_CB4X4
(void)block; (void)block;
...@@ -406,6 +415,9 @@ static INLINE PREDICTION_MODE get_y_mode(const MODE_INFO *mi, int block) { ...@@ -406,6 +415,9 @@ static INLINE PREDICTION_MODE get_y_mode(const MODE_INFO *mi, int block) {
} }
static INLINE int is_inter_block(const MB_MODE_INFO *mbmi) { static INLINE int is_inter_block(const MB_MODE_INFO *mbmi) {
#if CONFIG_INTRABC
if (is_intrabc_block(mbmi)) return 1;
#endif
return mbmi->ref_frame[0] > INTRA_FRAME; return mbmi->ref_frame[0] > INTRA_FRAME;
} }
...@@ -911,6 +923,10 @@ static INLINE TX_TYPE get_tx_type(PLANE_TYPE plane_type, const MACROBLOCKD *xd, ...@@ -911,6 +923,10 @@ static INLINE TX_TYPE get_tx_type(PLANE_TYPE plane_type, const MACROBLOCKD *xd,
int block, TX_SIZE tx_size) { int block, TX_SIZE tx_size) {
const MODE_INFO *const mi = xd->mi[0]; const MODE_INFO *const mi = xd->mi[0];
const MB_MODE_INFO *const mbmi = &mi->mbmi; const MB_MODE_INFO *const mbmi = &mi->mbmi;
#if CONFIG_INTRABC
// TODO(aconverse@google.com): Revisit this decision
if (is_intrabc_block(mbmi)) return DCT_DCT;
#endif // CONFIG_INTRABC
#if !CONFIG_TXK_SEL #if !CONFIG_TXK_SEL
const int block_raster_idx = av1_block_index_to_raster_order(tx_size, block); const int block_raster_idx = av1_block_index_to_raster_order(tx_size, block);
if (FIXED_TX_TYPE) if (FIXED_TX_TYPE)
......
...@@ -69,6 +69,10 @@ extern "C" { ...@@ -69,6 +69,10 @@ extern "C" {
#define PALETTE_MAX_BLOCK_SIZE (64 * 64) #define PALETTE_MAX_BLOCK_SIZE (64 * 64)
#endif // CONFIG_PALETTE #endif // CONFIG_PALETTE
#if CONFIG_INTRABC
#define INTRABC_PROB 192
#endif // CONFIG_INTRABC
struct AV1Common; struct AV1Common;
typedef struct { typedef struct {
...@@ -218,6 +222,9 @@ typedef struct frame_contexts { ...@@ -218,6 +222,9 @@ typedef struct frame_contexts {
nmv_context nmvc[NMV_CONTEXTS]; nmv_context nmvc[NMV_CONTEXTS];
#else #else
nmv_context nmvc; nmv_context nmvc;
#endif
#if CONFIG_INTRABC
nmv_context ndvc;
#endif #endif
int initialized; int initialized;
#if CONFIG_EXT_TX #if CONFIG_EXT_TX
...@@ -381,6 +388,9 @@ typedef struct FRAME_COUNTS { ...@@ -381,6 +388,9 @@ typedef struct FRAME_COUNTS {
#else #else
nmv_context_counts mv; nmv_context_counts mv;
#endif #endif
#if CONFIG_INTRABC
nmv_context_counts dv;
#endif
#if CONFIG_DELTA_Q #if CONFIG_DELTA_Q
unsigned int delta_q[DELTA_Q_PROBS][2]; unsigned int delta_q[DELTA_Q_PROBS][2];
#endif #endif
......
...@@ -332,7 +332,10 @@ void av1_init_mv_probs(AV1_COMMON *cm) { ...@@ -332,7 +332,10 @@ void av1_init_mv_probs(AV1_COMMON *cm) {
} }
#else #else
cm->fc->nmvc = default_nmv_context; cm->fc->nmvc = default_nmv_context;
#endif #endif // CONFIG_REF_MV
#if CONFIG_INTRABC
cm->fc->ndvc = default_nmv_context;
#endif // CONFIG_INTRABC
#if CONFIG_GLOBAL_MOTION #if CONFIG_GLOBAL_MOTION
av1_copy(cm->fc->global_motion_types_prob, default_global_motion_types_prob); av1_copy(cm->fc->global_motion_types_prob, default_global_motion_types_prob);
#endif // CONFIG_GLOBAL_MOTION #endif // CONFIG_GLOBAL_MOTION
......
...@@ -515,6 +515,57 @@ int findSamples(const AV1_COMMON *cm, MACROBLOCKD *xd, int mi_row, int mi_col, ...@@ -515,6 +515,57 @@ int findSamples(const AV1_COMMON *cm, MACROBLOCKD *xd, int mi_row, int mi_col,
int *pts, int *pts_inref); int *pts, int *pts_inref);
#endif // CONFIG_WARPED_MOTION #endif // CONFIG_WARPED_MOTION
#if CONFIG_INTRABC
static INLINE void av1_find_ref_dv(int_mv *ref_dv, int mi_row, int mi_col) {
// TODO(aconverse@google.com): Handle tiles and such
(void)mi_col;
if (mi_row < MAX_MIB_SIZE) {
ref_dv->as_mv.row = 0;
ref_dv->as_mv.col = -MI_SIZE * MAX_MIB_SIZE;
} else {
ref_dv->as_mv.row = -MI_SIZE * MAX_MIB_SIZE;
ref_dv->as_mv.col = 0;
}
}
static INLINE int is_dv_valid(const MV dv, const TileInfo *const tile,
int mi_row, int mi_col, BLOCK_SIZE bsize) {
const int bw = block_size_wide[bsize];
const int bh = block_size_high[bsize];
const int SCALE_PX_TO_MV = 8;
// Disallow subpixel for now
// SUBPEL_MASK is not the correct scale
if ((dv.row & (SCALE_PX_TO_MV - 1) || dv.col & (SCALE_PX_TO_MV - 1)))
return 0;
// Is the source top-left inside the current tile?
const int src_top_edge = mi_row * MI_SIZE * SCALE_PX_TO_MV + dv.row;
const int tile_top_edge = tile->mi_row_start * MI_SIZE * SCALE_PX_TO_MV;
if (src_top_edge < tile_top_edge) return 0;
const int src_left_edge = mi_col * MI_SIZE * SCALE_PX_TO_MV + dv.col;
const int tile_left_edge = tile->mi_col_start * MI_SIZE * SCALE_PX_TO_MV;
if (src_left_edge < tile_left_edge) return 0;
// Is the bottom right inside the current tile?
const int src_bottom_edge = (mi_row * MI_SIZE + bh) * SCALE_PX_TO_MV + dv.row;
const int tile_bottom_edge = tile->mi_row_end * MI_SIZE * SCALE_PX_TO_MV;
if (src_bottom_edge > tile_bottom_edge) return 0;
const int src_right_edge = (mi_col * MI_SIZE + bw) * SCALE_PX_TO_MV + dv.col;
const int tile_right_edge = tile->mi_col_end * MI_SIZE * SCALE_PX_TO_MV;
if (src_right_edge > tile_right_edge) return 0;
// Is the bottom right within an already coded SB?
const int active_sb_top_edge =
(mi_row & ~MAX_MIB_MASK) * MI_SIZE * SCALE_PX_TO_MV;
const int active_sb_bottom_edge =
((mi_row & ~MAX_MIB_MASK) + MAX_MIB_SIZE) * MI_SIZE * SCALE_PX_TO_MV;
const int active_sb_left_edge =
(mi_col & ~MAX_MIB_MASK) * MI_SIZE * SCALE_PX_TO_MV;
if (src_bottom_edge > active_sb_bottom_edge) return 0;
if (src_bottom_edge > active_sb_top_edge &&
src_right_edge > active_sb_left_edge)
return 0;
return 1;
}
#endif // CONFIG_INTRABC
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif
......
...@@ -906,6 +906,18 @@ void build_inter_predictors(MACROBLOCKD *xd, int plane, ...@@ -906,6 +906,18 @@ void build_inter_predictors(MACROBLOCKD *xd, int plane,
#endif // CONFIG_MOTION_VAR #endif // CONFIG_MOTION_VAR
const int is_compound = has_second_ref(&mi->mbmi); const int is_compound = has_second_ref(&mi->mbmi);
int ref; int ref;
#if CONFIG_INTRABC
const int is_intrabc = is_intrabc_block(&mi->mbmi);
struct scale_factors sf_identity;
#if CONFIG_HIGHBITDEPTH
av1_setup_scale_factors_for_frame(
&sf_identity, 64, 64, 64, 64,
xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH);
#else
av1_setup_scale_factors_for_frame(&sf_identity, 64, 64, 64, 64);
#endif // CONFIG_HIGHBITDEPTH
assert(IMPLIES(is_intrabc, !is_compound));
#endif // CONFIG_INTRABC
#if CONFIG_GLOBAL_MOTION #if CONFIG_GLOBAL_MOTION
int is_global[2]; int is_global[2];
for (ref = 0; ref < 1 + is_compound; ++ref) { for (ref = 0; ref < 1 + is_compound; ++ref) {
...@@ -946,9 +958,15 @@ void build_inter_predictors(MACROBLOCKD *xd, int plane, ...@@ -946,9 +958,15 @@ void build_inter_predictors(MACROBLOCKD *xd, int plane,
for (idx = 0; idx < b8_s; idx += b4_w) { for (idx = 0; idx < b8_s; idx += b4_w) {
const int chr_idx = (idy * 2) + idx; const int chr_idx = (idy * 2) + idx;
for (ref = 0; ref < 1 + is_compound; ++ref) { for (ref = 0; ref < 1 + is_compound; ++ref) {
struct buf_2d *const dst_buf = &pd->dst;
#if CONFIG_INTRABC
const struct scale_factors *const sf =
is_intrabc ? &sf_identity : &xd->block_refs[ref]->sf;
struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref];
#else
const struct scale_factors *const sf = &xd->block_refs[ref]->sf; const struct scale_factors *const sf = &xd->block_refs[ref]->sf;
struct buf_2d *const pre_buf = &pd->pre[ref]; struct buf_2d *const pre_buf = &pd->pre[ref];
struct buf_2d *const dst_buf = &pd->dst; #endif // CONFIG_INTRABC
uint8_t *dst = dst_buf->buf; uint8_t *dst = dst_buf->buf;
const MV mv = mi->bmi[chr_idx].as_mv[ref].as_mv; const MV mv = mi->bmi[chr_idx].as_mv[ref].as_mv;
const MV mv_q4 = clamp_mv_to_umv_border_sb( const MV mv_q4 = clamp_mv_to_umv_border_sb(
...@@ -1038,8 +1056,14 @@ void build_inter_predictors(MACROBLOCKD *xd, int plane, ...@@ -1038,8 +1056,14 @@ void build_inter_predictors(MACROBLOCKD *xd, int plane,
#endif // CONFIG_CONVOLVE_ROUND #endif // CONFIG_CONVOLVE_ROUND
for (ref = 0; ref < 1 + is_compound; ++ref) { for (ref = 0; ref < 1 + is_compound; ++ref) {
#if CONFIG_INTRABC
const struct scale_factors *const sf =
is_intrabc ? &sf_identity : &xd->block_refs[ref]->sf;
struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref];
#else
const struct scale_factors *const sf = &xd->block_refs[ref]->sf; const struct scale_factors *const sf = &xd->block_refs[ref]->sf;
struct buf_2d *const pre_buf = &pd->pre[ref]; struct buf_2d *const pre_buf = &pd->pre[ref];
#endif // CONFIG_INTRABC
#if CONFIG_CB4X4 #if CONFIG_CB4X4
const MV mv = mi->mbmi.mv[ref].as_mv; const MV mv = mi->mbmi.mv[ref].as_mv;
#else #else
...@@ -1090,8 +1114,14 @@ void build_inter_predictors(MACROBLOCKD *xd, int plane, ...@@ -1090,8 +1114,14 @@ void build_inter_predictors(MACROBLOCKD *xd, int plane,
ConvolveParams conv_params = get_conv_params(ref, plane); ConvolveParams conv_params = get_conv_params(ref, plane);
#endif // CONFIG_CONVOLVE_ROUND #endif // CONFIG_CONVOLVE_ROUND
for (ref = 0; ref < 1 + is_compound; ++ref) { for (ref = 0; ref < 1 + is_compound; ++ref) {
#if CONFIG_INTRABC
const struct scale_factors *const sf =
is_intrabc ? &sf_identity : &xd->block_refs[ref]->sf;
struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref];
#else
const struct scale_factors *const sf = &xd->block_refs[ref]->sf; const struct scale_factors *const sf = &xd->block_refs[ref]->sf;
struct buf_2d *const pre_buf = &pd->pre[ref]; struct buf_2d *const pre_buf = &pd->pre[ref];
#endif // CONFIG_INTRABC
#if CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION #if CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION
WarpTypesAllowed warp_types; WarpTypesAllowed warp_types;
#if CONFIG_GLOBAL_MOTION #if CONFIG_GLOBAL_MOTION
......
...@@ -57,6 +57,7 @@ static INLINE void inter_predictor(const uint8_t *src, int src_stride, ...@@ -57,6 +57,7 @@ static INLINE void inter_predictor(const uint8_t *src, int src_stride,
av1_get_interp_filter_params(interp_filter); av1_get_interp_filter_params(interp_filter);
#endif #endif
assert(sf);
#if CONFIG_DUAL_FILTER #if CONFIG_DUAL_FILTER
if (interp_filter_params_x.taps == SUBPEL_TAPS && if (interp_filter_params_x.taps == SUBPEL_TAPS &&
interp_filter_params_y.taps == SUBPEL_TAPS && w > 2 && h > 2 && interp_filter_params_y.taps == SUBPEL_TAPS && w > 2 && h > 2 &&
......
...@@ -1728,13 +1728,24 @@ static void decode_token_and_recon_block(AV1Decoder *const pbi, ...@@ -1728,13 +1728,24 @@ static void decode_token_and_recon_block(AV1Decoder *const pbi,
for (ref = 0; ref < 1 + has_second_ref(mbmi); ++ref) { for (ref = 0; ref < 1 + has_second_ref(mbmi); ++ref) {
const MV_REFERENCE_FRAME frame = mbmi->ref_frame[ref]; const MV_REFERENCE_FRAME frame = mbmi->ref_frame[ref];
RefBuffer *ref_buf = &cm->frame_refs[frame - LAST_FRAME]; if (frame < LAST_FRAME) {
#if CONFIG_INTRABC
xd->block_refs[ref] = ref_buf; assert(is_intrabc_block(mbmi));
if ((!av1_is_valid_scale(&ref_buf->sf))) assert(frame == INTRA_FRAME);
aom_internal_error(xd->error_info, AOM_CODEC_UNSUP_BITSTREAM, assert(ref == 0);
"Reference frame has invalid dimensions"); #else
av1_setup_pre_planes(xd, ref, ref_buf->buf, mi_row, mi_col, &ref_buf->sf); assert(0);
#endif // CONFIG_INTRABC
} else {
RefBuffer *ref_buf = &cm->frame_refs[frame - LAST_FRAME];
xd->block_refs[ref] = ref_buf;
if ((!av1_is_valid_scale(&ref_buf->sf)))
aom_internal_error(xd->error_info, AOM_CODEC_UNSUP_BITSTREAM,
"Reference frame has invalid dimensions");
av1_setup_pre_planes(xd, ref, ref_buf->buf, mi_row, mi_col,
&ref_buf->sf);
}
} }
#if CONFIG_CB4X4 #if CONFIG_CB4X4
......
...@@ -902,6 +902,32 @@ void av1_read_tx_type(const AV1_COMMON *const cm, MACROBLOCKD *xd, ...@@ -902,6 +902,32 @@ void av1_read_tx_type(const AV1_COMMON *const cm, MACROBLOCKD *xd,
} }
} }
#if CONFIG_INTRABC
static INLINE void read_mv(aom_reader *r, MV *mv, const MV *ref,
nmv_context *ctx, nmv_context_counts *counts,
int allow_hp);
static INLINE int is_mv_valid(const MV *mv);
static INLINE int assign_dv(AV1_COMMON *cm, MACROBLOCKD *xd, int_mv *mv,
const int_mv *ref_mv, int mi_row, int mi_col,
BLOCK_SIZE bsize, aom_reader *r) {
#if CONFIG_EC_ADAPT
FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
(void)cm;
#else
FRAME_CONTEXT *ec_ctx = cm->fc;
#endif
FRAME_COUNTS *counts = xd->counts;
nmv_context_counts *const dv_counts = counts ? &counts->dv : NULL;
read_mv(r, &mv->as_mv, &ref_mv->as_mv, &ec_ctx->ndvc, dv_counts, 0);
int valid = is_mv_valid(&mv->as_mv) &&
is_dv_valid(mv->as_mv, &xd->tile, mi_row, mi_col, bsize);
// TODO(aconverse@google.com): additional validation
return valid;
}
#endif // CONFIG_INTRABC
static void read_intra_frame_mode_info(AV1_COMMON *const cm, static void read_intra_frame_mode_info(AV1_COMMON *const cm,
MACROBLOCKD *const xd, int mi_row, MACROBLOCKD *const xd, int mi_row,
int mi_col, aom_reader *r) { int mi_col, aom_reader *r) {
...@@ -942,6 +968,21 @@ static void read_intra_frame_mode_info(AV1_COMMON *const cm, ...@@ -942,6 +968,21 @@ static void read_intra_frame_mode_info(AV1_COMMON *const cm,
mbmi->ref_frame[0] = INTRA_FRAME; mbmi->ref_frame[0] = INTRA_FRAME;
mbmi->ref_frame[1] = NONE_FRAME; mbmi->ref_frame[1] = NONE_FRAME;
#if CONFIG_INTRABC
if (bsize >= BLOCK_8X8 && cm->allow_screen_content_tools) {
mbmi->use_intrabc = aom_read(r, INTRABC_PROB, ACCT_STR);
if (mbmi->use_intrabc) {
int_mv dv_ref;
mbmi->mode = mbmi->uv_mode = DC_PRED;
mbmi->interp_filter = BILINEAR;
av1_find_ref_dv(&dv_ref, mi_row, mi_col);
xd->corrupted |=
!assign_dv(cm, xd, &mbmi->mv[0], &dv_ref, mi_row, mi_col, bsize, r);
return;
}
}
#endif // CONFIG_INTRABC
#if CONFIG_CB4X4 #if CONFIG_CB4X4
(void)i; (void)i;
mbmi->mode = mbmi->mode =
...@@ -2283,6 +2324,10 @@ void av1_read_mode_info(AV1Decoder *const pbi, MACROBLOCKD *xd, ...@@ -2283,6 +2324,10 @@ void av1_read_mode_info(AV1Decoder *const pbi, MACROBLOCKD *xd,
MV_REF *frame_mvs = cm->cur_frame->mvs + mi_row * cm->mi_cols + mi_col; MV_REF *frame_mvs = cm->cur_frame->mvs + mi_row * cm->mi_cols + mi_col;
int w, h; int w, h;
#if CONFIG_INTRABC
mi->mbmi.use_intrabc = 0;
#endif // CONFIG_INTRABC
if (frame_is_intra_only(cm)) { if (frame_is_intra_only(cm)) {
read_intra_frame_mode_info(cm, xd, mi_row, mi_col, r); read_intra_frame_mode_info(cm, xd, mi_row, mi_col, r);
#if CONFIG_REF_MV #if CONFIG_REF_MV
......
...@@ -221,6 +221,9 @@ static void write_intra_mode_kf(const AV1_COMMON *cm, FRAME_CONTEXT *frame_ctx, ...@@ -221,6 +221,9 @@ static void write_intra_mode_kf(const AV1_COMMON *cm, FRAME_CONTEXT *frame_ctx,
const MODE_INFO *mi, const MODE_INFO *above_mi, const MODE_INFO *mi, const MODE_INFO *above_mi,
const MODE_INFO *left_mi, int block, const MODE_INFO *left_mi, int block,
PREDICTION_MODE mode, aom_writer *w) { PREDICTION_MODE mode, aom_writer *w) {
#if CONFIG_INTRABC
assert(!is_intrabc_block(&mi->mbmi));
#endif // CONFIG_INTRABC
#if CONFIG_EC_MULTISYMBOL #if CONFIG_EC_MULTISYMBOL
aom_write_symbol(w, av1_intra_mode_ind[mode], aom_write_symbol(w, av1_intra_mode_ind[mode],
get_y_mode_cdf(frame_ctx, mi, above_mi, left_mi, block), get_y_mode_cdf(frame_ctx, mi, above_mi, left_mi, block),
...@@ -2094,6 +2097,21 @@ static void write_mb_modes_kf(AV1_COMMON *cm, const MACROBLOCKD *xd, ...@@ -2094,6 +2097,21 @@ static void write_mb_modes_kf(AV1_COMMON *cm, const MACROBLOCKD *xd,
!xd->lossless[mbmi->segment_id]) !xd->lossless[mbmi->segment_id])
write_selected_tx_size(cm, xd, w); write_selected_tx_size(cm, xd, w);
#if CONFIG_INTRABC
if (bsize >= BLOCK_8X8 && cm->allow_screen_content_tools) {
int use_intrabc = is_intrabc_block(mbmi);
aom_write(w, use_intrabc, INTRABC_PROB);
if (use_intrabc) {
assert(mbmi->mode == DC_PRED);
assert(mbmi->uv_mode == DC_PRED);
int_mv dv_ref;
av1_find_ref_dv(&dv_ref, mi_row, mi_col);
av1_encode_dv(w, &mbmi->mv[0].as_mv, &dv_ref.as_mv, &ec_ctx->ndvc);
return;
}
}
#endif // CONFIG_INTRABC
if (bsize >= BLOCK_8X8 || unify_bsize) { if (bsize >= BLOCK_8X8 || unify_bsize) {
write_intra_mode_kf(cm, ec_ctx, mi, above_mi, left_mi, 0, mbmi->mode, w); write_intra_mode_kf(cm, ec_ctx, mi, above_mi, left_mi, 0, mbmi->mode, w);
} else { } else {
......
...@@ -5882,6 +5882,11 @@ static void encode_superblock(const AV1_COMP *const cpi, ThreadData *td, ...@@ -5882,6 +5882,11 @@ static void encode_superblock(const AV1_COMP *const cpi, ThreadData *td,
const int unify_bsize = 0; const int unify_bsize = 0;
const BLOCK_SIZE block_size = AOMMAX(bsize, BLOCK_8X8); const BLOCK_SIZE block_size = AOMMAX(bsize, BLOCK_8X8);
#endif #endif
#if CONFIG_INTRABC
// TODO(aconverse@google.com): Remove this when the non-synthetic encoder
// side intrabc is added
assert(IMPLIES(is_intrabc_block(mbmi), mbmi->skip));
#endif
#if CONFIG_PVQ #if CONFIG_PVQ
x->pvq_speed = 0; x->pvq_speed = 0;
...@@ -5964,7 +5969,11 @@ static void encode_superblock(const AV1_COMP *const cpi, ThreadData *td, ...@@ -5964,7 +5969,11 @@ static void encode_superblock(const AV1_COMP *const cpi, ThreadData *td,
set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
for (ref = 0; ref < 1 + is_compound; ++ref) { for (ref = 0; ref < 1 + is_compound; ++ref) {
YV12_BUFFER_CONFIG *cfg = get_ref_frame_buffer(cpi, mbmi->ref_frame[ref]); YV12_BUFFER_CONFIG *cfg = get_ref_frame_buffer(cpi, mbmi->ref_frame[ref]);
#if CONFIG_INTRABC
assert(IMPLIES(!is_intrabc_block(mbmi), cfg));
#else
assert(cfg != NULL); assert(cfg != NULL);
#endif // !CONFIG_INTRABC
av1_setup_pre_planes(xd, ref, cfg, mi_row, mi_col, av1_setup_pre_planes(xd, ref, cfg, mi_row, mi_col,
&xd->block_refs[ref]->sf); &xd->block_refs[ref]->sf);
} }
......
...@@ -278,6 +278,25 @@ void av1_encode_mv(AV1_COMP *cpi, aom_writer *w, const MV *mv, const MV *ref, ...@@ -278,6 +278,25 @@ void av1_encode_mv(AV1_COMP *cpi, aom_writer *w, const MV *mv, const MV *ref,
} }
} }
#if CONFIG_INTRABC
void av1_encode_dv(aom_writer *w, const MV *mv, const MV *ref,
nmv_context *mvctx) {
const MV diff = { mv->row - ref->row, mv->col - ref->col };
const MV_JOINT_TYPE j = av1_get_mv_joint(&diff);
#if CONFIG_EC_MULTISYMBOL
aom_write_symbol(w, j, mvctx->joint_cdf, MV_JOINTS);
#else
av1_write_token(w, av1_mv_joint_tree, mvctx->joints, &mv_joint_encodings[j]);
#endif
if (mv_joint_vertical(j))
encode_mv_component(w, diff.row, &mvctx->comps[0], 0);
if (mv_joint_horizontal(j))
encode_mv_component(w, diff.col, &mvctx->comps[1], 0);
}
#endif // CONFIG_INTRABC
void av1_build_nmv_cost_table(int *mvjoint, int *mvcost[2], void av1_build_nmv_cost_table(int *mvjoint, int *mvcost[2],
const nmv_context *ctx, int usehp) { const nmv_context *ctx, int usehp) {
av1_cost_tokens(mvjoint, ctx->joints, av1_mv_joint_tree); av1_cost_tokens(mvjoint, ctx->joints, av1_mv_joint_tree);
......
...@@ -31,6 +31,11 @@ void av1_build_nmv_cost_table(int *mvjoint, int *mvcost[2], ...@@ -31,6 +31,11 @@ void av1_build_nmv_cost_table(int *mvjoint, int *mvcost[2],
void av1_update_mv_count(ThreadData *td); void av1_update_mv_count(ThreadData *td);
#if CONFIG_INTRABC
void av1_encode_dv(aom_writer *w, const MV *mv, const MV *ref,
nmv_context *mvctx);
#endif // CONFIG_INTRABC
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif
......
...@@ -9166,6 +9166,39 @@ static int64_t handle_inter_mode( ...@@ -9166,6 +9166,39 @@ static int64_t handle_inter_mode(
return 0; // The rate-distortion cost will be re-calculated by caller. return 0; // The rate-distortion cost will be re-calculated by caller.
} }
#if CONFIG_INTRABC
// This is a dummy function that forces intrabc on for testing purposes
// TODO(aconverse@google.com): Implement a real intrabc search
static int64_t rd_pick_intrabc_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x,
RD_COST *rd_cost, BLOCK_SIZE bsize,
int64_t best_rd) {
MACROBLOCKD *const xd = &x->e_mbd;
(void)best_rd;
if (bsize >= BLOCK_8X8 && cpi->common.allow_screen_content_tools) {
if (xd->mb_to_top_edge == -MAX_SB_SIZE * 8) {
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
mbmi->use_intrabc = 1;
mbmi->mode = DC_PRED;
mbmi->uv_mode = DC_PRED;
mbmi->mv[0].as_mv.row = -MAX_SB_SIZE * 8;
mbmi->mv[0].as_mv.col = 0;
mbmi->interp_filter = BILINEAR;
mbmi->skip = 1;
x->skip = 1;
const int mi_row = -xd->mb_to_top_edge / (8 * MI_SIZE);
const int mi_col = -xd->mb_to_left_edge / (8 * MI_SIZE);
av1_build_inter_predictors_sb(xd, mi_row, mi_col, NULL, bsize);
rd_cost->rate = 1;
rd_cost->dist = 0;
rd_cost->rdcost =
RDCOST(x->rdmult, x->rddiv, rd_cost->rate, rd_cost->dist);
return rd_cost->rdcost;
}
}
return INT64_MAX;
}
#endif // CONFIG_INTRABC
void av1_rd_pick_intra_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, void av1_rd_pick_intra_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x,
RD_COST *rd_cost, BLOCK_SIZE bsize, RD_COST *rd_cost, BLOCK_SIZE bsize,
PICK_MODE_CONTEXT *ctx, int64_t best_rd) { PICK_MODE_CONTEXT *ctx, int64_t best_rd) {
...@@ -9181,6 +9214,9 @@ void av1_rd_pick_intra_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, ...@@ -9181,6 +9214,9 @@ void av1_rd_pick_intra_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x,
ctx->skip = 0; ctx->skip = 0;
xd->mi[0]->mbmi.ref_frame[0] = INTRA_FRAME; xd->mi[0]->mbmi.ref_frame[0] = INTRA_FRAME;
xd->mi[0]->mbmi.ref_frame[1] = NONE_FRAME; xd->mi[0]->mbmi.ref_frame[1] = NONE_FRAME;
#if CONFIG_INTRABC
xd->mi[0]->mbmi.use_intrabc = 0;
#endif // CONFIG_INTRABC
if (bsize >= BLOCK_8X8 || unify_bsize) { if (bsize >= BLOCK_8X8 || unify_bsize) {
if (rd_pick_intra_sby_mode(cpi, x, &rate_y, &rate_y_tokenonly, &dist_y, if (rd_pick_intra_sby_mode(cpi, x, &rate_y, &rate_y_tokenonly, &dist_y,
...@@ -9220,6 +9256,12 @@ void av1_rd_pick_intra_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, ...@@ -9220,6 +9256,12 @@ void av1_rd_pick_intra_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x,
rd_cost->dist = dist_y + dist_uv; rd_cost->dist = dist_y + dist_uv;
} }
#if CONFIG_INTRABC
if (rd_pick_intrabc_mode_sb(cpi, x, rd_cost, bsize, best_rd) < best_rd) {
ctx->skip = x->skip; // FIXME where is the proper place to set this?!
}
#endif
ctx->mic = *xd->mi[0]; ctx->mic = *xd->mi[0];
ctx->mbmi_ext = *x->mbmi_ext; ctx->mbmi_ext = *x->mbmi_ext;
rd_cost->rdcost = RDCOST(x->rdmult, x->rddiv, rd_cost->rate, rd_cost->dist); rd_cost->rdcost = RDCOST(x->rdmult, x->rddiv, rd_cost->rate, rd_cost->dist);
......
/*
* Copyright (c) 2017, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
#include "./aom_config.h"
#include "av1/common/enums.h"
#include "av1/common/mv.h"
#include "av1/common/mvref_common.h"
#include "av1/common/tile_common.h"
namespace {
TEST(IntrabcTest, DvValidation) {
struct DvTestCase {