--- trunk/vfw/src/2pass.c 2002/04/05 14:42:37 102 +++ trunk/vfw/src/2pass.c 2002/08/07 06:13:18 365 @@ -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) { @@ -708,6 +719,7 @@ for (i=0 ; i<32 ; ++i) { quant_error[i] = 0.0; + twopass->quant_count[i] = 0; } curve_comp_error = 0.0; @@ -918,6 +930,32 @@ twopass->desired_bytes2 = bytes2; + // if this keyframe is too close to the next, + // reduce it's byte allotment + if (frame->intra && !credits_pos) + { + 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); @@ -929,19 +967,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; @@ -1005,7 +1050,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) { @@ -1020,7 +1065,8 @@ } } - last_quant = frame->quant; + if (capped_to_max_framesize == 0) + last_quant = frame->quant; if (codec->config.quant_type == QUANT_MODE_MOD) { @@ -1038,6 +1084,7 @@ NNSTATS nns1; DWORD wrote; + int credits_pos, tempdiv; char* quant_type; if (codec->framenum == 0) @@ -1060,7 +1107,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; @@ -1083,8 +1131,56 @@ case DLG_MODE_2PASS_2_INT : case DLG_MODE_2PASS_2_EXT : - codec->twopass.overflow += codec->twopass.desired_bytes2 - frame->length; - DEBUG2ND(frame->quant, quant_type, frame->intra, codec->twopass.bytes1, codec->twopass.desired_bytes2, frame->length, codec->twopass.overflow, codec_is_in_credits(&codec->config, codec->framenum)) + 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)) + { + // calculate how much to distribute per frame in + // order to make up for this keyframe's overflow + + 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 + { + // distribute part of the keyframe overflow + + 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; default: @@ -1094,4 +1190,23 @@ return ICERR_OK; } +void codec_2pass_finish(CODEC* codec) +{ + int i; + char s[100]; + if (codec->config.mode == DLG_MODE_2PASS_2_EXT || codec->config.mode == DLG_MODE_2PASS_2_INT) + { + // output the quantizer distribution for this encode. + OutputDebugString("Quantizer distribution for 2nd pass:"); + for (i=1; i<=31; i++) + { + if (codec->twopass.quant_count[i]) + { + wsprintf(s, "Q:%i:%i", i, codec->twopass.quant_count[i]); + OutputDebugString(s); + } + } + return; + } +} \ No newline at end of file