Index: source/libvpx/vp9/encoder/vp9_firstpass.c |
=================================================================== |
--- source/libvpx/vp9/encoder/vp9_firstpass.c (revision 290053) |
+++ source/libvpx/vp9/encoder/vp9_firstpass.c (working copy) |
@@ -22,7 +22,6 @@ |
#include "vp9/common/vp9_quant_common.h" |
#include "vp9/common/vp9_reconinter.h" // vp9_setup_dst_planes() |
#include "vp9/common/vp9_systemdependent.h" |
- |
#include "vp9/encoder/vp9_aq_variance.h" |
#include "vp9/encoder/vp9_block.h" |
#include "vp9/encoder/vp9_encodeframe.h" |
@@ -56,7 +55,6 @@ |
#define MIN_KF_BOOST 300 |
#define MIN_GF_INTERVAL 4 |
-#define LONG_TERM_VBR_CORRECTION |
static void swap_yv12(YV12_BUFFER_CONFIG *a, YV12_BUFFER_CONFIG *b) { |
YV12_BUFFER_CONFIG temp = *a; |
@@ -225,27 +223,7 @@ |
section->duration -= frame->duration; |
} |
-static void avg_stats(FIRSTPASS_STATS *section) { |
- if (section->count < 1.0) |
- return; |
- section->intra_error /= section->count; |
- section->coded_error /= section->count; |
- section->sr_coded_error /= section->count; |
- section->pcnt_inter /= section->count; |
- section->pcnt_second_ref /= section->count; |
- section->pcnt_neutral /= section->count; |
- section->pcnt_motion /= section->count; |
- section->MVr /= section->count; |
- section->mvr_abs /= section->count; |
- section->MVc /= section->count; |
- section->mvc_abs /= section->count; |
- section->MVrv /= section->count; |
- section->MVcv /= section->count; |
- section->mv_in_out_count /= section->count; |
- section->duration /= section->count; |
-} |
- |
// Calculate a modified Error used in distributing bits between easier and |
// harder frames. |
static double calculate_modified_err(const TWO_PASS *twopass, |
@@ -278,7 +256,7 @@ |
} |
void vp9_end_first_pass(VP9_COMP *cpi) { |
- if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) { |
+ if (is_spatial_svc(cpi)) { |
int i; |
for (i = 0; i < cpi->svc.number_spatial_layers; ++i) { |
output_stats(&cpi->svc.layer_context[i].twopass.total_stats, |
@@ -466,7 +444,7 @@ |
set_first_pass_params(cpi); |
vp9_set_quantizer(cm, find_fp_qindex()); |
- if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) { |
+ if (is_spatial_svc(cpi)) { |
MV_REFERENCE_FRAME ref_frame = LAST_FRAME; |
const YV12_BUFFER_CONFIG *scaled_ref_buf = NULL; |
twopass = &cpi->svc.layer_context[cpi->svc.spatial_layer_id].twopass; |
@@ -553,6 +531,9 @@ |
const int use_dc_pred = (mb_col || mb_row) && (!mb_col || !mb_row); |
double error_weight = 1.0; |
const BLOCK_SIZE bsize = get_bsize(cm, mb_row, mb_col); |
+#if CONFIG_FP_MB_STATS |
+ const int mb_index = mb_row * cm->mb_cols + mb_col; |
+#endif |
vp9_clear_system_state(); |
@@ -599,7 +580,8 @@ |
#if CONFIG_FP_MB_STATS |
if (cpi->use_fp_mb_stats) { |
- // TODO(pengchong): store some related block statistics here |
+ // initialization |
+ cpi->twopass.frame_mb_stats_buf[mb_index] = 0; |
} |
#endif |
@@ -631,8 +613,7 @@ |
&unscaled_last_source_buf_2d); |
// TODO(pengchong): Replace the hard-coded threshold |
- if (raw_motion_error > 25 || |
- (cpi->use_svc && cpi->svc.number_temporal_layers == 1)) { |
+ if (raw_motion_error > 25 || is_spatial_svc(cpi)) { |
// 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, |
@@ -700,6 +681,20 @@ |
// Start by assuming that intra mode is best. |
best_ref_mv.as_int = 0; |
+#if CONFIG_FP_MB_STATS |
+ if (cpi->use_fp_mb_stats) { |
+ // intra predication statistics |
+ cpi->twopass.frame_mb_stats_buf[mb_index] = 0; |
+ cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_DCINTRA_MASK; |
+ cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_MOTION_ZERO_MASK; |
+ if (this_error > FPMB_ERROR_LARGE_TH) { |
+ cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_ERROR_LARGE_MASK; |
+ } else if (this_error < FPMB_ERROR_SMALL_TH) { |
+ cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_ERROR_SMALL_MASK; |
+ } |
+ } |
+#endif |
+ |
if (motion_error <= this_error) { |
// Keep a count of cases where the inter and intra were very close |
// and very low. This helps with scene cut detection for example in |
@@ -730,13 +725,50 @@ |
#if CONFIG_FP_MB_STATS |
if (cpi->use_fp_mb_stats) { |
- // TODO(pengchong): save some related block statistics here |
+ // inter predication statistics |
+ cpi->twopass.frame_mb_stats_buf[mb_index] = 0; |
+ cpi->twopass.frame_mb_stats_buf[mb_index] &= ~FPMB_DCINTRA_MASK; |
+ cpi->twopass.frame_mb_stats_buf[mb_index] |= FPMB_MOTION_ZERO_MASK; |
+ if (this_error > FPMB_ERROR_LARGE_TH) { |
+ cpi->twopass.frame_mb_stats_buf[mb_index] |= |
+ FPMB_ERROR_LARGE_MASK; |
+ } else if (this_error < FPMB_ERROR_SMALL_TH) { |
+ cpi->twopass.frame_mb_stats_buf[mb_index] |= |
+ FPMB_ERROR_SMALL_MASK; |
+ } |
} |
#endif |
if (mv.as_int) { |
++mvcount; |
+#if CONFIG_FP_MB_STATS |
+ if (cpi->use_fp_mb_stats) { |
+ cpi->twopass.frame_mb_stats_buf[mb_index] &= |
+ ~FPMB_MOTION_ZERO_MASK; |
+ // check estimated motion direction |
+ if (mv.as_mv.col > 0 && mv.as_mv.col >= abs(mv.as_mv.row)) { |
+ // right direction |
+ cpi->twopass.frame_mb_stats_buf[mb_index] |= |
+ FPMB_MOTION_RIGHT_MASK; |
+ } else if (mv.as_mv.row < 0 && |
+ abs(mv.as_mv.row) >= abs(mv.as_mv.col)) { |
+ // up direction |
+ cpi->twopass.frame_mb_stats_buf[mb_index] |= |
+ FPMB_MOTION_UP_MASK; |
+ } else if (mv.as_mv.col < 0 && |
+ abs(mv.as_mv.col) >= abs(mv.as_mv.row)) { |
+ // left direction |
+ cpi->twopass.frame_mb_stats_buf[mb_index] |= |
+ FPMB_MOTION_LEFT_MASK; |
+ } else { |
+ // down direction |
+ cpi->twopass.frame_mb_stats_buf[mb_index] |= |
+ FPMB_MOTION_DOWN_MASK; |
+ } |
+ } |
+#endif |
+ |
// Non-zero vector, was it different from the last non zero vector? |
if (mv.as_int != lastmv_as_int) |
++new_mv_count; |
@@ -863,7 +895,7 @@ |
vp9_extend_frame_borders(new_yv12); |
- if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) { |
+ if (is_spatial_svc(cpi)) { |
vp9_update_reference_frames(cpi); |
} else { |
// Swap frame pointers so last frame refers to the frame we just compressed. |
@@ -929,13 +961,11 @@ |
const double err_per_mb = section_err / num_mbs; |
const double speed_term = 1.0 + 0.04 * oxcf->speed; |
const int target_norm_bits_per_mb = ((uint64_t)section_target_bandwidth << |
- BPER_MB_NORMBITS) / num_mbs; |
+ BPER_MB_NORMBITS) / num_mbs; |
int q; |
int is_svc_upper_layer = 0; |
- if (cpi->use_svc && cpi->svc.number_temporal_layers == 1 && |
- cpi->svc.spatial_layer_id > 0) { |
+ if (is_spatial_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 |
// content at the given rate. |
@@ -1049,6 +1079,19 @@ |
return MIN(second_ref_decay, next_frame->pcnt_inter); |
} |
+// This function gives an estimate of how badly we believe the prediction |
+// quality is decaying from frame to frame. |
+static double get_zero_motion_factor(const VP9_COMMON *cm, |
+ const FIRSTPASS_STATS *frame) { |
+ const double sr_ratio = frame->coded_error / |
+ DOUBLE_DIVIDE_CHECK(frame->sr_coded_error); |
+ const double zero_motion_pct = frame->pcnt_inter - |
+ frame->pcnt_motion; |
+ |
+ return MIN(sr_ratio, zero_motion_pct); |
+} |
+ |
+ |
// Function to test for a condition where a complex transition is followed |
// by a static section. For example in slide shows where there is a fade |
// between slides. This is to help with more optimal kf and gf positioning. |
@@ -1572,11 +1615,9 @@ |
decay_accumulator = decay_accumulator * loop_decay_rate; |
// Monitor for static sections. |
- if ((next_frame.pcnt_inter - next_frame.pcnt_motion) < |
- zero_motion_accumulator) { |
- zero_motion_accumulator = next_frame.pcnt_inter - |
- next_frame.pcnt_motion; |
- } |
+ zero_motion_accumulator = |
+ MIN(zero_motion_accumulator, |
+ get_zero_motion_factor(&cpi->common, &next_frame)); |
// Break clause to detect very still sections after motion. For example, |
// a static image after a fade or other transition. |
@@ -1946,11 +1987,9 @@ |
break; |
// Monitor for static sections. |
- if ((next_frame.pcnt_inter - next_frame.pcnt_motion) < |
- zero_motion_accumulator) { |
- zero_motion_accumulator = (next_frame.pcnt_inter - |
- next_frame.pcnt_motion); |
- } |
+ zero_motion_accumulator = |
+ MIN(zero_motion_accumulator, |
+ get_zero_motion_factor(&cpi->common, &next_frame)); |
// For the first few frames collect data to decide kf boost. |
if (i <= (rc->max_gf_interval * 2)) { |
@@ -2065,9 +2104,11 @@ |
break; |
default: |
assert(0); |
+ break; |
} |
- if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) { |
- cpi->refresh_golden_frame = 0; |
+ if (is_spatial_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) |
cpi->refresh_alt_ref_frame = 0; |
} |
@@ -2084,9 +2125,8 @@ |
int target_rate; |
LAYER_CONTEXT *lc = NULL; |
- const int is_spatial_svc = (cpi->use_svc && |
- cpi->svc.number_temporal_layers == 1); |
- if (is_spatial_svc) { |
+ |
+ if (is_spatial_svc(cpi)) { |
lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id]; |
frames_left = (int)(twopass->total_stats.count - |
lc->current_video_frame_in_layer); |
@@ -2106,15 +2146,15 @@ |
target_rate = twopass->gf_group.bit_allocation[twopass->gf_group.index]; |
target_rate = vp9_rc_clamp_pframe_target_size(cpi, target_rate); |
rc->base_frame_target = target_rate; |
-#ifdef LONG_TERM_VBR_CORRECTION |
+ |
// Correction to rate target based on prior over or under shoot. |
if (cpi->oxcf.rc_mode == VPX_VBR) |
vbr_rate_correction(&target_rate, rc->vbr_bits_off_target); |
-#endif |
+ |
vp9_rc_set_frame_target(cpi, target_rate); |
cm->frame_type = INTER_FRAME; |
- if (is_spatial_svc) { |
+ if (is_spatial_svc(cpi)) { |
if (cpi->svc.spatial_layer_id == 0) { |
lc->is_key_frame = 0; |
} else { |
@@ -2130,7 +2170,7 @@ |
vp9_clear_system_state(); |
- if (is_spatial_svc && twopass->kf_intra_err_min == 0) { |
+ if (is_spatial_svc(cpi) && twopass->kf_intra_err_min == 0) { |
twopass->kf_intra_err_min = KF_MB_INTRA_MIN * cpi->common.MBs; |
twopass->gf_intra_err_min = GF_MB_INTRA_MIN * cpi->common.MBs; |
} |
@@ -2138,7 +2178,8 @@ |
if (cpi->oxcf.rc_mode == VPX_Q) { |
twopass->active_worst_quality = cpi->oxcf.cq_level; |
} else if (cm->current_video_frame == 0 || |
- (is_spatial_svc && lc->current_video_frame_in_layer == 0)) { |
+ (is_spatial_svc(cpi) && |
+ lc->current_video_frame_in_layer == 0)) { |
// Special case code for first frame. |
const int section_target_bandwidth = (int)(twopass->bits_left / |
frames_left); |
@@ -2164,9 +2205,12 @@ |
cm->frame_type = INTER_FRAME; |
} |
- if (is_spatial_svc) { |
+ if (is_spatial_svc(cpi)) { |
if (cpi->svc.spatial_layer_id == 0) { |
lc->is_key_frame = (cm->frame_type == KEY_FRAME); |
+ if (lc->is_key_frame) |
+ cpi->ref_frame_flags &= |
+ (~VP9_LAST_FLAG & ~VP9_GOLD_FLAG & ~VP9_ALT_FLAG); |
} else { |
cm->frame_type = INTER_FRAME; |
lc->is_key_frame = cpi->svc.layer_context[0].is_key_frame; |
@@ -2192,7 +2236,7 @@ |
} |
rc->frames_till_gf_update_due = rc->baseline_gf_interval; |
- if (!is_spatial_svc) |
+ if (!is_spatial_svc(cpi)) |
cpi->refresh_golden_frame = 1; |
} |
@@ -2205,11 +2249,11 @@ |
target_rate = vp9_rc_clamp_pframe_target_size(cpi, target_rate); |
rc->base_frame_target = target_rate; |
-#ifdef LONG_TERM_VBR_CORRECTION |
+ |
// Correction to rate target based on prior over or under shoot. |
if (cpi->oxcf.rc_mode == VPX_VBR) |
vbr_rate_correction(&target_rate, rc->vbr_bits_off_target); |
-#endif |
+ |
vp9_rc_set_frame_target(cpi, target_rate); |
// Update the total stats remaining structure. |
@@ -2219,45 +2263,19 @@ |
void vp9_twopass_postencode_update(VP9_COMP *cpi) { |
TWO_PASS *const twopass = &cpi->twopass; |
RATE_CONTROL *const rc = &cpi->rc; |
-#ifdef LONG_TERM_VBR_CORRECTION |
- // In this experimental mode, the VBR correction is done exclusively through |
- // rc->vbr_bits_off_target. Based on the sign of this value, a limited % |
- // adjustment is made to the target rate of subsequent frames, to try and |
- // push it back towards 0. This mode is less likely to suffer from |
- // extreme behaviour at the end of a clip or group of frames. |
+ |
+ // VBR correction is done through rc->vbr_bits_off_target. Based on the |
+ // sign of this value, a limited % adjustment is made to the target rate |
+ // of subsequent frames, to try and push it back towards 0. This method |
+ // is designed to prevent extreme behaviour at the end of a clip |
+ // or group of frames. |
const int bits_used = rc->base_frame_target; |
rc->vbr_bits_off_target += rc->base_frame_target - rc->projected_frame_size; |
-#else |
- // In this mode, VBR correction is acheived by altering bits_left, |
- // kf_group_bits & gf_group_bits to reflect any deviation from the target |
- // rate in this frame. This alters the allocation of bits to the |
- // remaning frames in the group / clip. |
- // |
- // This method can give rise to unstable behaviour near the end of a clip |
- // or kf/gf group of frames where any accumulated error is corrected over an |
- // ever decreasing number of frames. Hence we change the balance of target |
- // vs. actual bitrate gradually as we progress towards the end of the |
- // sequence in order to mitigate this effect. |
- const double progress = |
- (double)(twopass->stats_in - twopass->stats_in_start) / |
- (twopass->stats_in_end - twopass->stats_in_start); |
- const int bits_used = (int)(progress * rc->this_frame_target + |
- (1.0 - progress) * rc->projected_frame_size); |
-#endif |
twopass->bits_left = MAX(twopass->bits_left - bits_used, 0); |
-#ifdef LONG_TERM_VBR_CORRECTION |
if (cpi->common.frame_type != KEY_FRAME && |
!vp9_is_upper_layer_key_frame(cpi)) { |
-#else |
- if (cpi->common.frame_type == KEY_FRAME || |
- vp9_is_upper_layer_key_frame(cpi)) { |
- // For key frames kf_group_bits already had the target bits subtracted out. |
- // So now update to the correct value based on the actual bits used. |
- twopass->kf_group_bits += rc->this_frame_target - bits_used; |
- } else { |
-#endif |
twopass->kf_group_bits -= bits_used; |
} |
twopass->kf_group_bits = MAX(twopass->kf_group_bits, 0); |