int in_use;
} PRED_BUFFER;
-static int mv_refs_rt(const VP9_COMMON *cm, const MACROBLOCK *x,
+static int mv_refs_rt(VP9_COMP *cpi, const VP9_COMMON *cm,
+ const MACROBLOCK *x,
const MACROBLOCKD *xd,
const TileInfo *const tile,
MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
- int_mv *mv_ref_list,
- int mi_row, int mi_col) {
+ int_mv *mv_ref_list, int_mv *base_mv,
+ int mi_row, int mi_col, int use_base_mv) {
const int *ref_sign_bias = cm->ref_frame_sign_bias;
int i, refmv_count = 0;
}
}
}
+ if (use_base_mv &&
+ !cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame &&
+ ref_frame == LAST_FRAME) {
+ // Get base layer mv.
+ MV_REF *candidate =
+ &cm->prev_frame->mvs[(mi_col>>1) + (mi_row>>1) * (cm->mi_cols>>1)];
+ if (candidate->mv[0].as_int != INVALID_MV) {
+ base_mv->as_mv.row = (candidate->mv[0].as_mv.row << 1);
+ base_mv->as_mv.col = (candidate->mv[0].as_mv.col << 1);
+ clamp_mv_ref(&base_mv->as_mv, xd);
+ } else {
+ base_mv->as_int = INVALID_MV;
+ }
+ }
Done:
static int combined_motion_search(VP9_COMP *cpi, MACROBLOCK *x,
BLOCK_SIZE bsize, int mi_row, int mi_col,
int_mv *tmp_mv, int *rate_mv,
- int64_t best_rd_sofar) {
+ int64_t best_rd_sofar, int use_base_mv) {
MACROBLOCKD *xd = &x->e_mbd;
MODE_INFO *mi = xd->mi[0];
struct buf_2d backup_yv12[MAX_MB_PLANE] = {{0, 0}};
MV mvp_full;
const int ref = mi->ref_frame[0];
const MV ref_mv = x->mbmi_ext->ref_mvs[ref][0].as_mv;
+ MV center_mv;
int dis;
int rate_mode;
const int tmp_col_min = x->mv_col_min;
mvp_full.col >>= 3;
mvp_full.row >>= 3;
+ if (!use_base_mv)
+ center_mv = ref_mv;
+ else
+ center_mv = tmp_mv->as_mv;
+
vp9_full_pixel_search(cpi, x, bsize, &mvp_full, step_param, sadpb,
cond_cost_list(cpi, cost_list),
- &ref_mv, &tmp_mv->as_mv, INT_MAX, 0);
+ ¢er_mv, &tmp_mv->as_mv, INT_MAX, 0);
x->mv_col_min = tmp_col_min;
x->mv_col_max = tmp_col_max;
cm->base_qindex, cm->y_dc_delta_q, cm->bit_depth) >> reduction_fac;
}
+static INLINE void find_predictors(VP9_COMP *cpi, MACROBLOCK *x,
+ MV_REFERENCE_FRAME ref_frame,
+ int_mv frame_mv[MB_MODE_COUNT][MAX_REF_FRAMES],
+ int const_motion[MAX_REF_FRAMES],
+ int *ref_frame_skip_mask,
+ const int flag_list[4],
+ TileDataEnc *tile_data,
+ int mi_row, int mi_col,
+ struct buf_2d yv12_mb[4][MAX_MB_PLANE],
+ BLOCK_SIZE bsize) {
+ VP9_COMMON *const cm = &cpi->common;
+ MACROBLOCKD *const xd = &x->e_mbd;
+ const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, ref_frame);
+ TileInfo *const tile_info = &tile_data->tile_info;
// TODO(jingning) placeholder for inter-frame non-RD mode decision.
+ x->pred_mv_sad[ref_frame] = INT_MAX;
+ frame_mv[NEWMV][ref_frame].as_int = INVALID_MV;
+ frame_mv[ZEROMV][ref_frame].as_int = 0;
// this needs various further optimizations. to be continued..
+ if ((cpi->ref_frame_flags & flag_list[ref_frame]) && (yv12 != NULL)) {
+ int_mv *const candidates = x->mbmi_ext->ref_mvs[ref_frame];
+ const struct scale_factors *const sf = &cm->frame_refs[ref_frame - 1].sf;
+ vp9_setup_pred_block(xd, yv12_mb[ref_frame], yv12, mi_row, mi_col,
+ sf, sf);
+ if (cm->use_prev_frame_mvs)
+ vp9_find_mv_refs(cm, xd, xd->mi[0], ref_frame,
+ candidates, mi_row, mi_col,
+ x->mbmi_ext->mode_context);
+ else
+ const_motion[ref_frame] =
+ mv_refs_rt(cpi, cm, x, xd, tile_info, xd->mi[0], ref_frame,
+ candidates, &frame_mv[NEWMV][ref_frame], mi_row, mi_col,
+ (int)(cpi->svc.use_base_mv && cpi->svc.spatial_layer_id));
+ vp9_find_best_ref_mvs(xd, cm->allow_high_precision_mv, candidates,
+ &frame_mv[NEARESTMV][ref_frame],
+ &frame_mv[NEARMV][ref_frame]);
+ if (!vp9_is_scaled(sf) && bsize >= BLOCK_8X8) {
+ vp9_mv_pred(cpi, x, yv12_mb[ref_frame][0].buf, yv12->y_stride,
+ ref_frame, bsize);
+ }
+ } else {
+ *ref_frame_skip_mask |= (1 << ref_frame);
+ }
+}
void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
TileDataEnc *tile_data,
int mi_row, int mi_col, RD_COST *rd_cost,
VP9_COMMON *const cm = &cpi->common;
SPEED_FEATURES *const sf = &cpi->sf;
const SVC *const svc = &cpi->svc;
- TileInfo *const tile_info = &tile_data->tile_info;
MACROBLOCKD *const xd = &x->e_mbd;
MODE_INFO *const mi = xd->mi[0];
struct macroblockd_plane *const pd = &xd->plane[0];
unsigned int var_y = UINT_MAX;
unsigned int sse_y = UINT_MAX;
const int intra_cost_penalty = set_intra_cost_penalty(cpi, bsize);
- const int64_t inter_mode_thresh = RDCOST(x->rdmult, x->rddiv,
+ int64_t inter_mode_thresh = RDCOST(x->rdmult, x->rddiv,
intra_cost_penalty, 0);
const int *const rd_threshes = cpi->rd.threshes[mi->segment_id][bsize];
const int *const rd_thresh_freq_fact = tile_data->thresh_freq_fact[bsize];
int best_early_term = 0;
int ref_frame_cost[MAX_REF_FRAMES];
int svc_force_zero_mode[3] = {0};
+ int perform_intra_pred = 1;
#if CONFIG_VP9_TEMPORAL_DENOISING
int64_t zero_last_cost_orig = INT64_MAX;
#endif
}
for (ref_frame = LAST_FRAME; ref_frame <= usable_ref_frame; ++ref_frame) {
- const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, ref_frame);
-
- x->pred_mv_sad[ref_frame] = INT_MAX;
- frame_mv[NEWMV][ref_frame].as_int = INVALID_MV;
- frame_mv[ZEROMV][ref_frame].as_int = 0;
-
- if ((cpi->ref_frame_flags & flag_list[ref_frame]) && (yv12 != NULL)) {
- int_mv *const candidates = x->mbmi_ext->ref_mvs[ref_frame];
- const struct scale_factors *const sf = &cm->frame_refs[ref_frame - 1].sf;
-
- vp9_setup_pred_block(xd, yv12_mb[ref_frame], yv12, mi_row, mi_col,
- sf, sf);
-
- if (cm->use_prev_frame_mvs)
- vp9_find_mv_refs(cm, xd, xd->mi[0], ref_frame,
- candidates, mi_row, mi_col, x->mbmi_ext->mode_context);
- else
- const_motion[ref_frame] = mv_refs_rt(cm, x, xd, tile_info,
- xd->mi[0],
- ref_frame, candidates,
- mi_row, mi_col);
-
- vp9_find_best_ref_mvs(xd, cm->allow_high_precision_mv, candidates,
- &frame_mv[NEARESTMV][ref_frame],
- &frame_mv[NEARMV][ref_frame]);
-
- if (!vp9_is_scaled(sf) && bsize >= BLOCK_8X8)
- vp9_mv_pred(cpi, x, yv12_mb[ref_frame][0].buf, yv12->y_stride,
- ref_frame, bsize);
- } else {
- ref_frame_skip_mask |= (1 << ref_frame);
- }
+ find_predictors(cpi, x, ref_frame, frame_mv, const_motion,
+ &ref_frame_skip_mask, flag_list, tile_data, mi_row, mi_col,
+ yv12_mb, bsize);
}
for (idx = 0; idx < RT_INTER_MODES; ++idx) {
cond_cost_list(cpi, cost_list),
x->nmvjointcost, x->mvcost, &dis,
&x->pred_sse[ref_frame], NULL, 0, 0);
+ } else if (svc->use_base_mv && svc->spatial_layer_id) {
+ if (frame_mv[NEWMV][ref_frame].as_int != INVALID_MV &&
+ frame_mv[NEWMV][ref_frame].as_int != 0) {
+ const int pre_stride = xd->plane[0].pre[0].stride;
+ int base_mv_sad = INT_MAX;
+ const uint8_t * const pre_buf = xd->plane[0].pre[0].buf +
+ (frame_mv[NEWMV][ref_frame].as_mv.row >> 3) * pre_stride +
+ (frame_mv[NEWMV][ref_frame].as_mv.col >> 3);
+ base_mv_sad = cpi->fn_ptr[bsize].sdf(x->plane[0].src.buf,
+ x->plane[0].src.stride,
+ pre_buf, pre_stride);
+
+ // TODO(wonkap): make the decision to use base layer mv on RD;
+ // not just SAD.
+ if (base_mv_sad < x->pred_mv_sad[ref_frame]) {
+ // Base layer mv is good.
+ if (!combined_motion_search(cpi, x, bsize, mi_row, mi_col,
+ &frame_mv[NEWMV][ref_frame], &rate_mv, best_rdc.rdcost, 1)) {
+ continue;
+ }
+ } else if (!combined_motion_search(cpi, x, bsize, mi_row, mi_col,
+ &frame_mv[NEWMV][ref_frame], &rate_mv, best_rdc.rdcost, 0)) {
+ continue;
+ }
+ } else if (!combined_motion_search(cpi, x, bsize, mi_row, mi_col,
+ &frame_mv[NEWMV][ref_frame], &rate_mv, best_rdc.rdcost, 0)) {
+ continue;
+ }
} else if (!combined_motion_search(cpi, x, bsize, mi_row, mi_col,
- &frame_mv[NEWMV][ref_frame], &rate_mv, best_rdc.rdcost)) {
+ &frame_mv[NEWMV][ref_frame], &rate_mv, best_rdc.rdcost, 0)) {
continue;
}
}
xd->mi[0]->bmi[0].as_mv[0].as_int = mi->mv[0].as_int;
x->skip_txfm[0] = best_mode_skip_txfm;
+ // Perform intra prediction only if base layer is chosen as the reference.
+ if (cpi->svc.spatial_layer_id) {
+ perform_intra_pred =
+ cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame ||
+ (!cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame
+ && svc_force_zero_mode[best_ref_frame]);
+ inter_mode_thresh = (inter_mode_thresh << 1) + inter_mode_thresh;
+ }
// Perform intra prediction search, if the best SAD is above a certain
// threshold.
- if (best_rdc.rdcost == INT64_MAX ||
+ if (perform_intra_pred &&
+ ((best_rdc.rdcost == INT64_MAX ||
(!x->skip && best_rdc.rdcost > inter_mode_thresh &&
- bsize <= cpi->sf.max_intra_bsize)) {
+ bsize <= cpi->sf.max_intra_bsize)))) {
struct estimate_block_intra_args args = { cpi, x, DC_PRED, 0, 0 };
int i;
TX_SIZE best_intra_tx_size = TX_SIZES;
svc->first_spatial_layer_to_encode = 0;
svc->rc_drop_superframe = 0;
svc->force_zero_mode_spatial_ref = 0;
+ svc->use_base_mv = 0;
svc->current_superframe = 0;
for (i = 0; i < REF_FRAMES; ++i)
svc->ref_frame_index[i] = -1;
cpi->ref_frame_flags = VP9_LAST_FLAG;
} else if (cpi->svc.layer_context[temporal_id].is_key_frame) {
// base layer is a key frame.
- cpi->ref_frame_flags = VP9_GOLD_FLAG;
+ cpi->ref_frame_flags = VP9_LAST_FLAG;
+ cpi->ext_refresh_last_frame = 0;
+ cpi->ext_refresh_golden_frame = 1;
} else {
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
} else {
if (frame_num_within_temporal_struct == 1) {
// the first tl2 picture
- if (!spatial_id) {
+ if (spatial_id == cpi->svc.number_spatial_layers - 1) { // top layer
+ cpi->ext_refresh_frame_flags_pending = 1;
+ if (!spatial_id)
+ cpi->ref_frame_flags = VP9_LAST_FLAG;
+ else
+ cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
+ } else if (!spatial_id) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ext_refresh_alt_ref_frame = 1;
cpi->ref_frame_flags = VP9_LAST_FLAG;
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ext_refresh_alt_ref_frame = 1;
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
- } else { // Top layer
- cpi->ext_refresh_frame_flags_pending = 0;
- cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
} else {
// The second tl2 picture
- if (!spatial_id) {
+ if (spatial_id == cpi->svc.number_spatial_layers - 1) { // top layer
cpi->ext_refresh_frame_flags_pending = 1;
+ if (!spatial_id)
cpi->ref_frame_flags = VP9_LAST_FLAG;
- cpi->ext_refresh_last_frame = 1;
- } else if (spatial_id < cpi->svc.number_spatial_layers - 1) {
+ else
+ cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
+ } else if (!spatial_id) {
cpi->ext_refresh_frame_flags_pending = 1;
- cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
- cpi->ext_refresh_last_frame = 1;
+ cpi->ref_frame_flags = VP9_LAST_FLAG;
+ cpi->ext_refresh_alt_ref_frame = 1;
} else { // top layer
- cpi->ext_refresh_frame_flags_pending = 0;
+ cpi->ext_refresh_frame_flags_pending = 1;
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
+ cpi->ext_refresh_alt_ref_frame = 1;
}
}
}
if (temporal_id == 0) {
cpi->lst_fb_idx = spatial_id;
- if (spatial_id)
+ if (spatial_id) {
+ if (cpi->svc.layer_context[temporal_id].is_key_frame) {
+ cpi->lst_fb_idx = spatial_id - 1;
+ cpi->gld_fb_idx = spatial_id;
+ } else {
cpi->gld_fb_idx = spatial_id - 1;
- else
+ }
+ } else {
cpi->gld_fb_idx = 0;
+ }
cpi->alt_fb_idx = 0;
} else if (temporal_id == 1) {
cpi->lst_fb_idx = spatial_id;
} else {
cpi->lst_fb_idx = cpi->svc.number_spatial_layers + spatial_id;
cpi->gld_fb_idx = cpi->svc.number_spatial_layers + spatial_id - 1;
- cpi->alt_fb_idx = 0;
+ cpi->alt_fb_idx = cpi->svc.number_spatial_layers + spatial_id;
}
}
cpi->ref_frame_flags = VP9_LAST_FLAG;
} else if (cpi->svc.layer_context[temporal_id].is_key_frame) {
// base layer is a key frame.
- cpi->ref_frame_flags = VP9_GOLD_FLAG;
+ cpi->ref_frame_flags = VP9_LAST_FLAG;
+ cpi->ext_refresh_last_frame = 0;
+ cpi->ext_refresh_golden_frame = 1;
} else {
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
if (temporal_id == 0) {
cpi->lst_fb_idx = spatial_id;
- if (spatial_id)
+ if (spatial_id) {
+ if (cpi->svc.layer_context[temporal_id].is_key_frame) {
+ cpi->lst_fb_idx = spatial_id - 1;
+ cpi->gld_fb_idx = spatial_id;
+ } else {
cpi->gld_fb_idx = spatial_id - 1;
- else
+ }
+ } else {
cpi->gld_fb_idx = 0;
+ }
cpi->alt_fb_idx = 0;
} else if (temporal_id == 1) {
cpi->lst_fb_idx = spatial_id;
if (!spatial_id) {
cpi->ref_frame_flags = VP9_LAST_FLAG;
} else if (cpi->svc.layer_context[0].is_key_frame) {
- cpi->ref_frame_flags = VP9_GOLD_FLAG;
+ cpi->ref_frame_flags = VP9_LAST_FLAG;
+ cpi->ext_refresh_last_frame = 0;
+ cpi->ext_refresh_golden_frame = 1;
} else {
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
cpi->lst_fb_idx = spatial_id;
- if (spatial_id)
+ if (spatial_id) {
+ if (cpi->svc.layer_context[0].is_key_frame) {
+ cpi->lst_fb_idx = spatial_id - 1;
+ cpi->gld_fb_idx = spatial_id;
+ } else {
cpi->gld_fb_idx = spatial_id - 1;
- else
+ }
+ } else {
cpi->gld_fb_idx = 0;
+ }
}
int vp9_one_pass_cbr_svc_start_layer(VP9_COMP *const cpi) {
int width = 0, height = 0;
LAYER_CONTEXT *lc = NULL;
+ if (cpi->svc.number_spatial_layers > 1)
+ cpi->svc.use_base_mv = 1;
cpi->svc.force_zero_mode_spatial_ref = 1;
if (cpi->svc.temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_0212) {