--- trunk/vfw/src/2pass.c 2002/04/17 14:04:41 127 +++ trunk/vfw/src/2pass.c 2002/09/12 21:18:49 482 @@ -161,8 +161,9 @@ { if (twopass->nns1.quant & NNSTATS_KEYFRAME) { - i_boost_total = twopass->nns2.bytes * codec->config.keyframe_boost / 100; + i_boost_total += twopass->nns2.bytes * codec->config.keyframe_boost / 100; i_total += twopass->nns2.bytes; + twopass->keyframe_locations[i_frames] = frames; ++i_frames; } @@ -174,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); @@ -371,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; } @@ -378,6 +381,7 @@ ++frames; } + twopass->keyframe_locations[i_frames] = frames; // compensate for avi frame overhead desired -= frames * 24; @@ -682,6 +686,9 @@ } twopass->overflow = 0; + twopass->KFoverflow = 0; + twopass->KFoverflow_partial = 0; + twopass->KF_idx = 1; break; } @@ -703,6 +710,7 @@ int overflow; int credits_pos; int capped_to_max_framesize = 0; + int KFdistance, KF_min_size; if (codec->framenum == 0) { @@ -786,7 +794,27 @@ } else // DLG_MODE_2PASS_2_EXT { - bytes2 = twopass->nns2.bytes; + if (codec->config.credits_mode == CREDITS_MODE_QUANT) + { + if (codec->config.credits_quant_i != codec->config.credits_quant_p) + { + frame->quant = frame->intra ? + codec->config.credits_quant_i : + codec->config.credits_quant_p; + } + else + { + frame->quant = codec->config.credits_quant_p; + frame->intra = -1; + } + + twopass->bytes1 = bytes1; + twopass->bytes2 = bytes1; + twopass->desired_bytes2 = bytes1; + return ICERR_OK; + } + else + bytes2 = twopass->nns2.bytes; } } else // Foxer: apply curve compression outside credits @@ -922,6 +950,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); @@ -1050,7 +1104,7 @@ NNSTATS nns1; DWORD wrote; - int credits_pos; + int credits_pos, tempdiv; char* quant_type; if (codec->framenum == 0) @@ -1097,11 +1151,54 @@ 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)) + { + // 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;