--- trunk/vfw/src/2pass.c 2002/04/06 06:21:29 105 +++ trunk/vfw/src/2pass.c 2002/07/27 21:38:19 343 @@ -23,6 +23,8 @@ * * History: * + * 17.04.2002 changed 1st pass quant to always be 2 (2pass_update()) + * 07.04.2002 added max bitrate constraint, overflow controls (foxer) * 31.03.2002 inital version; * *************************************************************************/ @@ -161,6 +163,7 @@ { i_boost_total = twopass->nns2.bytes * codec->config.keyframe_boost / 100; i_total += twopass->nns2.bytes; + twopass->keyframe_locations[i_frames] = frames; ++i_frames; } @@ -172,6 +175,7 @@ ++frames; } + twopass->keyframe_locations[i_frames] = frames; twopass->movie_curve = ((double)(total_ext + i_boost_total) / total_ext); twopass->average_frame = ((double)(total_ext - i_total) / (frames - credits_frames - i_frames) / twopass->movie_curve); @@ -369,6 +373,7 @@ { i_total += twopass->nns1.bytes + twopass->nns1.bytes * codec->config.keyframe_boost / 100; total += twopass->nns1.bytes * codec->config.keyframe_boost / 100; + twopass->keyframe_locations[i_frames] = frames; ++i_frames; } @@ -376,6 +381,7 @@ ++frames; } + twopass->keyframe_locations[i_frames] = frames; // compensate for avi frame overhead desired -= frames * 24; @@ -680,6 +686,9 @@ } twopass->overflow = 0; + twopass->KFoverflow = 0; + twopass->KFoverflow_partial = 0; + twopass->KF_idx = 1; break; } @@ -700,6 +709,8 @@ int bytes1, bytes2; int overflow; int credits_pos; + int capped_to_max_framesize = 0; + int KFdistance, KF_min_size; if (codec->framenum == 0) { @@ -919,6 +930,30 @@ twopass->desired_bytes2 = bytes2; + if (frame->intra) + { + KFdistance = codec->twopass.keyframe_locations[codec->twopass.KF_idx] - + codec->twopass.keyframe_locations[codec->twopass.KF_idx - 1]; + + if (KFdistance < codec->config.kftreshold) + { + KFdistance = KFdistance - codec->config.min_key_interval; + + if (KFdistance >= 0) + { + KF_min_size = bytes2 * (100 - codec->config.kfreduction) / 100; + if (KF_min_size < 1) + KF_min_size = 1; + + bytes2 = KF_min_size + (bytes2 - KF_min_size) * KFdistance / + (codec->config.kftreshold - codec->config.min_key_interval); + + if (bytes2 < 1) + bytes2 = 1; + } + } + } + // Foxer: scale overflow in relation to average size, so smaller frames don't get // too much/little bitrate overflow = (int)((double)overflow * bytes2 / twopass->average_frame); @@ -930,19 +965,26 @@ } // Foxer: make sure overflow doesn't run away - if (overflow > bytes2 * 6 / 10) + if (overflow > bytes2 * codec->config.twopass_max_overflow_improvement / 100) { - bytes2 += (overflow <= bytes2) ? bytes2 * 6 / 10 : overflow * 6 / 10; + bytes2 += (overflow <= bytes2) ? bytes2 * codec->config.twopass_max_overflow_improvement / 100 : + overflow * codec->config.twopass_max_overflow_improvement / 100; } - else if (overflow < bytes2 * -6 / 10) + else if (overflow < bytes2 * codec->config.twopass_max_overflow_degradation / -100) { - bytes2 += bytes2 * -6 / 10; + bytes2 += bytes2 * codec->config.twopass_max_overflow_degradation / -100; } else { bytes2 += overflow; } + if (bytes2 > twopass->max_framesize) + { + capped_to_max_framesize = 1; + bytes2 = twopass->max_framesize; + } + if (bytes2 < 1) { bytes2 = 1; @@ -1006,7 +1048,7 @@ } // subsequent frame quants can only be +- 2 - if (last_quant) + if (last_quant && capped_to_max_framesize == 0) { if (frame->quant > last_quant + 2) { @@ -1021,7 +1063,8 @@ } } - last_quant = frame->quant; + if (capped_to_max_framesize == 0) + last_quant = frame->quant; if (codec->config.quant_type == QUANT_MODE_MOD) { @@ -1039,7 +1082,7 @@ NNSTATS nns1; DWORD wrote; - int credits_pos; + int credits_pos, tempdiv; char* quant_type; if (codec->framenum == 0) @@ -1062,7 +1105,8 @@ nns1.md_u = nns1.md_y = 0; nns1.mk_u = nns1.mk_y = 0; - nns1.quant = stats->quant; +// nns1.quant = stats->quant; + nns1.quant = 2; // ugly fix for lumi masking in 1st pass returning new quant if (frame->intra) { nns1.quant |= NNSTATS_KEYFRAME; @@ -1085,11 +1129,49 @@ case DLG_MODE_2PASS_2_INT : case DLG_MODE_2PASS_2_EXT : - codec->twopass.overflow += codec->twopass.desired_bytes2 - frame->length; - credits_pos = codec_is_in_credits(&codec->config, codec->framenum); if (!credits_pos) + { codec->twopass.quant_count[frame->quant]++; + if ((codec->twopass.nns1.quant & NNSTATS_KEYFRAME)) + { + codec->twopass.overflow += codec->twopass.KFoverflow; + codec->twopass.KFoverflow = codec->twopass.desired_bytes2 - frame->length; + + tempdiv = (codec->twopass.keyframe_locations[codec->twopass.KF_idx] - + codec->twopass.keyframe_locations[codec->twopass.KF_idx - 1]); + + if (tempdiv > 1) + { + // non-consecutive keyframes + codec->twopass.KFoverflow_partial = codec->twopass.KFoverflow / (tempdiv - 1); + } + else + { + // consecutive keyframes + codec->twopass.overflow += codec->twopass.KFoverflow; + codec->twopass.KFoverflow = 0; + codec->twopass.KFoverflow_partial = 0; + } + codec->twopass.KF_idx++; + } + else + { + codec->twopass.overflow += codec->twopass.desired_bytes2 - frame->length + + codec->twopass.KFoverflow_partial; + codec->twopass.KFoverflow -= codec->twopass.KFoverflow_partial; + } + } + else + { + codec->twopass.overflow += codec->twopass.desired_bytes2 - frame->length; + + // ugly fix for credits.. + codec->twopass.overflow += codec->twopass.KFoverflow; + codec->twopass.KFoverflow = 0; + codec->twopass.KFoverflow_partial = 0; + // end of ugly fix. + } DEBUG2ND(frame->quant, quant_type, frame->intra, codec->twopass.bytes1, codec->twopass.desired_bytes2, frame->length, codec->twopass.overflow, credits_pos) break;