Newer
Older
1, &dummy_rate, &dummy_dist, cpi->pc_root);
case VAR_BASED_FIXED_PARTITION:
case FIXED_PARTITION:
bsize = cpi->sf.partition_search_type == FIXED_PARTITION ?
cpi->sf.always_this_block_size :
get_nonrd_var_based_fixed_partition(cpi, mi_row, mi_col);
set_fixed_partitioning(cpi, tile, mi, mi_row, mi_col, bsize);
nonrd_use_partition(cpi, tile, mi, tp, mi_row, mi_col, BLOCK_64X64,
1, &dummy_rate, &dummy_dist, cpi->pc_root);
if (cpi->sf.partition_check ||
!is_background(cpi, tile, mi_row, mi_col)) {
set_modeinfo_offsets(cm, xd, mi_row, mi_col);
auto_partition_range(cpi, tile, mi_row, mi_col,
&cpi->sf.min_partition_size,
&cpi->sf.max_partition_size);
nonrd_pick_partition(cpi, tile, tp, mi_row, mi_col, BLOCK_64X64,
&dummy_rate, &dummy_dist, 1, INT64_MAX,
copy_partitioning(cm, mi, prev_mi);
nonrd_use_partition(cpi, tile, mi, tp, mi_row, mi_col,
BLOCK_64X64, 1, &dummy_rate, &dummy_dist,
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
static int set_var_thresh_from_histogram(VP9_COMP *cpi) {
SPEED_FEATURES *const sf = &cpi->sf;
VP9_COMMON *const cm = &cpi->common;
const uint8_t *src = cpi->Source->y_buffer;
const uint8_t *last_src = cpi->Last_Source->y_buffer;
const int src_stride = cpi->Source->y_stride;
const int last_stride = cpi->Last_Source->y_stride;
// Pick cutoff threshold
const int cutoff = (MIN(cm->width, cm->height) >= 720) ?
(cm->MBs * VAR_HIST_LARGE_CUT_OFF / 100) :
(cm->MBs * VAR_HIST_SMALL_CUT_OFF / 100);
DECLARE_ALIGNED_ARRAY(16, int, hist, VAR_HIST_BINS);
diff *var16 = cpi->source_diff_var;
int sum = 0;
int i, j;
vpx_memset(hist, 0, VAR_HIST_BINS * sizeof(hist[0]));
for (i = 0; i < cm->mb_rows; i++) {
for (j = 0; j < cm->mb_cols; j++) {
vp9_get16x16var(src, src_stride, last_src, last_stride,
&var16->sse, &var16->sum);
var16->var = var16->sse -
(((uint32_t)var16->sum * var16->sum) >> 8);
if (var16->var >= VAR_HIST_MAX_BG_VAR)
hist[VAR_HIST_BINS - 1]++;
else
hist[var16->var / VAR_HIST_FACTOR]++;
src += 16;
last_src += 16;
var16++;
}
src = src - cm->mb_cols * 16 + 16 * src_stride;
last_src = last_src - cm->mb_cols * 16 + 16 * last_stride;
}
cpi->source_var_thresh = 0;
if (hist[VAR_HIST_BINS - 1] < cutoff) {
for (i = 0; i < VAR_HIST_BINS - 1; i++) {
sum += hist[i];
if (sum > cutoff) {
cpi->source_var_thresh = (i + 1) * VAR_HIST_FACTOR;
return 0;
}
}
}
return sf->search_type_check_frequency;
}
static void source_var_based_partition_search_method(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
SPEED_FEATURES *const sf = &cpi->sf;
if (cm->frame_type == KEY_FRAME) {
// For key frame, use SEARCH_PARTITION.
sf->partition_search_type = SEARCH_PARTITION;
} else if (cm->intra_only) {
sf->partition_search_type = FIXED_PARTITION;
} else {
if (cm->last_width != cm->width || cm->last_height != cm->height) {
if (cpi->source_diff_var)
vpx_free(cpi->source_diff_var);
CHECK_MEM_ERROR(cm, cpi->source_diff_var,
vpx_calloc(cm->MBs, sizeof(diff)));
}
if (!cpi->frames_till_next_var_check)
cpi->frames_till_next_var_check = set_var_thresh_from_histogram(cpi);
if (cpi->frames_till_next_var_check > 0) {
sf->partition_search_type = FIXED_PARTITION;
cpi->frames_till_next_var_check--;
}
}
}
static int get_skip_encode_frame(const VP9_COMMON *cm) {
unsigned int intra_count = 0, inter_count = 0;
int j;
for (j = 0; j < INTRA_INTER_CONTEXTS; ++j) {
intra_count += cm->counts.intra_inter[j][0];
inter_count += cm->counts.intra_inter[j][1];
}
return (intra_count << 2) < inter_count &&
cm->frame_type != KEY_FRAME &&
cm->show_frame;
}
static void encode_tiles(VP9_COMP *cpi) {
const VP9_COMMON *const cm = &cpi->common;
const int tile_cols = 1 << cm->log2_tile_cols;
const int tile_rows = 1 << cm->log2_tile_rows;
int tile_col, tile_row;
TOKENEXTRA *tok = cpi->tok;
for (tile_row = 0; tile_row < tile_rows; ++tile_row) {
for (tile_col = 0; tile_col < tile_cols; ++tile_col) {
TileInfo tile;
TOKENEXTRA *old_tok = tok;
int mi_row;
vp9_tile_init(&tile, cm, tile_row, tile_col);
for (mi_row = tile.mi_row_start; mi_row < tile.mi_row_end;
mi_row += MI_BLOCK_SIZE) {
if (cpi->sf.use_nonrd_pick_mode && !frame_is_intra_only(cm))
encode_nonrd_sb_row(cpi, &tile, mi_row, &tok);
else
encode_rd_sb_row(cpi, &tile, mi_row, &tok);
}
cpi->tok_count[tile_row][tile_col] = (unsigned int)(tok - old_tok);
assert(tok - cpi->tok <= get_token_alloc(cm->mb_rows, cm->mb_cols));
}
}
}
#if CONFIG_FP_MB_STATS
static int input_fpmb_stats(FIRSTPASS_MB_STATS *firstpass_mb_stats,
VP9_COMMON *cm, uint8_t **this_frame_mb_stats) {
uint8_t *mb_stats_in = firstpass_mb_stats->mb_stats_start +
cm->current_video_frame * cm->MBs * sizeof(uint8_t);
if (mb_stats_in > firstpass_mb_stats->mb_stats_end)
return EOF;
*this_frame_mb_stats = mb_stats_in;
return 1;
}
#endif
static void encode_frame_internal(VP9_COMP *cpi) {
SPEED_FEATURES *const sf = &cpi->sf;
MACROBLOCK *const x = &cpi->mb;
VP9_COMMON *const cm = &cpi->common;
MACROBLOCKD *const xd = &x->e_mbd;
xd->mi = cm->mi_grid_visible;
xd->mi[0] = cm->mi;
vp9_zero(cm->counts);
vp9_zero(cpi->tx_stepdown_count);
vp9_zero(rd_opt->comp_pred_diff);
vp9_zero(rd_opt->filter_diff);
vp9_zero(rd_opt->tx_select_diff);
vp9_zero(rd_opt->tx_select_threshes);
cpi->mb.e_mbd.lossless = cm->base_qindex == 0 &&
cm->y_dc_delta_q == 0 &&
cm->uv_dc_delta_q == 0 &&
cm->uv_ac_delta_q == 0;
cm->tx_mode = select_tx_mode(cpi);
cpi->mb.fwd_txm4x4 = cpi->mb.e_mbd.lossless ? vp9_fwht4x4 : vp9_fdct4x4;
cpi->mb.itxm_add = cpi->mb.e_mbd.lossless ? vp9_iwht4x4_add : vp9_idct4x4_add;
if (cpi->mb.e_mbd.lossless) {
cpi->mb.optimize = 0;
cpi->common.lf.filter_level = 0;
cpi->zbin_mode_boost_enabled = 0;
}
vp9_frame_init_quantizer(cpi);
vp9_initialize_rd_consts(cpi);
vp9_initialize_me_consts(cpi, cm->base_qindex);
init_encode_frame_mb_context(cpi);
vp9_zero(x->skip_txfm);
// Initialize internal buffer pointers for rtc coding, where non-RD
// mode decision is used and hence no buffer pointer swap needed.
int i;
struct macroblock_plane *const p = x->plane;
struct macroblockd_plane *const pd = xd->plane;
PICK_MODE_CONTEXT *ctx = &cpi->pc_root->none;
for (i = 0; i < MAX_MB_PLANE; ++i) {
p[i].coeff = ctx->coeff_pbuf[i][0];
p[i].qcoeff = ctx->qcoeff_pbuf[i][0];
pd[i].dqcoeff = ctx->dqcoeff_pbuf[i][0];
p[i].eobs = ctx->eobs_pbuf[i][0];
}
vp9_zero(x->zcoeff_blk);
if (sf->partition_search_type == SOURCE_VAR_BASED_PARTITION)
source_var_based_partition_search_method(cpi);
{
struct vpx_usec_timer emr_timer;
vpx_usec_timer_start(&emr_timer);
#if CONFIG_FP_MB_STATS
if (cpi->use_fp_mb_stats) {
input_fpmb_stats(&cpi->twopass.firstpass_mb_stats, cm,
&cpi->twopass.this_frame_mb_stats);
}
#endif
vpx_usec_timer_mark(&emr_timer);
cpi->time_encode_sb_row += vpx_usec_timer_elapsed(&emr_timer);
}
sf->skip_encode_frame = sf->skip_encode_sb ? get_skip_encode_frame(cm) : 0;
#if 0
// Keep record of the total distortion this time around for future use
cpi->last_frame_distortion = cpi->frame_distortion;
#endif
}
static INTERP_FILTER get_interp_filter(
const int64_t threshes[SWITCHABLE_FILTER_CONTEXTS], int is_alt_ref) {
if (!is_alt_ref &&
threshes[EIGHTTAP_SMOOTH] > threshes[EIGHTTAP] &&
threshes[EIGHTTAP_SMOOTH] > threshes[EIGHTTAP_SHARP] &&
threshes[EIGHTTAP_SMOOTH] > threshes[SWITCHABLE - 1]) {
return EIGHTTAP_SMOOTH;
} else if (threshes[EIGHTTAP_SHARP] > threshes[EIGHTTAP] &&
threshes[EIGHTTAP_SHARP] > threshes[SWITCHABLE - 1]) {
return EIGHTTAP_SHARP;
} else if (threshes[EIGHTTAP] > threshes[SWITCHABLE - 1]) {
return EIGHTTAP;
} else {
return SWITCHABLE;
}
}
void vp9_encode_frame(VP9_COMP *cpi) {
// In the longer term the encoder should be generalized to match the
// decoder such that we allow compound where one of the 3 buffers has a
// different sign bias and that buffer is then the fixed ref. However, this
// requires further work in the rd loop. For now the only supported encoder
// side behavior is where the ALT ref buffer has opposite sign bias to
if (!frame_is_intra_only(cm)) {
if ((cm->ref_frame_sign_bias[ALTREF_FRAME] ==
cm->ref_frame_sign_bias[GOLDEN_FRAME]) ||
(cm->ref_frame_sign_bias[ALTREF_FRAME] ==
cm->ref_frame_sign_bias[LAST_FRAME])) {
cm->allow_comp_inter_inter = 0;
} else {
cm->allow_comp_inter_inter = 1;
cm->comp_fixed_ref = ALTREF_FRAME;
cm->comp_var_ref[0] = LAST_FRAME;
cm->comp_var_ref[1] = GOLDEN_FRAME;
}
if (cpi->sf.frame_parameter_update) {
// This code does a single RD pass over the whole frame assuming
// either compound, single or hybrid prediction as per whatever has
// worked best for that type of frame in the past.
// It also predicts whether another coding mode would have worked
// better that this coding mode. If that is the case, it remembers
// that for subsequent frames.
// It does the same analysis for transform size selection also.
const MV_REFERENCE_FRAME frame_type = get_frame_type(cpi);
int64_t *const mode_thrs = rd_opt->prediction_type_threshes[frame_type];
int64_t *const filter_thrs = rd_opt->filter_threshes[frame_type];
int *const tx_thrs = rd_opt->tx_select_threshes[frame_type];
const int is_alt_ref = frame_type == ALTREF_FRAME;
/* prediction (compound, single or hybrid) mode selection */
if (is_alt_ref || !cm->allow_comp_inter_inter)
cm->reference_mode = SINGLE_REFERENCE;
else if (mode_thrs[COMPOUND_REFERENCE] > mode_thrs[SINGLE_REFERENCE] &&
mode_thrs[COMPOUND_REFERENCE] >
mode_thrs[REFERENCE_MODE_SELECT] &&
check_dual_ref_flags(cpi) &&
cpi->static_mb_pct == 100)
cm->reference_mode = COMPOUND_REFERENCE;
else if (mode_thrs[SINGLE_REFERENCE] > mode_thrs[REFERENCE_MODE_SELECT])
cm->reference_mode = SINGLE_REFERENCE;
cm->reference_mode = REFERENCE_MODE_SELECT;
if (cm->interp_filter == SWITCHABLE)
cm->interp_filter = get_interp_filter(filter_thrs, is_alt_ref);
encode_frame_internal(cpi);
for (i = 0; i < REFERENCE_MODES; ++i)
mode_thrs[i] = (mode_thrs[i] + rd_opt->comp_pred_diff[i] / cm->MBs) / 2;
for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i)
filter_thrs[i] = (filter_thrs[i] + rd_opt->filter_diff[i] / cm->MBs) / 2;
for (i = 0; i < TX_MODES; ++i) {
pd -= RDCOST(cpi->mb.rdmult, cpi->mb.rddiv, 2048 * (TX_SIZES - 1), 0);
tx_thrs[i] = (tx_thrs[i] + (int)(pd / cm->MBs)) / 2;
if (cm->reference_mode == REFERENCE_MODE_SELECT) {
int single_count_zero = 0;
int comp_count_zero = 0;
for (i = 0; i < COMP_INTER_CONTEXTS; i++) {
single_count_zero += cm->counts.comp_inter[i][0];
comp_count_zero += cm->counts.comp_inter[i][1];
int count4x4 = 0;
int count8x8_lp = 0, count8x8_8x8p = 0;
int count16x16_16x16p = 0, count16x16_lp = 0;
int count32x32 = 0;
for (i = 0; i < TX_SIZE_CONTEXTS; ++i) {
count4x4 += cm->counts.tx.p32x32[i][TX_4X4];
count4x4 += cm->counts.tx.p16x16[i][TX_4X4];
count4x4 += cm->counts.tx.p8x8[i][TX_4X4];
count8x8_lp += cm->counts.tx.p32x32[i][TX_8X8];
count8x8_lp += cm->counts.tx.p16x16[i][TX_8X8];
count8x8_8x8p += cm->counts.tx.p8x8[i][TX_8X8];
count16x16_16x16p += cm->counts.tx.p16x16[i][TX_16X16];
count16x16_lp += cm->counts.tx.p32x32[i][TX_16X16];
count32x32 += cm->counts.tx.p32x32[i][TX_32X32];
if (count4x4 == 0 && count16x16_lp == 0 && count16x16_16x16p == 0 &&
count32x32 == 0) {
cm->tx_mode = ALLOW_8X8;
} else if (count8x8_8x8p == 0 && count16x16_16x16p == 0 &&
count8x8_lp == 0 && count16x16_lp == 0 && count32x32 == 0) {
cm->tx_mode = ONLY_4X4;
} else if (count8x8_lp == 0 && count16x16_lp == 0 && count4x4 == 0) {
} else if (count32x32 == 0 && count8x8_lp == 0 && count4x4 == 0) {
cm->reference_mode = SINGLE_REFERENCE;
encode_frame_internal(cpi);
static void sum_intra_stats(FRAME_COUNTS *counts, const MODE_INFO *mi) {
const PREDICTION_MODE y_mode = mi->mbmi.mode;
const PREDICTION_MODE uv_mode = mi->mbmi.uv_mode;
const BLOCK_SIZE bsize = mi->mbmi.sb_type;
const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize];
const int num_4x4_h = num_4x4_blocks_high_lookup[bsize];
for (idy = 0; idy < 2; idy += num_4x4_h)
for (idx = 0; idx < 2; idx += num_4x4_w)
++counts->y_mode[0][mi->bmi[idy * 2 + idx].as_mode];
++counts->y_mode[size_group_lookup[bsize]][y_mode];
++counts->uv_mode[y_mode][uv_mode];
static int get_zbin_mode_boost(const MB_MODE_INFO *mbmi, int enabled) {
if (enabled) {
if (is_inter_block(mbmi)) {
if (mbmi->mode == ZEROMV) {
return mbmi->ref_frame[0] != LAST_FRAME ? GF_ZEROMV_ZBIN_BOOST
: LF_ZEROMV_ZBIN_BOOST;
} else {
return mbmi->sb_type < BLOCK_8X8 ? SPLIT_MV_ZBIN_BOOST
: MV_ZBIN_BOOST;
}
} else {
return INTRA_ZBIN_BOOST;
}
} else {
return 0;
}
}
static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t, int output_enabled,
int mi_row, int mi_col, BLOCK_SIZE bsize,
PICK_MODE_CONTEXT *ctx) {
VP9_COMMON *const cm = &cpi->common;
MACROBLOCK *const x = &cpi->mb;
MACROBLOCKD *const xd = &x->e_mbd;
MODE_INFO **mi_8x8 = xd->mi;
MODE_INFO *mi = mi_8x8[0];
MB_MODE_INFO *mbmi = &mi->mbmi;
unsigned int segment_id = mbmi->segment_id;
const int mis = cm->mi_stride;
const int mi_width = num_8x8_blocks_wide_lookup[bsize];
const int mi_height = num_8x8_blocks_high_lookup[bsize];
x->skip_recode = !x->select_tx_size && mbmi->sb_type >= BLOCK_8X8 &&
cpi->oxcf.aq_mode != COMPLEXITY_AQ &&
cpi->oxcf.aq_mode != CYCLIC_REFRESH_AQ &&
cpi->sf.allow_skip_recode;
x->skip_optimize = ctx->is_coded;
ctx->is_coded = 1;
x->use_lp32x32fdct = cpi->sf.use_lp32x32fdct;
x->skip_encode = (!output_enabled && cpi->sf.skip_encode_frame &&
x->q_index < QIDX_SKIP_THRESH);
if (x->skip_encode)
return;
set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
// Experimental code. Special case for gf and arf zeromv modes.
// Increase zbin size to suppress noise
cpi->zbin_mode_boost = get_zbin_mode_boost(mbmi,
cpi->zbin_mode_boost_enabled);
vp9_update_zbin_extra(cpi, x);
for (plane = 0; plane < MAX_MB_PLANE; ++plane)
vp9_encode_intra_block_plane(x, MAX(bsize, BLOCK_8X8), plane);
vp9_tokenize_sb(cpi, t, !output_enabled, MAX(bsize, BLOCK_8X8));
int ref;
const int is_compound = has_second_ref(mbmi);
for (ref = 0; ref < 1 + is_compound; ++ref) {
YV12_BUFFER_CONFIG *cfg = get_ref_frame_buffer(cpi,
mbmi->ref_frame[ref]);
vp9_setup_pre_planes(xd, ref, cfg, mi_row, mi_col,
&xd->block_refs[ref]->sf);
if (!cpi->sf.reuse_inter_pred_sby)
vp9_build_inter_predictors_sby(xd, mi_row, mi_col, MAX(bsize, BLOCK_8X8));
vp9_build_inter_predictors_sbuv(xd, mi_row, mi_col, MAX(bsize, BLOCK_8X8));
if (!x->skip) {
mbmi->skip = 1;
vp9_encode_sb(x, MAX(bsize, BLOCK_8X8));
vp9_tokenize_sb(cpi, t, !output_enabled, MAX(bsize, BLOCK_8X8));
} else {
mbmi->skip = 1;
if (output_enabled &&
!vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP))
cm->counts.skip[vp9_get_skip_context(xd)][1]++;
reset_skip_context(xd, MAX(bsize, BLOCK_8X8));
}
if (cm->tx_mode == TX_MODE_SELECT &&
mbmi->sb_type >= BLOCK_8X8 &&
vp9_segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP)))) {
++get_tx_counts(max_txsize_lookup[bsize], vp9_get_tx_size_context(xd),
&cm->counts.tx)[mbmi->tx_size];
TX_SIZE tx_size;
// The new intra coding scheme requires no change of transform size
tx_size = MIN(tx_mode_to_biggest_tx_size[cm->tx_mode],
max_txsize_lookup[bsize]);
tx_size = (bsize >= BLOCK_8X8) ? mbmi->tx_size : TX_4X4;
for (y = 0; y < mi_height; y++)
for (x = 0; x < mi_width; x++)
if (mi_col + x < cm->mi_cols && mi_row + y < cm->mi_rows)
mi_8x8[mis * y + x]->mbmi.tx_size = tx_size;