#if CONFIG_MULTITHREAD
-#if defined(_WIN32)
+#if defined(_WIN32) && !HAVE_PTHREAD_H
#include <errno.h> // NOLINT
#include <process.h> // NOLINT
#include <windows.h> // NOLINT
%if ARCH_X86_64
INIT_XMM sse2
-cglobal highbd_tm_predictor_16x16, 5, 6, 8, dst, stride, above, left, bps, one
+cglobal highbd_tm_predictor_16x16, 5, 6, 9, dst, stride, above, left, bps, one
movd m2, [aboveq-2]
mova m0, [aboveq]
mova m1, [aboveq+16]
return 0;
}
+
+void vp9_set_vbp_thresholds(VP9_COMP *cpi, int q) {
+ SPEED_FEATURES *const sf = &cpi->sf;
+ if (sf->partition_search_type != VAR_BASED_PARTITION) {
+ return;
+ } else {
+ VP9_COMMON *const cm = &cpi->common;
+ const VP9EncoderConfig *const oxcf = &cpi->oxcf;
+ const int is_key_frame = (cm->frame_type == KEY_FRAME);
+ const int use_4x4_partition = is_key_frame;
+ const int low_res = (cm->width <= 352 && cm->height <= 288);
+ const int threshold_multiplier = is_key_frame ? 80 : 4;
+ const int64_t threshold_base = (int64_t)(threshold_multiplier *
+ vp9_convert_qindex_to_q(q, cm->bit_depth));
+ cpi->vbp_threshold = threshold_base;
+ cpi->vbp_threshold_bsize_min = threshold_base << oxcf->speed;
+ cpi->vbp_threshold_bsize_max = threshold_base;
+
+ if (is_key_frame) {
+ cpi->vbp_threshold = threshold_base >> 2;
+ cpi->vbp_threshold_bsize_min = threshold_base << 2;
+ } else if (low_res) {
+ cpi->vbp_threshold_bsize_min = threshold_base << 3;
+ cpi->vbp_threshold_bsize_max = threshold_base >> 2;
+ }
+ // TODO(marpan): Allow 4x4 partitions for inter-frames.
+ // use_4x4_partition = (variance4x4downsample[i2 + j] == 1);
+ // If 4x4 partition is not used, then 8x8 partition will be selected
+ // if variance of 16x16 block is very high, so use larger threshold
+ // for 16x16 (threshold_bsize_min) in that case.
+ cpi->vbp_threshold_16x16 = (use_4x4_partition) ?
+ cpi->vbp_threshold : cpi->vbp_threshold_bsize_min;
+ cpi->vbp_bsize_min = (use_4x4_partition) ? BLOCK_8X8 : BLOCK_16X16;
+ }
+}
+
+
// This function chooses partitioning based on the variance between source and
// reconstructed last, where variance is computed for downs-sampled inputs.
static void choose_partitioning(VP9_COMP *cpi,
int mi_row, int mi_col) {
VP9_COMMON * const cm = &cpi->common;
MACROBLOCKD *xd = &x->e_mbd;
-
int i, j, k, m;
v64x64 vt;
v16x16 vt2[16];
int dp;
int pixels_wide = 64, pixels_high = 64;
const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, LAST_FRAME);
- const struct scale_factors *const sf = &cm->frame_refs[LAST_FRAME - 1].sf;
+
// Always use 4x4 partition for key frame.
const int is_key_frame = (cm->frame_type == KEY_FRAME);
const int use_4x4_partition = is_key_frame;
+ const int low_res = (cm->width <= 352 && cm->height <= 288);
int variance4x4downsample[16];
- int low_res = (cm->width <= 352 && cm->height <= 288) ? 1 : 0;
- const int threshold_multiplier = is_key_frame ? 80 : 4;
- int64_t threshold_base;
- int64_t threshold;
- int64_t threshold_bsize_min;
- int64_t threshold_bsize_max;
-
- vp9_clear_system_state();
- threshold_base = (int64_t)(threshold_multiplier *
- vp9_convert_qindex_to_q(cm->base_qindex, cm->bit_depth));
- threshold = threshold_base;
- threshold_bsize_min = threshold_base << cpi->oxcf.speed;
- threshold_bsize_max = threshold_base;
-
- // Modify thresholds for key frame and for low-resolutions (set lower
- // thresholds to favor split).
- if (is_key_frame) {
- threshold = threshold_base >> 2;
- threshold_bsize_min = threshold_base << 2;
- } else if (low_res) {
- threshold_bsize_min = threshold_base << 3;
- threshold_bsize_max = threshold_base >> 2;
- }
set_offsets(cpi, tile, x, mi_row, mi_col, BLOCK_64X64);
if (!is_key_frame) {
MB_MODE_INFO *mbmi = &xd->mi[0].src_mi->mbmi;
unsigned int var = 0, sse;
- vp9_setup_pre_planes(xd, 0, yv12, mi_row, mi_col, sf);
+ vp9_setup_pre_planes(xd, 0, yv12, mi_row, mi_col,
+ &cm->frame_refs[LAST_FRAME - 1].sf);
mbmi->ref_frame[0] = LAST_FRAME;
mbmi->ref_frame[1] = NONE;
mbmi->sb_type = BLOCK_64X64;
}
if (is_key_frame || (low_res &&
vt.split[i].split[j].part_variances.none.variance >
- (threshold << 1))) {
+ (cpi->vbp_threshold << 1))) {
// Go down to 4x4 down-sampling for variance.
variance4x4downsample[i2 + j] = 1;
for (k = 0; k < 4; k++) {
}
fill_variance_tree(&vt, BLOCK_64X64);
-
// Now go through the entire structure, splitting every block size until
// we get to one that's got a variance lower than our threshold.
if ( mi_col + 8 > cm->mi_cols || mi_row + 8 > cm->mi_rows ||
!set_vt_partitioning(cpi, xd, &vt, BLOCK_64X64, mi_row, mi_col,
- threshold_bsize_max, BLOCK_16X16)) {
+ cpi->vbp_threshold_bsize_max, BLOCK_16X16)) {
for (i = 0; i < 4; ++i) {
const int x32_idx = ((i & 1) << 2);
const int y32_idx = ((i >> 1) << 2);
const int i2 = i << 2;
if (!set_vt_partitioning(cpi, xd, &vt.split[i], BLOCK_32X32,
(mi_row + y32_idx), (mi_col + x32_idx),
- threshold, BLOCK_16X16)) {
+ cpi->vbp_threshold,
+ BLOCK_16X16)) {
for (j = 0; j < 4; ++j) {
const int x16_idx = ((j & 1) << 1);
const int y16_idx = ((j >> 1) << 1);
- // TODO(marpan): Allow 4x4 partitions for inter-frames.
- // use_4x4_partition = (variance4x4downsample[i2 + j] == 1);
- // If 4x4 partition is not used, then 8x8 partition will be selected
- // if variance of 16x16 block is very high, so use larger threshold
- // for 16x16 (threshold_bsize_min) in that case.
- uint64_t threshold_16x16 = (use_4x4_partition) ? threshold :
- threshold_bsize_min;
- BLOCK_SIZE bsize_min = (use_4x4_partition) ? BLOCK_8X8 : BLOCK_16X16;
// For inter frames: if variance4x4downsample[] == 1 for this 16x16
// block, then the variance is based on 4x4 down-sampling, so use vt2
// in set_vt_partioning(), otherwise use vt.
if (!set_vt_partitioning(cpi, xd, vtemp, BLOCK_16X16,
mi_row + y32_idx + y16_idx,
mi_col + x32_idx + x16_idx,
- threshold_16x16, bsize_min)) {
+ cpi->vbp_threshold_16x16,
+ cpi->vbp_bsize_min)) {
for (k = 0; k < 4; ++k) {
const int x8_idx = (k & 1);
const int y8_idx = (k >> 1);
BLOCK_8X8,
mi_row + y32_idx + y16_idx + y8_idx,
mi_col + x32_idx + x16_idx + x8_idx,
- threshold_bsize_min, BLOCK_8X8)) {
+ cpi->vbp_threshold_bsize_min,
+ BLOCK_8X8)) {
set_block_size(cpi, xd,
(mi_row + y32_idx + y16_idx + y8_idx),
(mi_col + x32_idx + x16_idx + x8_idx),
static void fill_mode_info_sb(VP9_COMMON *cm, MACROBLOCK *x,
int mi_row, int mi_col,
- BLOCK_SIZE bsize, BLOCK_SIZE subsize,
+ BLOCK_SIZE bsize,
PC_TREE *pc_tree) {
MACROBLOCKD *xd = &x->e_mbd;
int bsl = b_width_log2_lookup[bsize], hbs = (1 << bsl) / 4;
PARTITION_TYPE partition = pc_tree->partitioning;
+ BLOCK_SIZE subsize = get_subsize(bsize, partition);
assert(bsize >= BLOCK_8X8);
case PARTITION_VERT:
set_mode_info_offsets(cm, xd, mi_row, mi_col);
*(xd->mi[0].src_mi) = pc_tree->vertical[0].mic;
- duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col, bsize);
+ duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col, subsize);
if (mi_col + hbs < cm->mi_cols) {
set_mode_info_offsets(cm, xd, mi_row, mi_col + hbs);
*(xd->mi[0].src_mi) = pc_tree->vertical[1].mic;
- duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col + hbs, bsize);
+ duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col + hbs, subsize);
}
break;
case PARTITION_HORZ:
set_mode_info_offsets(cm, xd, mi_row, mi_col);
*(xd->mi[0].src_mi) = pc_tree->horizontal[0].mic;
- duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col, bsize);
+ duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col, subsize);
if (mi_row + hbs < cm->mi_rows) {
set_mode_info_offsets(cm, xd, mi_row + hbs, mi_col);
*(xd->mi[0].src_mi) = pc_tree->horizontal[1].mic;
- duplicate_mode_info_in_sb(cm, xd, mi_row + hbs, mi_col, bsize);
+ duplicate_mode_info_in_sb(cm, xd, mi_row + hbs, mi_col, subsize);
}
break;
case PARTITION_SPLIT: {
- BLOCK_SIZE subsubsize = get_subsize(subsize, PARTITION_SPLIT);
- fill_mode_info_sb(cm, x, mi_row, mi_col, subsize,
- subsubsize, pc_tree->split[0]);
+ fill_mode_info_sb(cm, x, mi_row, mi_col, subsize, pc_tree->split[0]);
fill_mode_info_sb(cm, x, mi_row, mi_col + hbs, subsize,
- subsubsize, pc_tree->split[1]);
+ pc_tree->split[1]);
fill_mode_info_sb(cm, x, mi_row + hbs, mi_col, subsize,
- subsubsize, pc_tree->split[2]);
+ pc_tree->split[2]);
fill_mode_info_sb(cm, x, mi_row + hbs, mi_col + hbs, subsize,
- subsubsize, pc_tree->split[3]);
+ pc_tree->split[3]);
break;
}
default:
}
// update mode info array
- subsize = get_subsize(bsize, pc_tree->partitioning);
- fill_mode_info_sb(cm, x, mi_row, mi_col, bsize, subsize,
- pc_tree);
+ fill_mode_info_sb(cm, x, mi_row, mi_col, bsize, pc_tree);
if (best_rdc.rate < INT_MAX && best_rdc.dist < INT64_MAX && do_recon) {
int output_enabled = (bsize == BLOCK_64X64);
void vp9_encode_tile(struct VP9_COMP *cpi, struct ThreadData *td,
int tile_row, int tile_col);
+void vp9_set_vbp_thresholds(struct VP9_COMP *cpi, int q);
+
#ifdef __cplusplus
} // extern "C"
#endif
vp9_extend_frame_borders(dst);
}
+static int scale_down(VP9_COMP *cpi, int q) {
+ RATE_CONTROL *const rc = &cpi->rc;
+ GF_GROUP *const gf_group = &cpi->twopass.gf_group;
+ int scale = 0;
+ assert(frame_is_kf_gf_arf(cpi));
+
+ if (rc->frame_size_selector == UNSCALED &&
+ q >= rc->rf_level_maxq[gf_group->rf_level[gf_group->index]]) {
+ const int max_size_thresh = (int)(rate_thresh_mult[SCALE_STEP1]
+ * MAX(rc->this_frame_target, rc->avg_frame_bandwidth));
+ scale = rc->projected_frame_size > max_size_thresh ? 1 : 0;
+ }
+ return scale;
+}
+
// Function to test for conditions that indicate we should loop
// back and recode a frame.
-static int recode_loop_test(const VP9_COMP *cpi,
+static int recode_loop_test(VP9_COMP *cpi,
int high_limit, int low_limit,
int q, int maxq, int minq) {
const RATE_CONTROL *const rc = &cpi->rc;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
+ const int frame_is_kfgfarf = frame_is_kf_gf_arf(cpi);
int force_recode = 0;
- // Special case trap if maximum allowed frame size exceeded.
- if (rc->projected_frame_size > rc->max_frame_bandwidth) {
- force_recode = 1;
-
- // Is frame recode allowed.
- // Yes if either recode mode 1 is selected or mode 2 is selected
- // and the frame is a key frame, golden frame or alt_ref_frame
- } else if ((cpi->sf.recode_loop == ALLOW_RECODE) ||
- ((cpi->sf.recode_loop == ALLOW_RECODE_KFARFGF) &&
- frame_is_kf_gf_arf(cpi))) {
- // General over and under shoot tests
+ if ((cpi->sf.recode_loop == ALLOW_RECODE) ||
+ (frame_is_kfgfarf &&
+ (cpi->sf.recode_loop == ALLOW_RECODE_KFARFGF))) {
+ if (frame_is_kfgfarf &&
+ (oxcf->resize_mode == RESIZE_DYNAMIC) &&
+ scale_down(cpi, q)) {
+ // Code this group at a lower resolution.
+ cpi->resize_pending = 1;
+ return 1;
+ }
+
+ // TODO(agrange) high_limit could be greater than the scale-down threshold.
if ((rc->projected_frame_size > high_limit && q < maxq) ||
(rc->projected_frame_size < low_limit && q > minq)) {
force_recode = 1;
recon_err = vp9_get_y_sse(cpi->Source, get_frame_new_buffer(cm));
if (cpi->twopass.total_left_stats.coded_error != 0.0)
- fprintf(f, "%10u %10d %10d %10d %10d"
+ fprintf(f, "%10u %dx%d %10d %10d %10d %10d"
"%10"PRId64" %10"PRId64" %10"PRId64" %10"PRId64" %10d "
"%7.2lf %7.2lf %7.2lf %7.2lf %7.2lf"
"%6d %6d %5d %5d %5d "
"%10"PRId64" %10.3lf"
"%10lf %8u %10"PRId64" %10d %10d\n",
- cpi->common.current_video_frame, cpi->rc.this_frame_target,
+ cpi->common.current_video_frame,
+ cm->width, cm->height,
+ cpi->rc.this_frame_target,
cpi->rc.projected_frame_size,
cpi->rc.projected_frame_size / cpi->common.MBs,
(cpi->rc.projected_frame_size - cpi->rc.this_frame_target),
void set_frame_size(VP9_COMP *cpi) {
int ref_frame;
VP9_COMMON *const cm = &cpi->common;
- const VP9EncoderConfig *const oxcf = &cpi->oxcf;
+ VP9EncoderConfig *const oxcf = &cpi->oxcf;
MACROBLOCKD *const xd = &cpi->td.mb.e_mbd;
if (oxcf->pass == 2 &&
- cm->current_video_frame == 0 &&
- oxcf->resize_mode == RESIZE_FIXED &&
- oxcf->rc_mode == VPX_VBR) {
- // Internal scaling is triggered on the first frame.
+ oxcf->rc_mode == VPX_VBR &&
+ ((oxcf->resize_mode == RESIZE_FIXED && cm->current_video_frame == 0) ||
+ (oxcf->resize_mode == RESIZE_DYNAMIC && cpi->resize_pending))) {
+ calculate_coded_size(
+ cpi, &oxcf->scaled_frame_width, &oxcf->scaled_frame_height);
+
+ // There has been a change in frame size.
vp9_set_size_literal(cpi, oxcf->scaled_frame_width,
oxcf->scaled_frame_height);
}
static void encode_without_recode_loop(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
- int q, bottom_index, top_index; // Dummy variables.
+ int q = 0, bottom_index = 0, top_index = 0; // Dummy variables.
vp9_clear_system_state();
set_size_dependent_vars(cpi, &q, &bottom_index, &top_index);
vp9_set_quantizer(cm, q);
+ vp9_set_vbp_thresholds(cpi, q);
+
setup_frame(cpi);
+
// Variance adaptive and in frame q adjustment experiments are mutually
// exclusive.
if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
RATE_CONTROL *const rc = &cpi->rc;
int bottom_index, top_index;
int loop_count = 0;
+ int loop_at_this_size = 0;
int loop = 0;
int overshoot_seen = 0;
int undershoot_seen = 0;
int frame_over_shoot_limit;
int frame_under_shoot_limit;
int q = 0, q_low = 0, q_high = 0;
- int frame_size_changed = 0;
set_size_independent_vars(cpi);
set_frame_size(cpi);
- if (loop_count == 0 || frame_size_changed != 0) {
+ if (loop_count == 0 || cpi->resize_pending != 0) {
set_size_dependent_vars(cpi, &q, &bottom_index, &top_index);
- q_low = bottom_index;
- q_high = top_index;
// TODO(agrange) Scale cpi->max_mv_magnitude if frame-size has changed.
set_mv_search_params(cpi);
+
+ // Reset the loop state for new frame size.
+ overshoot_seen = 0;
+ undershoot_seen = 0;
+
+ // Reconfiguration for change in frame size has concluded.
+ cpi->resize_pending = 0;
+
+ q_low = bottom_index;
+ q_high = top_index;
+
+ loop_at_this_size = 0;
}
- // Decide frame size bounds
- vp9_rc_compute_frame_size_bounds(cpi, rc->this_frame_target,
- &frame_under_shoot_limit,
- &frame_over_shoot_limit);
+ // Decide frame size bounds first time through.
+ if (loop_count == 0) {
+ vp9_rc_compute_frame_size_bounds(cpi, rc->this_frame_target,
+ &frame_under_shoot_limit,
+ &frame_over_shoot_limit);
+ }
cpi->Source = vp9_scale_if_required(cm, cpi->un_scaled_source,
&cpi->scaled_source);
int last_q = q;
int retries = 0;
+ if (cpi->resize_pending == 1) {
+ // Change in frame size so go back around the recode loop.
+ cpi->rc.frame_size_selector =
+ SCALE_STEP1 - cpi->rc.frame_size_selector;
+ cpi->rc.next_frame_size_selector = cpi->rc.frame_size_selector;
+
+#if CONFIG_INTERNAL_STATS
+ ++cpi->tot_recode_hits;
+#endif
+ ++loop_count;
+ loop = 1;
+ continue;
+ }
+
// Frame size out of permitted range:
// Update correction factor & compute new Q to try...
// Raise Qlow as to at least the current value
q_low = q < q_high ? q + 1 : q_high;
- if (undershoot_seen || loop_count > 1) {
+ if (undershoot_seen || loop_at_this_size > 1) {
// Update rate_correction_factor unless
vp9_rc_update_rate_correction_factors(cpi);
// Frame is too small
q_high = q > q_low ? q - 1 : q_low;
- if (overshoot_seen || loop_count > 1) {
+ if (overshoot_seen || loop_at_this_size > 1) {
vp9_rc_update_rate_correction_factors(cpi);
q = (q_high + q_low) / 2;
} else {
// Clamp Q to upper and lower limits:
q = clamp(q, q_low, q_high);
- loop = q != last_q;
+ loop = (q != last_q);
} else {
loop = 0;
}
loop = 0;
if (loop) {
- loop_count++;
+ ++loop_count;
+ ++loop_at_this_size;
#if CONFIG_INTERNAL_STATS
- cpi->tot_recode_hits++;
+ ++cpi->tot_recode_hits;
#endif
}
} while (loop);
VP9_DENOISER denoiser;
#endif
+ int resize_pending;
+
+ // VAR_BASED_PARTITION thresholds
+ int64_t vbp_threshold;
+ int64_t vbp_threshold_bsize_min;
+ int64_t vbp_threshold_bsize_max;
+ int64_t vbp_threshold_16x16;
+ BLOCK_SIZE vbp_bsize_min;
+
// Multi-threading
int num_workers;
VP9Worker *workers;
return cpi->sf.mv.subpel_search_method != SUBPEL_TREE ? cost_list : NULL;
}
+void vp9_new_framerate(VP9_COMP *cpi, double framerate);
+
#ifdef __cplusplus
} // extern "C"
#endif
}
}
-extern void vp9_new_framerate(VP9_COMP *cpi, double framerate);
+static void setup_rf_level_maxq(VP9_COMP *cpi) {
+ int i;
+ RATE_CONTROL *const rc = &cpi->rc;
+ for (i = INTER_NORMAL; i < RATE_FACTOR_LEVELS; ++i) {
+ int qdelta = vp9_frame_type_qdelta(cpi, i, rc->worst_quality);
+ rc->rf_level_maxq[i] = MAX(rc->worst_quality + qdelta, rc->best_quality);
+ }
+}
+
+void vp9_init_subsampling(VP9_COMP *cpi) {
+ const VP9_COMMON *const cm = &cpi->common;
+ RATE_CONTROL *const rc = &cpi->rc;
+ const int w = cm->width;
+ const int h = cm->height;
+ int i;
+
+ for (i = 0; i < FRAME_SCALE_STEPS; ++i) {
+ // Note: Frames with odd-sized dimensions may result from this scaling.
+ rc->frame_width[i] = (w * 16) / frame_scale_factor[i];
+ rc->frame_height[i] = (h * 16) / frame_scale_factor[i];
+ }
+
+ setup_rf_level_maxq(cpi);
+}
+
+void calculate_coded_size(VP9_COMP *cpi,
+ int *scaled_frame_width,
+ int *scaled_frame_height) {
+ RATE_CONTROL *const rc = &cpi->rc;
+ *scaled_frame_width = rc->frame_width[rc->frame_size_selector];
+ *scaled_frame_height = rc->frame_height[rc->frame_size_selector];
+}
void vp9_init_second_pass(VP9_COMP *cpi) {
SVC *const svc = &cpi->svc;
// Static sequence monitor variables.
twopass->kf_zeromotion_pct = 100;
twopass->last_kfgroup_zeromotion_pct = 100;
+
+ if (oxcf->resize_mode != RESIZE_NONE) {
+ vp9_init_subsampling(cpi);
+ }
}
#define SR_DIFF_PART 0.0015
// Analyse and define a gf/arf group.
static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
+ VP9_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc;
- const VP9EncoderConfig *const oxcf = &cpi->oxcf;
+ VP9EncoderConfig *const oxcf = &cpi->oxcf;
TWO_PASS *const twopass = &cpi->twopass;
FIRSTPASS_STATS next_frame;
const FIRSTPASS_STATS *const start_pos = twopass->stats_in;
int64_t gf_group_bits;
double gf_group_error_left;
int gf_arf_bits;
+ int is_key_frame = frame_is_intra_only(cm);
// Reset the GF group data structures unless this is a key
// frame in which case it will already have been done.
- if (cpi->common.frame_type != KEY_FRAME) {
+ if (is_key_frame == 0) {
vp9_zero(twopass->gf_group);
}
// If this is a key frame or the overlay from a previous arf then
// the error score / cost of this frame has already been accounted for.
- if (cpi->common.frame_type == KEY_FRAME || rc->source_alt_ref_active) {
+ if (is_key_frame || rc->source_alt_ref_active) {
gf_group_err -= gf_first_frame_err;
#if GROUP_ADAPTIVE_MAXQ
gf_group_raw_error -= this_frame->coded_error;
rc->constrained_gf_group = (i >= rc->frames_to_key) ? 1 : 0;
// Set the interval until the next gf.
- if (cpi->common.frame_type == KEY_FRAME || rc->source_alt_ref_active)
+ if (is_key_frame || rc->source_alt_ref_active)
rc->baseline_gf_interval = i - 1;
else
rc->baseline_gf_interval = i;
get_twopass_worst_quality(cpi, group_av_err, vbr_group_bits_per_frame,
twopass->kfgroup_inter_fraction);
- if (tmp_q < twopass->baseline_worst_quality) {
+ if (tmp_q < twopass->baseline_active_worst_quality) {
twopass->active_worst_quality =
- (tmp_q + twopass->baseline_worst_quality + 1) / 2;
+ (tmp_q + twopass->baseline_active_worst_quality + 1) / 2;
} else {
twopass->active_worst_quality = tmp_q;
}
// also a key frame in which case it has already been accounted for.
if (rc->source_alt_ref_pending) {
gf_group_error_left = gf_group_err - mod_frame_err;
- } else if (cpi->common.frame_type != KEY_FRAME) {
+ } else if (is_key_frame == 0) {
gf_group_error_left = gf_group_err - gf_first_frame_err;
} else {
gf_group_error_left = gf_group_err;
calculate_section_intra_ratio(start_pos, twopass->stats_in_end,
rc->baseline_gf_interval);
}
+
+ if (oxcf->resize_mode == RESIZE_DYNAMIC) {
+ // Default to starting GF groups at normal frame size.
+ cpi->rc.next_frame_size_selector = UNSCALED;
+ }
}
// TODO(PGW) Re-examine the use of II ration in this code in the light of#
// The count of bits left is adjusted elsewhere based on real coded frame
// sizes.
twopass->modified_error_left -= kf_group_err;
+
+ if (oxcf->resize_mode == RESIZE_DYNAMIC) {
+ // Default to normal-sized frame on keyframes.
+ cpi->rc.next_frame_size_selector = UNSCALED;
+ }
}
// Define the reference buffers that will be updated post encode.
section_target_bandwidth, DEFAULT_GRP_WEIGHT);
twopass->active_worst_quality = tmp_q;
- twopass->baseline_worst_quality = tmp_q;
+ twopass->baseline_active_worst_quality = tmp_q;
rc->ni_av_qi = tmp_q;
rc->last_q[INTER_FRAME] = tmp_q;
rc->avg_q = vp9_convert_qindex_to_q(tmp_q, cm->bit_depth);
int kf_zeromotion_pct;
int last_kfgroup_zeromotion_pct;
int gf_zeromotion_pct;
- int baseline_worst_quality;
int active_worst_quality;
+ int baseline_active_worst_quality;
int extend_minq;
int extend_maxq;
// Post encode update of the rate control parameters for 2-pass
void vp9_twopass_postencode_update(struct VP9_COMP *cpi);
+
+void vp9_init_subsampling(struct VP9_COMP *cpi);
+
+void calculate_coded_size(struct VP9_COMP *cpi,
+ int *scaled_frame_width,
+ int *scaled_frame_height);
+
#ifdef __cplusplus
} // extern "C"
#endif
ZEROMV, NEARESTMV, NEARMV, NEWMV,
};
+static const int ref_frame_cost[MAX_REF_FRAMES] = {
+ 1235, 229, 530, 615,
+};
// TODO(jingning) placeholder for inter-frame non-RD mode decision.
// this needs various further optimizations. to be continued..
void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
vp9_build_inter_predictors_sby(xd, mi_row, mi_col, bsize);
model_rd_for_sb_y(cpi, bsize, x, xd, &pf_rate[filter],
&pf_dist[filter], &pf_var[filter], &pf_sse[filter]);
- cost = RDCOST(x->rdmult, x->rddiv,
- vp9_get_switchable_rate(cpi, xd) + pf_rate[filter],
- pf_dist[filter]);
+ pf_rate[filter] += vp9_get_switchable_rate(cpi, xd);
+ cost = RDCOST(x->rdmult, x->rddiv, pf_rate[filter], pf_dist[filter]);
pf_tx_size[filter] = mbmi->tx_size;
if (cost < best_cost) {
best_filter = filter;
vp9_build_inter_predictors_sby(xd, mi_row, mi_col, bsize);
model_rd_for_sb_y(cpi, bsize, x, xd, &this_rdc.rate, &this_rdc.dist,
&var_y, &sse_y);
+ this_rdc.rate += cm->interp_filter == SWITCHABLE ?
+ vp9_get_switchable_rate(cpi, xd) : 0;
}
// chroma component rate-distortion cost modeling
this_rdc.rate += rate_mv;
this_rdc.rate += cpi->inter_mode_cost[mbmi->mode_context[ref_frame]]
[INTER_OFFSET(this_mode)];
+ this_rdc.rate += ref_frame_cost[ref_frame];
this_rdc.rdcost = RDCOST(x->rdmult, x->rddiv,
this_rdc.rate, this_rdc.dist);
this_rdc.rate = args.rate;
this_rdc.dist = args.dist;
this_rdc.rate += cpi->mbmode_cost[this_mode];
+ this_rdc.rate += ref_frame_cost[INTRA_FRAME];
this_rdc.rate += intra_cost_penalty;
this_rdc.rdcost = RDCOST(x->rdmult, x->rddiv,
this_rdc.rate, this_rdc.dist);
static double get_rate_correction_factor(const VP9_COMP *cpi) {
const RATE_CONTROL *const rc = &cpi->rc;
+ double rcf;
if (cpi->common.frame_type == KEY_FRAME) {
- return rc->rate_correction_factors[KF_STD];
+ rcf = rc->rate_correction_factors[KF_STD];
} else if (cpi->oxcf.pass == 2) {
RATE_FACTOR_LEVEL rf_lvl =
cpi->twopass.gf_group.rf_level[cpi->twopass.gf_group.index];
- return rc->rate_correction_factors[rf_lvl];
+ rcf = rc->rate_correction_factors[rf_lvl];
} else {
if ((cpi->refresh_alt_ref_frame || cpi->refresh_golden_frame) &&
!rc->is_src_frame_alt_ref && !cpi->use_svc &&
(cpi->oxcf.rc_mode != VPX_CBR || cpi->oxcf.gf_cbr_boost_pct > 20))
- return rc->rate_correction_factors[GF_ARF_STD];
+ rcf = rc->rate_correction_factors[GF_ARF_STD];
else
- return rc->rate_correction_factors[INTER_NORMAL];
+ rcf = rc->rate_correction_factors[INTER_NORMAL];
}
+ rcf *= rcf_mult[rc->frame_size_selector];
+ return rcf > MAX_BPB_FACTOR ? MAX_BPB_FACTOR : rcf;
}
static void set_rate_correction_factor(VP9_COMP *cpi, double factor) {
RATE_CONTROL *const rc = &cpi->rc;
+ // Normalize RCF to account for the size-dependent scaling factor.
+ factor /= rcf_mult[cpi->rc.frame_size_selector];
+
if (cpi->common.frame_type == KEY_FRAME) {
rc->rate_correction_factors[KF_STD] = factor;
} else if (cpi->oxcf.pass == 2) {
return q;
}
+int vp9_frame_type_qdelta(const VP9_COMP *cpi, int rf_level, int q) {
+ static const double rate_factor_deltas[RATE_FACTOR_LEVELS] = {
+ 1.00, // INTER_NORMAL
+ 1.00, // INTER_HIGH
+ 1.50, // GF_ARF_LOW
+ 1.75, // GF_ARF_STD
+ 2.00, // KF_STD
+ };
+ static const FRAME_TYPE frame_type[RATE_FACTOR_LEVELS] =
+ {INTER_FRAME, INTER_FRAME, INTER_FRAME, INTER_FRAME, KEY_FRAME};
+ const VP9_COMMON *const cm = &cpi->common;
+ int qdelta = vp9_compute_qdelta_by_rate(&cpi->rc, frame_type[rf_level],
+ q, rate_factor_deltas[rf_level],
+ cm->bit_depth);
+ return qdelta;
+}
+
#define STATIC_MOTION_THRESH 95
static int rc_pick_q_and_bounds_two_pass(const VP9_COMP *cpi,
int *bottom_index,
const VP9_COMMON *const cm = &cpi->common;
const RATE_CONTROL *const rc = &cpi->rc;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
+ const GF_GROUP *gf_group = &cpi->twopass.gf_group;
const int cq_level = get_active_cq_level(rc, oxcf);
int active_best_quality;
int active_worst_quality = cpi->twopass.active_worst_quality;
if (!cpi->refresh_alt_ref_frame) {
active_best_quality = cq_level;
} else {
- const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
active_best_quality = get_gf_active_quality(rc, q, cm->bit_depth);
// Modify best quality for second level arfs. For mode VPX_Q this
}
}
- // Extenstion to max or min Q if undershoot or overshoot is outside
+ // Extension to max or min Q if undershoot or overshoot is outside
// the permitted range.
if ((cpi->oxcf.rc_mode == VPX_VBR) &&
(cpi->twopass.gf_zeromotion_pct < VLOW_MOTION_THRESHOLD)) {
if (!((frame_is_intra_only(cm) || vp9_is_upper_layer_key_frame(cpi))) ||
!rc->this_key_frame_forced ||
(cpi->twopass.last_kfgroup_zeromotion_pct < STATIC_MOTION_THRESH)) {
- const GF_GROUP *const gf_group = &cpi->twopass.gf_group;
- const double rate_factor_deltas[RATE_FACTOR_LEVELS] = {
- 1.00, // INTER_NORMAL
- 1.00, // INTER_HIGH
- 1.50, // GF_ARF_LOW
- 1.75, // GF_ARF_STD
- 2.00, // KF_STD
- };
- const double rate_factor =
- rate_factor_deltas[gf_group->rf_level[gf_group->index]];
- int qdelta = vp9_compute_qdelta_by_rate(&cpi->rc, cm->frame_type,
- active_worst_quality, rate_factor,
- cm->bit_depth);
- active_worst_quality = active_worst_quality + qdelta;
- active_worst_quality = MAX(active_worst_quality, active_best_quality);
+ int qdelta = vp9_frame_type_qdelta(cpi, gf_group->rf_level[gf_group->index],
+ active_worst_quality);
+ active_worst_quality = MAX(active_worst_quality + qdelta,
+ active_best_quality);
}
#endif
- // Clip the active best and worst quality values to limits.
+ // Modify active_best_quality for downscaled normal frames.
+ if (rc->frame_size_selector != UNSCALED && !frame_is_kf_gf_arf(cpi)) {
+ int qdelta = vp9_compute_qdelta_by_rate(rc, cm->frame_type,
+ active_best_quality, 2.0,
+ cm->bit_depth);
+ active_best_quality = MAX(active_best_quality + qdelta, rc->best_quality);
+ }
+
active_best_quality = clamp(active_best_quality,
rc->best_quality, rc->worst_quality);
active_worst_quality = clamp(active_worst_quality,
rc->this_frame_target = target;
+ // Modify frame size target when down-scaling.
+ if (cpi->oxcf.resize_mode == RESIZE_DYNAMIC &&
+ rc->frame_size_selector != UNSCALED)
+ rc->this_frame_target =
+ rc->this_frame_target * rate_thresh_mult[rc->frame_size_selector];
+
// Target rate per SB64 (including partial SB64s.
rc->sb64_target_rate = ((int64_t)rc->this_frame_target * 64 * 64) /
(cm->width * cm->height);
rc->frames_since_key++;
rc->frames_to_key--;
}
+
+ // Trigger the resizing of the next frame if it is scaled.
+ cpi->resize_pending =
+ rc->next_frame_size_selector != rc->frame_size_selector;
+ rc->frame_size_selector = rc->next_frame_size_selector;
}
void vp9_rc_postencode_update_drop_frame(VP9_COMP *cpi) {
RATE_FACTOR_LEVELS = 5
} RATE_FACTOR_LEVEL;
+// Internal frame scaling level.
+typedef enum {
+ UNSCALED = 0, // Frame is unscaled.
+ SCALE_STEP1 = 1, // First-level down-scaling.
+ FRAME_SCALE_STEPS
+} FRAME_SCALE_LEVEL;
+
+// Frame dimensions multiplier wrt the native frame size, in 1/16ths,
+// specified for the scale-up case.
+// e.g. 24 => 16/24 = 2/3 of native size. The restriction to 1/16th is
+// intended to match the capabilities of the normative scaling filters,
+// giving precedence to the up-scaling accuracy.
+static const int frame_scale_factor[FRAME_SCALE_STEPS] = {16, 24};
+
+// Multiplier of the target rate to be used as threshold for triggering scaling.
+static const double rate_thresh_mult[FRAME_SCALE_STEPS] = {1.0, 2.0};
+
+// Scale dependent Rate Correction Factor multipliers. Compensates for the
+// greater number of bits per pixel generated in down-scaled frames.
+static const double rcf_mult[FRAME_SCALE_STEPS] = {1.0, 2.0};
+
typedef struct {
// Rate targetting variables
int base_frame_target; // A baseline frame target before adjustment
int64_t starting_buffer_level;
int64_t optimal_buffer_level;
int64_t maximum_buffer_size;
+
// rate control history for last frame(1) and the frame before(2).
// -1: undershot
// 1: overshoot
int rc_2_frame;
int q_1_frame;
int q_2_frame;
+
+ // Auto frame-scaling variables.
+ FRAME_SCALE_LEVEL frame_size_selector;
+ FRAME_SCALE_LEVEL next_frame_size_selector;
+ int frame_width[FRAME_SCALE_STEPS];
+ int frame_height[FRAME_SCALE_STEPS];
+ int rf_level_maxq[RATE_FACTOR_LEVELS];
} RATE_CONTROL;
struct VP9_COMP;
int qindex, double rate_target_ratio,
vpx_bit_depth_t bit_depth);
+int vp9_frame_type_qdelta(const struct VP9_COMP *cpi, int rf_level, int q);
+
void vp9_rc_update_framerate(struct VP9_COMP *cpi);
void vp9_rc_set_gf_max_interval(const struct VP9_COMP *const cpi,
for (midx = 0; midx < INTER_MODES; ++midx)
bsi->rdstat[iy][midx].brdcost = INT64_MAX;
bsi->segment_rd = INT64_MAX;
- return INT64_MAX;;
+ return INT64_MAX;
}
mode_idx = INTER_OFFSET(mode_selected);
for (midx = 0; midx < INTER_MODES; ++midx)
bsi->rdstat[iy][midx].brdcost = INT64_MAX;
bsi->segment_rd = INT64_MAX;
- return INT64_MAX;;
+ return INT64_MAX;
}
}
} /* for each label */
if (cpi->sf.adaptive_motion_search) {
int bwl = b_width_log2_lookup[bsize];
int bhl = b_height_log2_lookup[bsize];
- int i;
int tlevel = x->pred_mv_sad[ref] >> (bwl + bhl + 4);
if (tlevel < 5)
step_param += 2;
- for (i = LAST_FRAME; i <= ALTREF_FRAME && cm->show_frame; ++i) {
- if ((x->pred_mv_sad[ref] >> 3) > x->pred_mv_sad[i]) {
- x->pred_mv[ref].row = 0;
- x->pred_mv[ref].col = 0;
- tmp_mv->as_int = INVALID_MV;
-
- if (scaled_ref_frame) {
- int i;
- for (i = 0; i < MAX_MB_PLANE; i++)
- xd->plane[i].pre[0] = backup_yv12[i];
+ // prev_mv_sad is not setup for dynamically scaled frames.
+ if (cpi->oxcf.resize_mode != RESIZE_DYNAMIC) {
+ int i;
+ for (i = LAST_FRAME; i <= ALTREF_FRAME && cm->show_frame; ++i) {
+ if ((x->pred_mv_sad[ref] >> 3) > x->pred_mv_sad[i]) {
+ x->pred_mv[ref].row = 0;
+ x->pred_mv[ref].col = 0;
+ tmp_mv->as_int = INVALID_MV;
+
+ if (scaled_ref_frame) {
+ int i;
+ for (i = 0; i < MAX_MB_PLANE; ++i)
+ xd->plane[i].pre[0] = backup_yv12[i];
+ }
+ return;
}
- return;
}
}
}
best_mode_skippable |= !has_high_freq_coeff;
}
+ assert(best_mode_index >= 0);
+
store_coding_context(x, ctx, best_mode_index, best_pred_diff,
best_tx_diff, best_filter_diff, best_mode_skippable);
}
sf->tx_size_search_method = frame_is_boosted(cpi) ? USE_FULL_RD
: USE_LARGESTALL;
- sf->reference_masking = 1;
+ // Reference masking is not supported in dynamic scaling mode.
+ sf->reference_masking = cpi->oxcf.resize_mode != RESIZE_DYNAMIC ? 1 : 0;
+
sf->mode_search_skip_flags = (cm->frame_type == KEY_FRAME) ? 0 :
FLAG_SKIP_INTRA_DIRMISMATCH |
FLAG_SKIP_INTRA_BESTINTER |
FLAG_SKIP_COMP_BESTINTRA |
FLAG_SKIP_INTRA_LOWVAR;
sf->adaptive_pred_interp_filter = 2;
- sf->reference_masking = 1;
+
+ // Reference masking is not supported in dynamic scaling mode.
+ sf->reference_masking = cpi->oxcf.resize_mode != RESIZE_DYNAMIC ? 1 : 0;
+
sf->disable_filter_search_var_thresh = 50;
sf->comp_inter_joint_search_thresh = BLOCK_SIZES;
sf->auto_min_max_partition_size = RELAXED_NEIGHBORING_MIN_MAX;
#endif
#endif // VP9_ENCODER_VP9_SPEED_FEATURES_H_
-
NULL, "frame-boost", 1,
"Enable frame periodic boost (0: off (default), 1: on)");
+static const struct arg_enum_list color_space_enum[] = {
+ { "unknown", VPX_CS_UNKNOWN },
+ { "bt601", VPX_CS_BT_601 },
+ { "bt709", VPX_CS_BT_709 },
+ { "smpte170", VPX_CS_SMPTE_170 },
+ { "smpte240", VPX_CS_SMPTE_240 },
+ { "bt2020", VPX_CS_BT_2020 },
+ { "reserved", VPX_CS_RESERVED },
+ { "sRGB", VPX_CS_SRGB },
+ { NULL, 0 }
+};
+
+static const arg_def_t input_color_space = ARG_DEF_ENUM(
+ NULL, "color-space", 1,
+ "The color space of input content:", color_space_enum);
+
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
static const struct arg_enum_list bitdepth_enum[] = {
{"8", VPX_BITS_8},
&tune_ssim, &cq_level, &max_intra_rate_pct, &max_inter_rate_pct,
&gf_cbr_boost_pct, &lossless,
&frame_parallel_decoding, &aq_mode, &frame_periodic_boost,
- &noise_sens, &tune_content,
+ &noise_sens, &tune_content, &input_color_space,
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
&bitdeptharg, &inbitdeptharg,
#endif