Index: source/libvpx/vp9/encoder/vp9_firstpass.c |
=================================================================== |
--- source/libvpx/vp9/encoder/vp9_firstpass.c (revision 291857) |
+++ source/libvpx/vp9/encoder/vp9_firstpass.c (working copy) |
@@ -76,16 +76,6 @@ |
p->stats_in = position; |
} |
-static int lookup_next_frame_stats(const TWO_PASS *p, |
- FIRSTPASS_STATS *next_frame) { |
- if (p->stats_in >= p->stats_in_end) |
- return EOF; |
- |
- *next_frame = *p->stats_in; |
- return 1; |
-} |
- |
- |
// Read frame stats at an offset from the current position. |
static const FIRSTPASS_STATS *read_frame_stats(const TWO_PASS *p, int offset) { |
if ((offset >= 0 && p->stats_in + offset >= p->stats_in_end) || |
@@ -256,7 +246,7 @@ |
} |
void vp9_end_first_pass(VP9_COMP *cpi) { |
- if (is_spatial_svc(cpi)) { |
+ if (is_two_pass_svc(cpi)) { |
int i; |
for (i = 0; i < cpi->svc.number_spatial_layers; ++i) { |
output_stats(&cpi->svc.layer_context[i].twopass.total_stats, |
@@ -396,7 +386,7 @@ |
cpi->rc.frames_to_key = INT_MAX; |
} |
-void vp9_first_pass(VP9_COMP *cpi) { |
+void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) { |
int mb_row, mb_col; |
MACROBLOCK *const x = &cpi->mb; |
VP9_COMMON *const cm = &cpi->common; |
@@ -428,12 +418,12 @@ |
int neutral_count = 0; |
int new_mv_count = 0; |
int sum_in_vectors = 0; |
- uint32_t lastmv_as_int = 0; |
+ MV lastmv = {0, 0}; |
TWO_PASS *twopass = &cpi->twopass; |
const MV zero_mv = {0, 0}; |
const YV12_BUFFER_CONFIG *first_ref_buf = lst_yv12; |
- LAYER_CONTEXT *const lc = is_spatial_svc(cpi) ? |
- &cpi->svc.layer_context[cpi->svc.spatial_layer_id] : 0; |
+ LAYER_CONTEXT *const lc = is_two_pass_svc(cpi) ? |
+ &cpi->svc.layer_context[cpi->svc.spatial_layer_id] : NULL; |
#if CONFIG_FP_MB_STATS |
if (cpi->use_fp_mb_stats) { |
@@ -448,13 +438,13 @@ |
if (lc != NULL) { |
MV_REFERENCE_FRAME ref_frame = LAST_FRAME; |
- const YV12_BUFFER_CONFIG *scaled_ref_buf = NULL; |
twopass = &lc->twopass; |
if (cpi->common.current_video_frame == 0) { |
cpi->ref_frame_flags = 0; |
} else { |
- if (lc->current_video_frame_in_layer == 0) |
+ if (lc->current_video_frame_in_layer < |
+ (unsigned int)cpi->svc.number_temporal_layers) |
cpi->ref_frame_flags = VP9_GOLD_FLAG; |
else |
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG; |
@@ -464,16 +454,17 @@ |
// Use either last frame or alt frame for motion search. |
if (cpi->ref_frame_flags & VP9_LAST_FLAG) { |
- scaled_ref_buf = vp9_get_scaled_ref_frame(cpi, LAST_FRAME); |
+ first_ref_buf = vp9_get_scaled_ref_frame(cpi, LAST_FRAME); |
ref_frame = LAST_FRAME; |
+ if (first_ref_buf == NULL) |
+ first_ref_buf = get_ref_frame_buffer(cpi, LAST_FRAME); |
} else if (cpi->ref_frame_flags & VP9_GOLD_FLAG) { |
- scaled_ref_buf = vp9_get_scaled_ref_frame(cpi, GOLDEN_FRAME); |
+ first_ref_buf = vp9_get_scaled_ref_frame(cpi, GOLDEN_FRAME); |
ref_frame = GOLDEN_FRAME; |
+ if (first_ref_buf == NULL) |
+ first_ref_buf = get_ref_frame_buffer(cpi, GOLDEN_FRAME); |
} |
- if (scaled_ref_buf != NULL) |
- first_ref_buf = scaled_ref_buf; |
- |
recon_y_stride = new_yv12->y_stride; |
recon_uv_stride = new_yv12->uv_stride; |
uv_mb_height = 16 >> (new_yv12->y_height > new_yv12->uv_height); |
@@ -512,10 +503,8 @@ |
vp9_tile_init(&tile, cm, 0, 0); |
for (mb_row = 0; mb_row < cm->mb_rows; ++mb_row) { |
- int_mv best_ref_mv; |
+ MV best_ref_mv = {0, 0}; |
- best_ref_mv.as_int = 0; |
- |
// Reset above block coeffs. |
xd->up_available = (mb_row != 0); |
recon_yoffset = (mb_row * recon_y_stride * 16); |
@@ -594,14 +583,13 @@ |
// Other than for the first frame do a motion search. |
if (cm->current_video_frame > 0) { |
int tmp_err, motion_error, raw_motion_error; |
- int_mv mv, tmp_mv; |
+ // Assume 0,0 motion with no mv overhead. |
+ MV mv = {0, 0} , tmp_mv = {0, 0}; |
struct buf_2d unscaled_last_source_buf_2d; |
xd->plane[0].pre[0].buf = first_ref_buf->y_buffer + recon_yoffset; |
motion_error = get_prediction_error(bsize, &x->plane[0].src, |
&xd->plane[0].pre[0]); |
- // Assume 0,0 motion with no mv overhead. |
- mv.as_int = tmp_mv.as_int = 0; |
// Compute the motion error of the 0,0 motion using the last source |
// frame as the reference. Skip the further motion search on |
@@ -617,8 +605,7 @@ |
if (raw_motion_error > 25 || lc != NULL) { |
// Test last reference frame using the previous best mv as the |
// starting point (best reference) for the search. |
- first_pass_motion_search(cpi, x, &best_ref_mv.as_mv, &mv.as_mv, |
- &motion_error); |
+ first_pass_motion_search(cpi, x, &best_ref_mv, &mv, &motion_error); |
if (cpi->oxcf.aq_mode == VARIANCE_AQ) { |
vp9_clear_system_state(); |
motion_error = (int)(motion_error * error_weight); |
@@ -626,9 +613,9 @@ |
// If the current best reference mv is not centered on 0,0 then do a |
// 0,0 based search as well. |
- if (best_ref_mv.as_int) { |
+ if (!is_zero_mv(&best_ref_mv)) { |
tmp_err = INT_MAX; |
- first_pass_motion_search(cpi, x, &zero_mv, &tmp_mv.as_mv, &tmp_err); |
+ first_pass_motion_search(cpi, x, &zero_mv, &tmp_mv, &tmp_err); |
if (cpi->oxcf.aq_mode == VARIANCE_AQ) { |
vp9_clear_system_state(); |
tmp_err = (int)(tmp_err * error_weight); |
@@ -636,7 +623,7 @@ |
if (tmp_err < motion_error) { |
motion_error = tmp_err; |
- mv.as_int = tmp_mv.as_int; |
+ mv = tmp_mv; |
} |
} |
@@ -649,7 +636,7 @@ |
gf_motion_error = get_prediction_error(bsize, &x->plane[0].src, |
&xd->plane[0].pre[0]); |
- first_pass_motion_search(cpi, x, &zero_mv, &tmp_mv.as_mv, |
+ first_pass_motion_search(cpi, x, &zero_mv, &tmp_mv, |
&gf_motion_error); |
if (cpi->oxcf.aq_mode == VARIANCE_AQ) { |
vp9_clear_system_state(); |
@@ -680,7 +667,8 @@ |
} |
// Start by assuming that intra mode is best. |
- best_ref_mv.as_int = 0; |
+ best_ref_mv.row = 0; |
+ best_ref_mv.col = 0; |
#if CONFIG_FP_MB_STATS |
if (cpi->use_fp_mb_stats) { |
@@ -704,25 +692,25 @@ |
this_error < 2 * intrapenalty) |
++neutral_count; |
- mv.as_mv.row *= 8; |
- mv.as_mv.col *= 8; |
+ mv.row *= 8; |
+ mv.col *= 8; |
this_error = motion_error; |
xd->mi[0]->mbmi.mode = NEWMV; |
- xd->mi[0]->mbmi.mv[0] = mv; |
+ xd->mi[0]->mbmi.mv[0].as_mv = mv; |
xd->mi[0]->mbmi.tx_size = TX_4X4; |
xd->mi[0]->mbmi.ref_frame[0] = LAST_FRAME; |
xd->mi[0]->mbmi.ref_frame[1] = NONE; |
vp9_build_inter_predictors_sby(xd, mb_row << 1, mb_col << 1, bsize); |
vp9_encode_sby_pass1(x, bsize); |
- sum_mvr += mv.as_mv.row; |
- sum_mvr_abs += abs(mv.as_mv.row); |
- sum_mvc += mv.as_mv.col; |
- sum_mvc_abs += abs(mv.as_mv.col); |
- sum_mvrs += mv.as_mv.row * mv.as_mv.row; |
- sum_mvcs += mv.as_mv.col * mv.as_mv.col; |
+ sum_mvr += mv.row; |
+ sum_mvr_abs += abs(mv.row); |
+ sum_mvc += mv.col; |
+ sum_mvc_abs += abs(mv.col); |
+ sum_mvrs += mv.row * mv.row; |
+ sum_mvcs += mv.col * mv.col; |
++intercount; |
- best_ref_mv.as_int = mv.as_int; |
+ best_ref_mv = mv; |
#if CONFIG_FP_MB_STATS |
if (cpi->use_fp_mb_stats) { |
@@ -740,7 +728,7 @@ |
} |
#endif |
- if (mv.as_int) { |
+ if (!is_zero_mv(&mv)) { |
++mvcount; |
#if CONFIG_FP_MB_STATS |
@@ -771,33 +759,33 @@ |
#endif |
// Non-zero vector, was it different from the last non zero vector? |
- if (mv.as_int != lastmv_as_int) |
+ if (!is_equal_mv(&mv, &lastmv)) |
++new_mv_count; |
- lastmv_as_int = mv.as_int; |
+ lastmv = mv; |
// Does the row vector point inwards or outwards? |
if (mb_row < cm->mb_rows / 2) { |
- if (mv.as_mv.row > 0) |
+ if (mv.row > 0) |
--sum_in_vectors; |
- else if (mv.as_mv.row < 0) |
+ else if (mv.row < 0) |
++sum_in_vectors; |
} else if (mb_row > cm->mb_rows / 2) { |
- if (mv.as_mv.row > 0) |
+ if (mv.row > 0) |
++sum_in_vectors; |
- else if (mv.as_mv.row < 0) |
+ else if (mv.row < 0) |
--sum_in_vectors; |
} |
// Does the col vector point inwards or outwards? |
if (mb_col < cm->mb_cols / 2) { |
- if (mv.as_mv.col > 0) |
+ if (mv.col > 0) |
--sum_in_vectors; |
- else if (mv.as_mv.col < 0) |
+ else if (mv.col < 0) |
++sum_in_vectors; |
} else if (mb_col > cm->mb_cols / 2) { |
- if (mv.as_mv.col > 0) |
+ if (mv.col > 0) |
++sum_in_vectors; |
- else if (mv.as_mv.col < 0) |
+ else if (mv.col < 0) |
--sum_in_vectors; |
} |
} |
@@ -865,7 +853,7 @@ |
// TODO(paulwilkins): Handle the case when duration is set to 0, or |
// something less than the full time between subsequent values of |
// cpi->source_time_stamp. |
- fps.duration = (double)(cpi->source->ts_end - cpi->source->ts_start); |
+ fps.duration = (double)(source->ts_end - source->ts_start); |
// Don't want to do output stats with a stack variable! |
twopass->this_frame_stats = fps; |
@@ -927,7 +915,7 @@ |
++cm->current_video_frame; |
if (cpi->use_svc) |
- vp9_inc_frame_in_layer(&cpi->svc); |
+ vp9_inc_frame_in_layer(cpi); |
} |
static double calc_correction_factor(double err_per_mb, |
@@ -965,7 +953,7 @@ |
BPER_MB_NORMBITS) / num_mbs; |
int q; |
int is_svc_upper_layer = 0; |
- if (is_spatial_svc(cpi) && cpi->svc.spatial_layer_id > 0) |
+ if (is_two_pass_svc(cpi) && cpi->svc.spatial_layer_id > 0) |
is_svc_upper_layer = 1; |
// Try and pick a max Q that will be high enough to encode the |
@@ -993,9 +981,9 @@ |
void vp9_init_second_pass(VP9_COMP *cpi) { |
SVC *const svc = &cpi->svc; |
const VP9EncoderConfig *const oxcf = &cpi->oxcf; |
- const int is_spatial_svc = (svc->number_spatial_layers > 1) && |
- (svc->number_temporal_layers == 1); |
- TWO_PASS *const twopass = is_spatial_svc ? |
+ const int is_two_pass_svc = (svc->number_spatial_layers > 1) || |
+ (svc->number_temporal_layers > 1); |
+ TWO_PASS *const twopass = is_two_pass_svc ? |
&svc->layer_context[svc->spatial_layer_id].twopass : &cpi->twopass; |
double frame_rate; |
FIRSTPASS_STATS *stats; |
@@ -1018,7 +1006,7 @@ |
// It is calculated based on the actual durations of all frames from the |
// first pass. |
- if (is_spatial_svc) { |
+ if (is_two_pass_svc) { |
vp9_update_spatial_layer_framerate(cpi, frame_rate); |
twopass->bits_left = (int64_t)(stats->duration * |
svc->layer_context[svc->spatial_layer_id].target_bandwidth / |
@@ -1033,7 +1021,7 @@ |
// scores used in the second pass. We have this minimum to make sure |
// that clips that are static but "low complexity" in the intra domain |
// are still boosted appropriately for KF/GF/ARF. |
- if (!is_spatial_svc) { |
+ if (!is_two_pass_svc) { |
// We don't know the number of MBs for each layer at this point. |
// So we will do it later. |
twopass->kf_intra_err_min = KF_MB_INTRA_MIN * cpi->common.MBs; |
@@ -1381,7 +1369,14 @@ |
int mid_boost_bits = 0; |
int mid_frame_idx; |
unsigned char arf_buffer_indices[MAX_ACTIVE_ARFS]; |
+ int alt_frame_index = frame_index; |
+ int has_temporal_layers = is_two_pass_svc(cpi) && |
+ cpi->svc.number_temporal_layers > 1; |
+ // Only encode alt reference frame in temporal base layer. |
+ if (has_temporal_layers) |
+ alt_frame_index = cpi->svc.number_temporal_layers; |
+ |
key_frame = cpi->common.frame_type == KEY_FRAME || |
vp9_is_upper_layer_key_frame(cpi); |
@@ -1416,16 +1411,24 @@ |
// Store the bits to spend on the ARF if there is one. |
if (rc->source_alt_ref_pending) { |
- gf_group->update_type[frame_index] = ARF_UPDATE; |
- gf_group->rf_level[frame_index] = GF_ARF_STD; |
- gf_group->bit_allocation[frame_index] = gf_arf_bits; |
- gf_group->arf_src_offset[frame_index] = |
- (unsigned char)(rc->baseline_gf_interval - 1); |
- gf_group->arf_update_idx[frame_index] = arf_buffer_indices[0]; |
- gf_group->arf_ref_idx[frame_index] = |
+ gf_group->update_type[alt_frame_index] = ARF_UPDATE; |
+ gf_group->rf_level[alt_frame_index] = GF_ARF_STD; |
+ gf_group->bit_allocation[alt_frame_index] = gf_arf_bits; |
+ |
+ if (has_temporal_layers) |
+ gf_group->arf_src_offset[alt_frame_index] = |
+ (unsigned char)(rc->baseline_gf_interval - |
+ cpi->svc.number_temporal_layers); |
+ else |
+ gf_group->arf_src_offset[alt_frame_index] = |
+ (unsigned char)(rc->baseline_gf_interval - 1); |
+ |
+ gf_group->arf_update_idx[alt_frame_index] = arf_buffer_indices[0]; |
+ gf_group->arf_ref_idx[alt_frame_index] = |
arf_buffer_indices[cpi->multi_arf_last_grp_enabled && |
rc->source_alt_ref_active]; |
- ++frame_index; |
+ if (!has_temporal_layers) |
+ ++frame_index; |
if (cpi->multi_arf_enabled) { |
// Set aside a slot for a level 1 arf. |
@@ -1448,6 +1451,10 @@ |
if (EOF == input_stats(twopass, &frame_stats)) |
break; |
+ if (has_temporal_layers && frame_index == alt_frame_index) { |
+ ++frame_index; |
+ } |
+ |
modified_err = calculate_modified_err(twopass, oxcf, &frame_stats); |
if (group_error > 0) |
@@ -1669,6 +1676,21 @@ |
else |
rc->baseline_gf_interval = i; |
+ // Only encode alt reference frame in temporal base layer. So |
+ // baseline_gf_interval should be multiple of a temporal layer group |
+ // (typically the frame distance between two base layer frames) |
+ if (is_two_pass_svc(cpi) && cpi->svc.number_temporal_layers > 1) { |
+ int count = (1 << (cpi->svc.number_temporal_layers - 1)) - 1; |
+ int new_gf_interval = (rc->baseline_gf_interval + count) & (~count); |
+ int j; |
+ for (j = 0; j < new_gf_interval - rc->baseline_gf_interval; ++j) { |
+ if (EOF == input_stats(twopass, this_frame)) |
+ break; |
+ gf_group_err += calculate_modified_err(twopass, oxcf, this_frame); |
+ } |
+ rc->baseline_gf_interval = new_gf_interval; |
+ } |
+ |
rc->frames_till_gf_update_due = rc->baseline_gf_interval; |
// Should we use the alternate reference frame. |
@@ -1874,16 +1896,17 @@ |
input_stats(twopass, this_frame); |
// Provided that we are not at the end of the file... |
- if (cpi->oxcf.auto_key && |
- lookup_next_frame_stats(twopass, &next_frame) != EOF) { |
+ if (cpi->oxcf.auto_key && twopass->stats_in < twopass->stats_in_end) { |
double loop_decay_rate; |
// Check for a scene cut. |
- if (test_candidate_kf(twopass, &last_frame, this_frame, &next_frame)) |
+ if (test_candidate_kf(twopass, &last_frame, this_frame, |
+ twopass->stats_in)) |
break; |
// How fast is the prediction quality decaying? |
- loop_decay_rate = get_prediction_decay_rate(&cpi->common, &next_frame); |
+ loop_decay_rate = get_prediction_decay_rate(&cpi->common, |
+ twopass->stats_in); |
// We want to know something about the recent past... rather than |
// as used elsewhere where we are concerned with decay in prediction |
@@ -1940,6 +1963,18 @@ |
rc->next_key_frame_forced = 0; |
} |
+ if (is_two_pass_svc(cpi) && cpi->svc.number_temporal_layers > 1) { |
+ int count = (1 << (cpi->svc.number_temporal_layers - 1)) - 1; |
+ int new_frame_to_key = (rc->frames_to_key + count) & (~count); |
+ int j; |
+ for (j = 0; j < new_frame_to_key - rc->frames_to_key; ++j) { |
+ if (EOF == input_stats(twopass, this_frame)) |
+ break; |
+ kf_group_err += calculate_modified_err(twopass, oxcf, this_frame); |
+ } |
+ rc->frames_to_key = new_frame_to_key; |
+ } |
+ |
// Special case for the last key frame of the file. |
if (twopass->stats_in >= twopass->stats_in_end) { |
// Accumulate kf group error. |
@@ -2098,7 +2133,7 @@ |
assert(0); |
break; |
} |
- if (is_spatial_svc(cpi)) { |
+ if (is_two_pass_svc(cpi)) { |
if (cpi->svc.layer_context[cpi->svc.spatial_layer_id].gold_ref_idx < 0) |
cpi->refresh_golden_frame = 0; |
if (cpi->alt_ref_source == NULL) |
@@ -2117,7 +2152,7 @@ |
FIRSTPASS_STATS this_frame_copy; |
int target_rate; |
- LAYER_CONTEXT *const lc = is_spatial_svc(cpi) ? |
+ LAYER_CONTEXT *const lc = is_two_pass_svc(cpi) ? |
&cpi->svc.layer_context[cpi->svc.spatial_layer_id] : 0; |
if (lc != NULL) { |
@@ -2200,15 +2235,18 @@ |
if (lc != NULL) { |
if (cpi->svc.spatial_layer_id == 0) { |
lc->is_key_frame = (cm->frame_type == KEY_FRAME); |
- if (lc->is_key_frame) |
+ if (lc->is_key_frame) { |
cpi->ref_frame_flags &= |
(~VP9_LAST_FLAG & ~VP9_GOLD_FLAG & ~VP9_ALT_FLAG); |
+ lc->frames_from_key_frame = 0; |
+ } |
} else { |
cm->frame_type = INTER_FRAME; |
lc->is_key_frame = cpi->svc.layer_context[0].is_key_frame; |
if (lc->is_key_frame) { |
cpi->ref_frame_flags &= (~VP9_LAST_FLAG); |
+ lc->frames_from_key_frame = 0; |
} |
} |
} |