summaryrefslogtreecommitdiff
path: root/vp8/encoder/firstpass.c
diff options
context:
space:
mode:
Diffstat (limited to 'vp8/encoder/firstpass.c')
-rw-r--r--vp8/encoder/firstpass.c188
1 files changed, 113 insertions, 75 deletions
diff --git a/vp8/encoder/firstpass.c b/vp8/encoder/firstpass.c
index d489413f6..804b80bd5 100644
--- a/vp8/encoder/firstpass.c
+++ b/vp8/encoder/firstpass.c
@@ -312,7 +312,9 @@ void vp8_output_stats(const VP8_COMP *cpi,
FILE *fpfile;
fpfile = fopen("firstpass.stt", "a");
- fprintf(fpfile, "%12.0f %12.0f %12.0f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.0f\n",
+ fprintf(fpfile, "%12.0f %12.0f %12.0f %12.4f %12.4f %12.4f %12.4f"
+ " %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.0f"
+ " %12.4f\n",
stats->frame,
stats->intra_error,
stats->coded_error,
@@ -320,6 +322,7 @@ void vp8_output_stats(const VP8_COMP *cpi,
stats->pcnt_inter,
stats->pcnt_motion,
stats->pcnt_second_ref,
+ stats->pcnt_neutral,
stats->MVr,
stats->mvr_abs,
stats->MVc,
@@ -327,7 +330,8 @@ void vp8_output_stats(const VP8_COMP *cpi,
stats->MVrv,
stats->MVcv,
stats->mv_in_out_count,
- stats->count);
+ stats->count,
+ stats->duration);
fclose(fpfile);
@@ -359,6 +363,7 @@ void vp8_zero_stats(FIRSTPASS_STATS *section)
section->pcnt_inter = 0.0;
section->pcnt_motion = 0.0;
section->pcnt_second_ref = 0.0;
+ section->pcnt_neutral = 0.0;
section->MVr = 0.0;
section->mvr_abs = 0.0;
section->MVc = 0.0;
@@ -378,6 +383,7 @@ void vp8_accumulate_stats(FIRSTPASS_STATS *section, FIRSTPASS_STATS *frame)
section->pcnt_inter += frame->pcnt_inter;
section->pcnt_motion += frame->pcnt_motion;
section->pcnt_second_ref += frame->pcnt_second_ref;
+ section->pcnt_neutral += frame->pcnt_neutral;
section->MVr += frame->MVr;
section->mvr_abs += frame->mvr_abs;
section->MVc += frame->MVc;
@@ -398,6 +404,7 @@ void vp8_avg_stats(FIRSTPASS_STATS *section)
section->ssim_weighted_pred_err /= 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;
@@ -570,6 +577,7 @@ void vp8_first_pass(VP8_COMP *cpi)
int intercount = 0;
int second_ref_count = 0;
int intrapenalty = 256;
+ int neutral_count = 0;
int sum_in_vectors = 0;
@@ -726,6 +734,17 @@ void vp8_first_pass(VP8_COMP *cpi)
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 cropped clips with black bars
+ // at the sides or top and bottom.
+ if( (((this_error-intrapenalty) * 9) <=
+ (motion_error*10)) &&
+ (this_error < (2*intrapenalty)) )
+ {
+ neutral_count++;
+ }
+
d->bmi.mv.as_mv.row <<= 3;
d->bmi.mv.as_mv.col <<= 3;
this_error = motion_error;
@@ -854,6 +873,7 @@ void vp8_first_pass(VP8_COMP *cpi)
fps.pcnt_inter = 1.0 * (double)intercount / cm->MBs;
fps.pcnt_second_ref = 1.0 * (double)second_ref_count / cm->MBs;
+ fps.pcnt_neutral = 1.0 * (double)neutral_count / cm->MBs;
if (mvcount > 0)
{
@@ -1341,7 +1361,7 @@ 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 get_prediction_decay_rate(VP8_COMP *cpi, FIRSTPASS_STATS *next_frame)
{
double prediction_decay_rate;
double motion_decay;
@@ -1376,6 +1396,52 @@ double gf_prediction_decay_rate(VP8_COMP *cpi, FIRSTPASS_STATS *next_frame)
return prediction_decay_rate;
}
+// 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.
+BOOL detect_transition_to_still(
+ VP8_COMP *cpi,
+ int frame_interval,
+ int still_interval,
+ double loop_decay_rate,
+ double decay_accumulator )
+{
+ BOOL trans_to_still = FALSE;
+
+ // Break clause to detect very still sections after motion
+ // For example a static image after a fade or other transition
+ // instead of a clean scene cut.
+ if ( (frame_interval > MIN_GF_INTERVAL) &&
+ (loop_decay_rate >= 0.999) &&
+ (decay_accumulator < 0.9) )
+ {
+ 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 < still_interval; j++ )
+ {
+ if (EOF == vp8_input_stats(cpi, &tmp_next_frame))
+ break;
+
+ decay_rate = get_prediction_decay_rate(cpi, &tmp_next_frame);
+ if ( decay_rate < 0.999 )
+ break;
+ }
+ // Reset file position
+ reset_fpf_position(cpi, position);
+
+ // Only if it does do we signal a transition to still
+ if ( j == still_interval )
+ trans_to_still = TRUE;
+ }
+
+ return trans_to_still;
+}
+
// Analyse and define a gf/arf group .
static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame)
{
@@ -1528,7 +1594,7 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame)
if (r > GF_RMAX)
r = GF_RMAX;
- loop_decay_rate = gf_prediction_decay_rate(cpi, &next_frame);
+ loop_decay_rate = get_prediction_decay_rate(cpi, &next_frame);
// Cumulative effect of decay
decay_accumulator = decay_accumulator * loop_decay_rate;
@@ -1537,48 +1603,13 @@ static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame)
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) )
+ // For example a staic image after a fade or other transition.
+ if ( detect_transition_to_still( cpi, i, 5,
+ loop_decay_rate, decay_accumulator ) )
{
- 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;
-
- decay_rate = gf_prediction_decay_rate(cpi, &tmp_next_frame);
- if ( decay_rate < 0.999 )
- break;
- }
- reset_fpf_position(cpi, position); // Reset file position
-
- // 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);
- }
-
- allow_alt_ref = FALSE;
-
- boost_score = old_boost_score;
- break;
- }
+ allow_alt_ref = FALSE;
+ boost_score = old_boost_score;
+ break;
}
// Break out conditions.
@@ -2285,7 +2316,7 @@ static BOOL test_candidate_kf(VP8_COMP *cpi, FIRSTPASS_STATS *last_frame, FIRST
(next_frame->pcnt_second_ref < 0.10) &&
((this_frame->pcnt_inter < 0.05) ||
(
- (this_frame->pcnt_inter < .25) &&
+ ((this_frame->pcnt_inter - this_frame->pcnt_neutral) < .25) &&
((this_frame->intra_error / DOUBLE_DIVIDE_CHECK(this_frame->coded_error)) < 2.5) &&
((fabs(last_frame->coded_error - this_frame->coded_error) / DOUBLE_DIVIDE_CHECK(this_frame->coded_error) > .40) ||
(fabs(last_frame->intra_error - this_frame->intra_error) / DOUBLE_DIVIDE_CHECK(this_frame->intra_error) > .40) ||
@@ -2332,7 +2363,9 @@ static BOOL test_candidate_kf(VP8_COMP *cpi, FIRSTPASS_STATS *last_frame, FIRST
// Test various breakout clauses
if ((local_next_frame.pcnt_inter < 0.05) ||
(next_iiratio < 1.5) ||
- ((local_next_frame.pcnt_inter < 0.20) && (next_iiratio < 3.0)) ||
+ (((local_next_frame.pcnt_inter -
+ local_next_frame.pcnt_neutral) < 0.20) &&
+ (next_iiratio < 3.0)) ||
((boost_score - old_boost_score) < 0.5) ||
(local_next_frame.intra_error < 200)
)
@@ -2363,13 +2396,13 @@ static BOOL test_candidate_kf(VP8_COMP *cpi, FIRSTPASS_STATS *last_frame, FIRST
}
void vp8_find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame)
{
- int i;
+ int i,j;
FIRSTPASS_STATS last_frame;
FIRSTPASS_STATS first_frame;
FIRSTPASS_STATS next_frame;
FIRSTPASS_STATS *start_position;
- double decay_accumulator = 0;
+ double decay_accumulator = 1.0;
double boost_score = 0;
double old_boost_score = 0.0;
double loop_decay_rate;
@@ -2379,6 +2412,7 @@ void vp8_find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame)
double kf_group_intra_err = 0.0;
double kf_group_coded_err = 0.0;
double two_pass_min_rate = (double)(cpi->oxcf.target_bandwidth * cpi->oxcf.two_pass_vbrmin_section / 100);
+ double recent_loop_decay[8] = {1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0};
vpx_memset(&next_frame, 0, sizeof(next_frame)); // assure clean
@@ -2407,6 +2441,7 @@ void vp8_find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame)
kf_mod_err = calculate_modified_err(cpi, this_frame);
// find the next keyframe
+ i = 0;
while (cpi->stats_in < cpi->stats_in_end)
{
// Accumulate kf group error
@@ -2425,9 +2460,34 @@ void vp8_find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame)
if (cpi->oxcf.auto_key
&& lookup_next_frame_stats(cpi, &next_frame) != EOF)
{
+ // Normal scene cut check
if (test_candidate_kf(cpi, &last_frame, this_frame, &next_frame))
break;
+ // How fast is prediction quality decaying
+ loop_decay_rate = get_prediction_decay_rate(cpi, &next_frame);
+
+ // We want to know something about the recent past... rather than
+ // as used elsewhere where we are concened with decay in prediction
+ // quality since the last GF or KF.
+ recent_loop_decay[i%8] = loop_decay_rate;
+ decay_accumulator = 1.0;
+ for (j = 0; j < 8; j++)
+ {
+ decay_accumulator = decay_accumulator * recent_loop_decay[j];
+ }
+
+ // Special check for transition or high motion followed by a
+ // to a static scene.
+ if ( detect_transition_to_still( cpi, i,
+ (cpi->key_frame_frequency-i),
+ loop_decay_rate,
+ decay_accumulator ) )
+ {
+ break;
+ }
+
+
// Step on to the next frame
cpi->frames_to_key ++;
@@ -2437,6 +2497,8 @@ void vp8_find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame)
break;
} else
cpi->frames_to_key ++;
+
+ i++;
}
// If there is a max kf interval set by the user we must obey it.
@@ -2588,32 +2650,8 @@ void vp8_find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame)
if (r > RMAX)
r = RMAX;
- // Adjust loop decay rate
- //if ( next_frame.pcnt_inter < loop_decay_rate )
- 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;
-
- // 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 < loop_decay_rate)
- loop_decay_rate = distance_factor;
- }
+ // How fast is prediction quality decaying
+ loop_decay_rate = get_prediction_decay_rate(cpi, &next_frame);
decay_accumulator = decay_accumulator * loop_decay_rate;
decay_accumulator = decay_accumulator < 0.1 ? 0.1 : decay_accumulator;