From 1942eeb8860bd1350e66a250cd684fa7705fb68c Mon Sep 17 00:00:00 2001 From: John Koleszar <jkoleszar@google.com> Date: Thu, 6 Jan 2011 13:07:39 -0500 Subject: [PATCH 1/4] fix last frame buffer copy logic regression Commit 0ce3901 introduced a change in the frame buffer copy logic where the NEW frame could be copied to the ARF or GF buffer through the copy_buffer_to_{arf,gf}==1 flags, if the LAST frame was not being refreshed. This is not correct. The intent of the copy_buffer_to_{arf,gf}==1 flag is to copy the LAST buffer. To copy the NEW buffer, the refresh_{alt_ref,golden}_frame flag should be used. The original buffer copy logic is fairly convoluted. For example: if (cm->refresh_last_frame) { vp8_swap_yv12_buffer(&cm->last_frame, &cm->new_frame); cm->frame_to_show = &cm->last_frame; } else { cm->frame_to_show = &cm->new_frame; } ... if (cm->copy_buffer_to_arf) { if (cm->copy_buffer_to_arf == 1) { if (cm->refresh_last_frame) vp8_yv12_copy_frame_ptr(&cm->new_frame, &cm->alt_ref_frame); else vp8_yv12_copy_frame_ptr(&cm->last_frame, &cm->alt_ref_frame); } else if (cm->copy_buffer_to_arf == 2) vp8_yv12_copy_frame_ptr(&cm->golden_frame, &cm->alt_ref_frame); } Effectively, if refresh_last_frame, then new and last are swapped, so when "new" is copied to ARF, it's equivalent to copying LAST to ARF. If not refresh_last_frame, then LAST is copied to ARF. So LAST is copied to ARF in both cases. Commit 0ce3901 removed the first buffer swap but kept the refresh_last_frame?new:last behavior, changing the sense since the first swap wasn't done to the more readable refresh_last_frame?last:new, but this logic is not correct when !refresh_last_frame. This commit restores the correct behavior from v0.9.1 and prior. This case is missing from the test vector set. Change-Id: I8369fc13a37ae882e31a8a104da808a08bc8428f --- vp8/decoder/onyxd_if.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/vp8/decoder/onyxd_if.c b/vp8/decoder/onyxd_if.c index aa2709f5b..adc9f8ec8 100644 --- a/vp8/decoder/onyxd_if.c +++ b/vp8/decoder/onyxd_if.c @@ -254,12 +254,7 @@ static void ref_cnt_fb (int *buf, int *idx, int new_idx) /* If any buffer copy / swapping is signalled it should be done here. */ static int swap_frame_buffers (VP8_COMMON *cm) { - int fb_to_update_with, err = 0; - - if (cm->refresh_last_frame) - fb_to_update_with = cm->lst_fb_idx; - else - fb_to_update_with = cm->new_fb_idx; + int err = 0; /* The alternate reference frame or golden frame can be updated * using the new, last, or golden/alt ref frame. If it @@ -271,7 +266,7 @@ static int swap_frame_buffers (VP8_COMMON *cm) int new_fb = 0; if (cm->copy_buffer_to_arf == 1) - new_fb = fb_to_update_with; + new_fb = cm->lst_fb_idx; else if (cm->copy_buffer_to_arf == 2) new_fb = cm->gld_fb_idx; else @@ -285,7 +280,7 @@ static int swap_frame_buffers (VP8_COMMON *cm) int new_fb = 0; if (cm->copy_buffer_to_gf == 1) - new_fb = fb_to_update_with; + new_fb = cm->lst_fb_idx; else if (cm->copy_buffer_to_gf == 2) new_fb = cm->alt_fb_idx; else From cb791aaa2f6faf0ceb2c8a84e0ae6e5ec7758f90 Mon Sep 17 00:00:00 2001 From: Attila Nagy <attilanagy@google.com> Date: Mon, 10 Jan 2011 11:14:10 +0200 Subject: [PATCH 2/4] Fix encoder real-time only configuration. Remove allocation/deallocation of stats storage. Remove full search functions in machine specific encoder inits. Remove last pass validation in validate_config. Change-Id: I7f29be69273981a4fef6e80ecdb6217c68cbad4e --- vp8/encoder/generic/csystemdependent.c | 3 ++- vp8/encoder/mcomp.c | 4 ++-- vp8/encoder/onyx_if.c | 12 ++++++------ vp8/encoder/x86/x86_csystemdependent.c | 5 ++++- vp8/vp8_cx_iface.c | 2 ++ 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/vp8/encoder/generic/csystemdependent.c b/vp8/encoder/generic/csystemdependent.c index be00d0218..4738a5b28 100644 --- a/vp8/encoder/generic/csystemdependent.c +++ b/vp8/encoder/generic/csystemdependent.c @@ -91,8 +91,9 @@ void vp8_cmachine_specific_config(VP8_COMP *cpi) cpi->rtcd.quantize.quantb = vp8_regular_quantize_b; cpi->rtcd.quantize.fastquantb = vp8_fast_quantize_b_c; - +#if !(CONFIG_REALTIME_ONLY) cpi->rtcd.search.full_search = vp8_full_search_sad; +#endif cpi->rtcd.search.diamond_search = vp8_diamond_search_sad; cpi->rtcd.temporal.apply = vp8_temporal_filter_apply_c; diff --git a/vp8/encoder/mcomp.c b/vp8/encoder/mcomp.c index 9b91739cc..d9923fbe9 100644 --- a/vp8/encoder/mcomp.c +++ b/vp8/encoder/mcomp.c @@ -408,6 +408,7 @@ int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, MV *bestmv, diag = vfp->svf_halfpix_hv(y - 1, d->pre_stride, z, b->src_stride, &sse); break; case 3: + default: this_mv.col += 4; this_mv.row += 4; diag = vfp->svf_halfpix_hv(y, d->pre_stride, z, b->src_stride, &sse); @@ -1387,8 +1388,6 @@ int vp8_full_search_sadx3(MACROBLOCK *x, BLOCK *b, BLOCKD *d, MV *ref_mv, int er else return INT_MAX; } -#endif - int vp8_full_search_sadx8(MACROBLOCK *x, BLOCK *b, BLOCKD *d, MV *ref_mv, int error_per_bit, int distance, vp8_variance_fn_ptr_t *fn_ptr, int *mvcost[2], int *mvsadcost[2], MV *center_mv) { @@ -1541,6 +1540,7 @@ int vp8_full_search_sadx8(MACROBLOCK *x, BLOCK *b, BLOCKD *d, MV *ref_mv, int er else return INT_MAX; } +#endif /* !(CONFIG_REALTIME_ONLY) */ #ifdef ENTROPY_STATS void print_mode_context(void) diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c index 47fc3f78e..b7aa507f5 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c @@ -314,7 +314,7 @@ void vp8_dealloc_compressor_data(VP8_COMP *cpi) vpx_free(cpi->tok); cpi->tok = 0; - // Structure used to minitor GF useage + // Structure used to monitor GF usage if (cpi->gf_active_flags != 0) vpx_free(cpi->gf_active_flags); @@ -325,6 +325,7 @@ void vp8_dealloc_compressor_data(VP8_COMP *cpi) cpi->mb.pip = 0; +#if !(CONFIG_REALTIME_ONLY) if(cpi->total_stats) vpx_free(cpi->total_stats); @@ -334,6 +335,7 @@ void vp8_dealloc_compressor_data(VP8_COMP *cpi) vpx_free(cpi->this_frame_stats); cpi->this_frame_stats = 0; +#endif } static void enable_segmentation(VP8_PTR ptr) @@ -1448,6 +1450,7 @@ void vp8_alloc_compressor_data(VP8_COMP *cpi) cpi->gf_active_count = cm->mb_rows * cm->mb_cols; +#if !(CONFIG_REALTIME_ONLY) if(cpi->total_stats) vpx_free(cpi->total_stats); @@ -1461,6 +1464,7 @@ void vp8_alloc_compressor_data(VP8_COMP *cpi) if(!cpi->total_stats || !cpi->this_frame_stats) vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, "Failed to allocate firstpass stats"); +#endif } @@ -3150,8 +3154,8 @@ static void update_alt_ref_frame_and_stats(VP8_COMP *cpi) // Update data structure that monitors level of reference to last GF vpx_memset(cpi->gf_active_flags, 1, (cm->mb_rows * cm->mb_cols)); cpi->gf_active_count = cm->mb_rows * cm->mb_cols; - // this frame refreshes means next frames don't unless specified by user + // this frame refreshes means next frames don't unless specified by user cpi->common.frames_since_golden = 0; // Clear the alternate reference update pending flag. @@ -4362,10 +4366,6 @@ static void encode_frame_to_data_rate IF_RTCD(&cpi->rtcd.variance)); } - // Update the GF useage maps. - // This is done after completing the compression of a frame when all modes etc. are finalized but before loop filter - vp8_update_gf_useage_maps(cpi, cm, &cpi->mb); - // This frame's MVs are saved and will be used in next frame's MV prediction. if(cm->show_frame) //do not save for altref frame { diff --git a/vp8/encoder/x86/x86_csystemdependent.c b/vp8/encoder/x86/x86_csystemdependent.c index c7dffc443..f9b3ea1d8 100644 --- a/vp8/encoder/x86/x86_csystemdependent.c +++ b/vp8/encoder/x86/x86_csystemdependent.c @@ -323,8 +323,9 @@ void vp8_arch_x86_encoder_init(VP8_COMP *cpi) cpi->rtcd.variance.sad8x16x3 = vp8_sad8x16x3_sse3; cpi->rtcd.variance.sad8x8x3 = vp8_sad8x8x3_sse3; cpi->rtcd.variance.sad4x4x3 = vp8_sad4x4x3_sse3; +#if !(CONFIG_REALTIME_ONLY) cpi->rtcd.search.full_search = vp8_full_search_sadx3; - +#endif cpi->rtcd.variance.sad16x16x4d = vp8_sad16x16x4d_sse3; cpi->rtcd.variance.sad16x8x4d = vp8_sad16x8x4d_sse3; cpi->rtcd.variance.sad8x16x4d = vp8_sad8x16x4d_sse3; @@ -353,7 +354,9 @@ void vp8_arch_x86_encoder_init(VP8_COMP *cpi) cpi->rtcd.variance.sad8x16x8 = vp8_sad8x16x8_sse4; cpi->rtcd.variance.sad8x8x8 = vp8_sad8x8x8_sse4; cpi->rtcd.variance.sad4x4x8 = vp8_sad4x4x8_sse4; +#if !(CONFIG_REALTIME_ONLY) cpi->rtcd.search.full_search = vp8_full_search_sadx8; +#endif } #endif diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c index 1c9009a57..903c56c88 100644 --- a/vp8/vp8_cx_iface.c +++ b/vp8/vp8_cx_iface.c @@ -194,6 +194,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK(vp8_cfg, arnr_type, 1, 3); RANGE_CHECK(vp8_cfg, cq_level, 0, 63); +#if !(CONFIG_REALTIME_ONLY) if (cfg->g_pass == VPX_RC_LAST_PASS) { int mb_r = (cfg->g_h + 15) / 16; @@ -217,6 +218,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, if ((int)(stats->count + 0.5) != n_packets - 1) ERROR("rc_twopass_stats_in missing EOS stats packet"); } +#endif return VPX_CODEC_OK; } From 57136a268ab52d2874aa75859e43f663ca98e67c Mon Sep 17 00:00:00 2001 From: Paul Wilkins <paulwilkins@google.com> Date: Tue, 18 Jan 2011 15:19:05 +0000 Subject: [PATCH 3/4] Further CQ, Key frame and ARF changes This code fixes a bug in the calculation of the minimum Q for alt ref frames. It also allows an extended gf/arf interval for sections of clips that completely static (or nearly so). Change-Id: I1a21aaa16d4f0578e5f99b13bebd78d59403c73b --- vp8/encoder/encodeframe.c | 2 -- vp8/encoder/firstpass.c | 18 ++++++++++-------- vp8/encoder/onyx_if.c | 36 +++++++++++++++++++++++++----------- vp8/encoder/onyx_int.h | 1 + 4 files changed, 36 insertions(+), 21 deletions(-) diff --git a/vp8/encoder/encodeframe.c b/vp8/encoder/encodeframe.c index 2a89c59f4..4c95f28d6 100644 --- a/vp8/encoder/encodeframe.c +++ b/vp8/encoder/encodeframe.c @@ -710,9 +710,7 @@ void vp8_encode_frame(VP8_COMP *cpi) } vp8_initialize_rd_consts(cpi, vp8_dc_quant(cm->base_qindex, cm->y1dc_delta_q)); - //vp8_initialize_rd_consts( cpi, vp8_dc_quant(cpi->avg_frame_qindex, cm->y1dc_delta_q) ); vp8cx_initialize_me_consts(cpi, cm->base_qindex); - //vp8cx_initialize_me_consts( cpi, cpi->avg_frame_qindex); // Copy data over into macro block data sturctures. diff --git a/vp8/encoder/firstpass.c b/vp8/encoder/firstpass.c index c59613838..32a39c5f2 100644 --- a/vp8/encoder/firstpass.c +++ b/vp8/encoder/firstpass.c @@ -1375,7 +1375,7 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) // what level of boost is appropriate for the GF or ARF that will be coded with the group i = 0; - while (((i < cpi->max_gf_interval) || ((cpi->frames_to_key - i) < MIN_GF_INTERVAL)) && (i < cpi->frames_to_key)) + while (((i < cpi->static_scene_max_gf_interval) || ((cpi->frames_to_key - i) < MIN_GF_INTERVAL)) && (i < cpi->frames_to_key)) { double r; double this_frame_mvr_ratio; @@ -1485,18 +1485,20 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) boost_score += (decay_accumulator * r); // Break out conditions. - if ( /* i>4 || */ + if ( /* i>4 || */ + // Break at cpi->max_gf_interval unless almost totally static + (i >= cpi->max_gf_interval && (loop_decay_rate < 0.99)) || ( - (i > MIN_GF_INTERVAL) && // Dont break out with a very short interval - ((cpi->frames_to_key - i) >= MIN_GF_INTERVAL) && // Dont break out very close to a key frame + // Dont break out with a very short interval + (i > MIN_GF_INTERVAL) && + // Dont break out very close to a key frame + ((cpi->frames_to_key - i) >= MIN_GF_INTERVAL) && ((boost_score > 20.0) || (next_frame.pcnt_inter < 0.75)) && ((mv_ratio_accumulator > 100.0) || (abs_mv_in_out_accumulator > 3.0) || (mv_in_out_accumulator < -2.0) || - ((boost_score - old_boost_score) < 2.0) - ) - ) - ) + ((boost_score - old_boost_score) < 2.0)) + ) ) { boost_score = old_boost_score; break; diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c index 47fc3f78e..846ebb4bb 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c @@ -1497,21 +1497,25 @@ void vp8_new_frame_rate(VP8_COMP *cpi, double framerate) cpi->per_frame_bandwidth = (int)(cpi->oxcf.target_bandwidth / cpi->output_frame_rate); cpi->av_per_frame_bandwidth = (int)(cpi->oxcf.target_bandwidth / cpi->output_frame_rate); cpi->min_frame_bandwidth = (int)(cpi->av_per_frame_bandwidth * cpi->oxcf.two_pass_vbrmin_section / 100); - cpi->max_gf_interval = (int)(cpi->output_frame_rate / 2) + 2; - //cpi->max_gf_interval = (int)(cpi->output_frame_rate * 2 / 3) + 1; - //cpi->max_gf_interval = 24; + // Set Maximum gf/arf interval + cpi->max_gf_interval = max(((int)(cpi->output_frame_rate / 2.0) + 2), 12); - if (cpi->max_gf_interval < 12) - cpi->max_gf_interval = 12; + // Extended interval for genuinely static scenes + cpi->static_scene_max_gf_interval = cpi->key_frame_frequency >> 1; - - // Special conditions when altr ref frame enabled in lagged compress mode + // Special conditions when altr ref frame enabled in lagged compress mode if (cpi->oxcf.play_alternate && cpi->oxcf.lag_in_frames) { if (cpi->max_gf_interval > cpi->oxcf.lag_in_frames - 1) cpi->max_gf_interval = cpi->oxcf.lag_in_frames - 1; + + if (cpi->static_scene_max_gf_interval > cpi->oxcf.lag_in_frames - 1) + cpi->static_scene_max_gf_interval = cpi->oxcf.lag_in_frames - 1; } + + if ( cpi->max_gf_interval > cpi->static_scene_max_gf_interval ) + cpi->max_gf_interval = cpi->static_scene_max_gf_interval; } @@ -3846,9 +3850,21 @@ static void encode_frame_to_data_rate else if (cm->refresh_golden_frame || cpi->common.refresh_alt_ref_frame) { - if (cpi->avg_frame_qindex < cpi->active_worst_quality) + // Use the lower of cpi->active_worst_quality and recent + // average Q as basis for GF/ARF Q limit unless last frame was + // a key frame. + if ( (cpi->frames_since_key > 1) && + (cpi->avg_frame_qindex < cpi->active_worst_quality) ) + { Q = cpi->avg_frame_qindex; + if ( (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) && + (Q < cpi->oxcf.cq_level) ) + { + Q = cpi->oxcf.cq_level; + } + } + if ( cpi->pass == 2 ) { if ( cpi->gfu_boost > 1000 ) @@ -4528,9 +4544,7 @@ static void encode_frame_to_data_rate } // Keep a record of ambient average Q. - if (cm->frame_type == KEY_FRAME) - cpi->avg_frame_qindex = cm->base_qindex; - else + if (cm->frame_type != KEY_FRAME) cpi->avg_frame_qindex = (2 + 3 * cpi->avg_frame_qindex + cm->base_qindex) >> 2; // Keep a record from which we can calculate the average Q excluding GF updates and key frames diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h index 45fafd5b6..8a97e983b 100644 --- a/vp8/encoder/onyx_int.h +++ b/vp8/encoder/onyx_int.h @@ -402,6 +402,7 @@ typedef struct int kf_overspend_bits; // Extra bits spent on key frames that need to be recovered on inter frames int kf_bitrate_adjustment; // Current number of bit s to try and recover on each inter frame. int max_gf_interval; + int static_scene_max_gf_interval; int baseline_gf_interval; int gf_decay_rate; int active_arnr_frames; // <= cpi->oxcf.arnr_max_frames From edcf74c6add3b64fe7bd931194bcb9ebbfa3413a Mon Sep 17 00:00:00 2001 From: Jim Bankoski <jimbankoski@google.com> Date: Tue, 18 Jan 2011 11:14:17 -0500 Subject: [PATCH 4/4] vp8e -removed undefined max call Change-Id: I42a86b0488f44115f09551fc5ad6d711fd470f0d --- vp8/encoder/onyx_if.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c index 4f0be78fe..77fbb29b1 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c @@ -1503,7 +1503,10 @@ void vp8_new_frame_rate(VP8_COMP *cpi, double framerate) cpi->min_frame_bandwidth = (int)(cpi->av_per_frame_bandwidth * cpi->oxcf.two_pass_vbrmin_section / 100); // Set Maximum gf/arf interval - cpi->max_gf_interval = max(((int)(cpi->output_frame_rate / 2.0) + 2), 12); + cpi->max_gf_interval = ((int)(cpi->output_frame_rate / 2.0) + 2); + + if(cpi->max_gf_interval < 12) + cpi->max_gf_interval = 12; // Extended interval for genuinely static scenes cpi->static_scene_max_gf_interval = cpi->key_frame_frequency >> 1;