diff options
Diffstat (limited to 'vp8/encoder/firstpass.c')
-rw-r--r-- | vp8/encoder/firstpass.c | 224 |
1 files changed, 163 insertions, 61 deletions
diff --git a/vp8/encoder/firstpass.c b/vp8/encoder/firstpass.c index c59613838..3e67bf53c 100644 --- a/vp8/encoder/firstpass.c +++ b/vp8/encoder/firstpass.c @@ -1316,6 +1316,43 @@ void vp8_end_second_pass(VP8_COMP *cpi) { } +// This function gives and estimate of how badly we believe +// the predicition quality is decaying from frame to frame. +double gf_prediction_decay_rate(VP8_COMP *cpi, FIRSTPASS_STATS *next_frame) +{ + double prediction_decay_rate; + double motion_decay; + double motion_pct = next_frame->pcnt_motion; + + + // Initial basis is the % mbs inter coded + prediction_decay_rate = next_frame->pcnt_inter; + + // High % motion -> somewhat higher decay rate + motion_decay = (1.0 - (motion_pct / 20.0)); + if (motion_decay < prediction_decay_rate) + prediction_decay_rate = motion_decay; + + // Adjustment to decay rate based on speed of motion + { + double this_mv_rabs; + double this_mv_cabs; + double distance_factor; + + this_mv_rabs = fabs(next_frame->mvr_abs * motion_pct); + this_mv_cabs = fabs(next_frame->mvc_abs * motion_pct); + + distance_factor = sqrt((this_mv_rabs * this_mv_rabs) + + (this_mv_cabs * this_mv_cabs)) / 250.0; + distance_factor = ((distance_factor > 1.0) + ? 0.0 : (1.0 - distance_factor)); + if (distance_factor < prediction_decay_rate) + prediction_decay_rate = distance_factor; + } + + return prediction_decay_rate; +} + // Analyse and define a gf/arf group . static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) { @@ -1337,17 +1374,20 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) double decay_accumulator = 1.0; double boost_factor = IIFACTOR; - double loop_decay_rate = 1.00; // Starting decay rate + double loop_decay_rate = 1.00; // Starting decay rate double this_frame_mv_in_out = 0.0; double mv_in_out_accumulator = 0.0; double abs_mv_in_out_accumulator = 0.0; double mod_err_per_mb_accumulator = 0.0; - int max_bits = frame_max_bits(cpi); // Max for a single frame + int max_bits = frame_max_bits(cpi); // Max for a single frame unsigned char *fpmm_pos; + unsigned int allow_alt_ref = + cpi->oxcf.play_alternate && cpi->oxcf.lag_in_frames; + cpi->gf_group_bits = 0; cpi->gf_decay_rate = 0; @@ -1362,47 +1402,57 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) // Preload the stats for the next frame. mod_frame_err = calculate_modified_err(cpi, this_frame); - // Note the error of the frame at the start of the group (this will be the GF frame error if we code a normal gf + // Note the error of the frame at the start of the group (this will be + // the GF frame error if we code a normal gf gf_first_frame_err = mod_frame_err; - // Special treatment if the current frame is a key frame (which is also a gf). - // If it is then its error score (and hence bit allocation) need to be subtracted out - // from the calculation for the GF group + // Special treatment if the current frame is a key frame (which is also + // a gf). If it is then its error score (and hence bit allocation) need + // to be subtracted out from the calculation for the GF group if (cpi->common.frame_type == KEY_FRAME) gf_group_err -= gf_first_frame_err; - // Scan forward to try and work out how many frames the next gf group should contain and - // what level of boost is appropriate for the GF or ARF that will be coded with the group + // Scan forward to try and work out how many frames the next gf group + // should contain and 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; double this_frame_mvc_ratio; double motion_decay; - double motion_pct = next_frame.pcnt_motion; + //double motion_pct = next_frame.pcnt_motion; + double motion_pct; - i++; // Increment the loop counter + i++; // Increment the loop counter // Accumulate error score of frames in this gf group mod_frame_err = calculate_modified_err(cpi, this_frame); gf_group_err += mod_frame_err; - mod_err_per_mb_accumulator += mod_frame_err / DOUBLE_DIVIDE_CHECK((double)cpi->common.MBs); + mod_err_per_mb_accumulator += + mod_frame_err / DOUBLE_DIVIDE_CHECK((double)cpi->common.MBs); if (EOF == vp8_input_stats(cpi, &next_frame)) break; // Accumulate motion stats. + motion_pct = next_frame.pcnt_motion; mv_accumulator_rabs += fabs(next_frame.mvr_abs * motion_pct); mv_accumulator_cabs += fabs(next_frame.mvc_abs * motion_pct); //Accumulate Motion In/Out of frame stats - this_frame_mv_in_out = next_frame.mv_in_out_count * next_frame.pcnt_motion; - mv_in_out_accumulator += next_frame.mv_in_out_count * next_frame.pcnt_motion; - abs_mv_in_out_accumulator += fabs(next_frame.mv_in_out_count * next_frame.pcnt_motion); + this_frame_mv_in_out = + next_frame.mv_in_out_count * motion_pct; + mv_in_out_accumulator += + next_frame.mv_in_out_count * motion_pct; + abs_mv_in_out_accumulator += + fabs(next_frame.mv_in_out_count * motion_pct); // If there is a significant amount of motion if (motion_pct > 0.05) @@ -1431,7 +1481,9 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) } // Underlying boost factor is based on inter intra error ratio - r = (boost_factor * (next_frame.intra_error / DOUBLE_DIVIDE_CHECK(next_frame.coded_error))); + r = ( boost_factor * + ( next_frame.intra_error / + DOUBLE_DIVIDE_CHECK(next_frame.coded_error))); if (next_frame.intra_error > cpi->gf_intra_err_min) r = (IIKFACTOR2 * next_frame.intra_error / @@ -1440,63 +1492,87 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) r = (IIKFACTOR2 * cpi->gf_intra_err_min / DOUBLE_DIVIDE_CHECK(next_frame.coded_error)); - // Increase boost for frames where new data coming into frame (eg zoom out) - // Slightly reduce boost if there is a net balance of motion out of the frame (zoom in) + // Increase boost for frames where new data coming into frame + // (eg zoom out). Slightly reduce boost if there is a net balance + // of motion out of the frame (zoom in). // The range for this_frame_mv_in_out is -1.0 to +1.0 if (this_frame_mv_in_out > 0.0) r += r * (this_frame_mv_in_out * 2.0); + // In extreme case boost is halved else - r += r * (this_frame_mv_in_out / 2.0); // In extreme case boost is halved + r += r * (this_frame_mv_in_out / 2.0); if (r > GF_RMAX) r = GF_RMAX; - // Adjust loop decay rate - //if ( next_frame.pcnt_inter < loop_decay_rate ) - loop_decay_rate = next_frame.pcnt_inter; + loop_decay_rate = gf_prediction_decay_rate(cpi, &next_frame); - // High % motion -> somewhat higher decay rate - motion_decay = (1.0 - (motion_pct / 20.0)); - if (motion_decay < loop_decay_rate) - loop_decay_rate = motion_decay; + // Cumulative effect of decay + decay_accumulator = decay_accumulator * loop_decay_rate; + decay_accumulator = decay_accumulator < 0.1 ? 0.1 : decay_accumulator; - // Adjustment to decay rate based on speed of motion + boost_score += (decay_accumulator * r); + + // Break clause to detect very still sections after motion + // For example a staic image after a fade or other transition + // instead of a clean key frame. + if ( (i > MIN_GF_INTERVAL) && + (loop_decay_rate >= 0.999) && + (decay_accumulator < 0.9) ) { - double this_mv_rabs; - double this_mv_cabs; - double distance_factor; + int j; + FIRSTPASS_STATS * position = cpi->stats_in; + FIRSTPASS_STATS tmp_next_frame; + double decay_rate; + + // Look ahead a few frames to see if static condition + // persists... + for ( j = 0; j < 4; j++ ) + { + if (EOF == vp8_input_stats(cpi, &tmp_next_frame)) + break; - this_mv_rabs = fabs(next_frame.mvr_abs * motion_pct); - this_mv_cabs = fabs(next_frame.mvc_abs * motion_pct); + decay_rate = gf_prediction_decay_rate(cpi, &tmp_next_frame); + if ( decay_rate < 0.999 ) + break; + } + reset_fpf_position(cpi, position); // Reset file position - distance_factor = sqrt((this_mv_rabs * this_mv_rabs) + - (this_mv_cabs * this_mv_cabs)) / 250.0; - distance_factor = ((distance_factor > 1.0) - ? 0.0 : (1.0 - distance_factor)); - if (distance_factor < loop_decay_rate) - loop_decay_rate = distance_factor; - } + // Force GF not alt ref + if ( j == 4 ) + { + if (0) + { + FILE *f = fopen("fadegf.stt", "a"); + fprintf(f, " %8d %8d %10.4f %10.4f %10.4f\n", + cpi->common.current_video_frame+i, i, + loop_decay_rate, decay_accumulator, + boost_score ); + fclose(f); + } - // Cumulative effect of decay - decay_accumulator = decay_accumulator * loop_decay_rate; - decay_accumulator = decay_accumulator < 0.1 ? 0.1 : decay_accumulator; - //decay_accumulator = ( loop_decay_rate < decay_accumulator ) ? loop_decay_rate : decay_accumulator; + allow_alt_ref = FALSE; - boost_score += (decay_accumulator * r); + boost_score = old_boost_score; + break; + } + } // Break out conditions. - if ( /* i>4 || */ + if ( /* i>4 || */ + // Break at cpi->max_gf_interval unless almost totally static + (i >= cpi->max_gf_interval && (decay_accumulator < 0.995)) || ( - (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; @@ -1507,7 +1583,8 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) old_boost_score = boost_score; } - cpi->gf_decay_rate = (i > 0) ? (int)(100.0 * (1.0 - decay_accumulator)) / i : 0; + cpi->gf_decay_rate = + (i > 0) ? (int)(100.0 * (1.0 - decay_accumulator)) / i : 0; // When using CBR apply additional buffer related upper limits if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) @@ -1517,7 +1594,8 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) // For cbr apply buffer related limits if (cpi->drop_frames_allowed) { - int df_buffer_level = cpi->oxcf.drop_frames_water_mark * (cpi->oxcf.optimal_buffer_level / 100); + int df_buffer_level = cpi->oxcf.drop_frames_water_mark * + (cpi->oxcf.optimal_buffer_level / 100); if (cpi->buffer_level > df_buffer_level) max_boost = ((double)((cpi->buffer_level - df_buffer_level) * 2 / 3) * 16.0) / DOUBLE_DIVIDE_CHECK((double)cpi->av_per_frame_bandwidth); @@ -1540,10 +1618,10 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) cpi->gfu_boost = (int)(boost_score * 100.0) >> 4; // Should we use the alternate refernce frame - if (cpi->oxcf.play_alternate && - cpi->oxcf.lag_in_frames && + if (allow_alt_ref && (i >= MIN_GF_INTERVAL) && - (i <= (cpi->frames_to_key - MIN_GF_INTERVAL)) && // dont use ARF very near next kf + // dont use ARF very near next kf + (i <= (cpi->frames_to_key - MIN_GF_INTERVAL)) && (((next_frame.pcnt_inter > 0.75) && ((mv_in_out_accumulator / (double)i > -0.2) || (mv_in_out_accumulator > -2.0)) && //(cpi->gfu_boost>150) && @@ -2345,12 +2423,35 @@ void vp8_find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) if (cpi->oxcf.auto_key && cpi->frames_to_key > (int)cpi->key_frame_frequency ) { + int current_pos = cpi->stats_in; + FIRSTPASS_STATS tmp_frame; + cpi->frames_to_key /= 2; - // Estimate corrected kf group error - kf_group_err /= 2.0; - kf_group_intra_err /= 2.0; - kf_group_coded_err /= 2.0; + // Copy first frame details + vpx_memcpy(&tmp_frame, &first_frame, sizeof(first_frame)); + + // Reset to the start of the group + reset_fpf_position(cpi, start_position); + + kf_group_err = 0; + kf_group_intra_err = 0; + kf_group_coded_err = 0; + + // Rescan to get the correct error data for the forced kf group + for( i = 0; i < cpi->frames_to_key; i++ ) + { + // Accumulate kf group errors + kf_group_err += calculate_modified_err(cpi, &tmp_frame); + kf_group_intra_err += tmp_frame.intra_error; + kf_group_coded_err += tmp_frame.coded_error; + + // Load a the next frame's stats + vp8_input_stats(cpi, &tmp_frame); + } + + // Reset to the start of the group + reset_fpf_position(cpi, current_pos); cpi->next_key_frame_forced = TRUE; } @@ -2449,7 +2550,7 @@ void vp8_find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) { double r; double motion_decay; - double motion_pct = next_frame.pcnt_motion; + double motion_pct; if (EOF == vp8_input_stats(cpi, &next_frame)) break; @@ -2469,6 +2570,7 @@ void vp8_find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) loop_decay_rate = next_frame.pcnt_inter; // High % motion -> somewhat higher decay rate + motion_pct = next_frame.pcnt_motion; motion_decay = (1.0 - (motion_pct / 20.0)); if (motion_decay < loop_decay_rate) loop_decay_rate = motion_decay; |