--- plugin_2pass2.c 2003/03/25 10:58:33 1.1.2.1 +++ plugin_2pass2.c 2003/05/20 17:28:25 1.1.2.6 @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id: plugin_2pass2.c,v 1.1.2.1 2003/03/25 10:58:33 suxen_drol Exp $ + * $Id: plugin_2pass2.c,v 1.1.2.6 2003/05/20 17:28:25 edgomez Exp $ * *****************************************************************************/ @@ -38,9 +38,13 @@ typedef struct { int type; /* first pass type */ int quant; /* first pass quant */ + int blks[3]; /* k,m,y blks */ int length; /* first pass length */ - int scaled_length; /* scaled length */ - int desired_length; + int scaled_length; /* scaled length */ + int desired_length; /* desired length; calcuated during encoding */ + + int zone_mode; /* XVID_ZONE_xxx */ + double weight; } stat_t; @@ -52,16 +56,22 @@ xvid_plugin_2pass2_t param; /* constant statistical data */ - int num_frames; + int num_frames; int num_keyframes; - + uint64_t target; /* target filesize */ + int count[3]; /* count of each frame types */ uint64_t tot_length[3]; /* total length of each frame types */ double avg_length[3]; /* avg */ int min_length[3]; /* min frame length of each frame types */ uint64_t tot_scaled_length[3]; /* total scaled length of each frame type */ int max_length; /* max frame size */ - + + /* zone statistical data */ + double avg_weight; /* average weight */ + int64_t tot_quant; /* total length used by XVID_ZONE_QUANT zones */ + + double curve_comp_scale; double movie_curve; @@ -88,6 +98,8 @@ int KFoverflow; int KFoverflow_partial; int KF_idx; + + double fq_error; } rc_2pass2_t; @@ -110,8 +122,8 @@ if ((f = fopen(filename, "rt")) == NULL) return 0; - while((n = fscanf(f, "%c %d %d %d %d %d\n", - &type, &ignore, &ignore, &ignore, &ignore, &ignore)) != EOF) { + while((n = fscanf(f, "%c %d %d %d %d %d %d\n", + &type, &ignore, &ignore, &ignore, &ignore, &ignore, &ignore)) != EOF) { if (type == 'i') { rc->num_frames++; rc->num_keyframes++; @@ -126,30 +138,31 @@ } + /* open stats file(s) and read into rc->stats array */ -static int load_stats(rc_2pass2_t *rc, char * filename1, char * filename2) +static int load_stats(rc_2pass2_t *rc, char * filename) { - FILE * f1, *f2; - int i; - + FILE * f; + int i, not_scaled; + - if ((f1 = fopen(filename1, "rt"))==NULL) + if ((f = fopen(filename, "rt"))==NULL) return 0; - if ((f2 = fopen(filename2, "rt"))==NULL) { - fclose(f1); - return 0; - } - i = 0; + not_scaled = 0; while(i < rc->num_frames) { stat_t * s = &rc->stats[i]; - int n, ignore; + int n; char type; - n = fscanf(f1, "%c %d %d %d %d %d\n", &type, &s->quant, &s->length, &ignore, &ignore, &ignore); + s->scaled_length = 0; + n = fscanf(f, "%c %d %d %d %d %d %d\n", &type, &s->quant, &s->blks[0], &s->blks[1], &s->blks[2], &s->length, &s->scaled_length); if (n == EOF) break; + if (n < 7) { + not_scaled = 1; + } if (type == 'i') { s->type = XVID_TYPE_IVOP; @@ -158,186 +171,196 @@ }else if (type == 'b') { s->type = XVID_TYPE_BVOP; }else{ /* unknown type */ - printf("unk\n"); - continue; - } - - n = fscanf(f2, "%c %d %d %d %d %d\n", &type, &ignore, &s->scaled_length, &ignore, &ignore, &ignore); - if (n == EOF) break; - if (type != 'i'&& type != 'p' && type != 'b' && type != 's') { - printf("unk\n"); - continue; /* unknown type */ + DPRINTF(XVID_DEBUG_RC, "unknown stats frame type; assuming pvop"); + s->type = XVID_TYPE_PVOP; } i++; } rc->num_frames = i; - - - fclose(f1); - if (filename2) - fclose(f2); + + fclose(f); return 1; } -/*static void internal_scale(rc_2pass2_t *rc) + +#if 0 +static void print_stats(rc_2pass2_t * rc) { - const double avg_pvop = rc->avg_length[XVID_TYPE_PVOP-1]; - const double avg_bvop = rc->avg_length[XVID_TYPE_BVOP-1]; - const uint64_t tot_pvop = rc->tot_length[XVID_TYPE_PVOP-1]; - const uint64_t tot_bvop = rc->tot_length[XVID_TYPE_BVOP-1]; - uint64_t i_total = 0; - double total1,total2; int i; + for (i = 0; i < rc->num_frames; i++) { + stat_t * s = &rc->stats[i]; + DPRINTF(XVID_DEBUG_RC, "%i %i %i %i\n", s->type, s->quant, s->length, s->scaled_length); + } +} +#endif - for (i=0; inum_frames; i++) { +/* pre-process the statistics data + - for each type, count, tot_length, min_length, max_length + - set keyframes_locations +*/ + +void pre_process0(rc_2pass2_t * rc) +{ + int i,j; + + for (i=0; i<3; i++) { + rc->count[i]=0; + rc->tot_length[i] = 0; + rc->last_quant[i] = 0; + } + + for (i=j=0; inum_frames; i++) { stat_t * s = &rc->stats[i]; - if (s->type == XVID_TYPE_IVOP) { - i_total += s->length + s->length * rc->param.keyframe_boost / 100; + rc->count[s->type-1]++; + rc->tot_length[s->type-1] += s->length; + + if (i == 0 || s->length < rc->min_length[s->type-1]) { + rc->min_length[s->type-1] = s->length; } - } - - // compensate for avi frame overhead - rc->target_size -= rc->num_frames * 24; - // perform prepass to compensate for over/undersizing + if (i == 0 || s->length > rc->max_length) { + rc->max_length = s->length; + } - if (rc->param.use_alt_curve) { + if (s->type == XVID_TYPE_IVOP) { + rc->keyframe_locations[j] = i; + j++; + } + } + rc->keyframe_locations[j] = i; +} - rc->alt_curve_low = avg_pvop - avg_pvop * (double)rc->param.alt_curve_low_dist / 100.0; - rc->alt_curve_low_diff = avg_pvop - rc->alt_curve_low; - rc->alt_curve_high = avg_pvop + avg_pvop * (double)rc->param.alt_curve_high_dist / 100.0; - rc->alt_curve_high_diff = rc->alt_curve_high - avg_pvop; - if (rc->alt_curve_use_auto) { - if (rc->movie_curve > 1.0) { - rc->param.alt_curve_min_rel_qual = (int)(100.0 - (100.0 - 100.0 / rc->movie_curve) * (double)rc->param.alt_curve_auto_str / 100.0); - if (rc->param.alt_curve_min_rel_qual < 20) - rc->param.alt_curve_min_rel_qual = 20; - }else{ - rc->param.alt_curve_min_rel_qual = 100; - } - } - rc->alt_curve_mid_qual = (1.0 + (double)rc->param.alt_curve_min_rel_qual / 100.0) / 2.0; - rc->alt_curve_qual_dev = 1.0 - rc->alt_curve_mid_qual; + +/* calculate zone weight "center" */ - if (rc->param.alt_curve_low_dist > 100) { - switch(rc->param.alt_curve_type) { - case XVID_CURVE_SINE : // Sine Curve (high aggressiveness) - rc->alt_curve_qual_dev *= 2.0 / (1.0 + sin(DEG2RAD * (avg_pvop * 90.0 / rc->alt_curve_low_diff))); - rc->alt_curve_mid_qual = 1.0 - rc->alt_curve_qual_dev * sin(DEG2RAD * (avg_pvop * 90.0 / rc->alt_curve_low_diff)); - break; - case XVID_CURVE_LINEAR : // Linear (medium aggressiveness) - rc->alt_curve_qual_dev *= 2.0 / (1.0 + avg_pvop / rc->alt_curve_low_diff); - rc->alt_curve_mid_qual = 1.0 - rc->alt_curve_qual_dev * avg_pvop / rc->alt_curve_low_diff; - break; - case XVID_CURVE_COSINE : // Cosine Curve (low aggressiveness) - rc->alt_curve_qual_dev *= 2.0 / (1.0 + (1.0 - cos(DEG2RAD * (avg_pvop * 90.0 / rc->alt_curve_low_diff)))); - rc->alt_curve_mid_qual = 1.0 - rc->alt_curve_qual_dev * (1.0 - cos(DEG2RAD * (avg_pvop * 90.0 / rc->alt_curve_low_diff))); - } - } - } +static void zone_process(rc_2pass2_t *rc, const xvid_plg_create_t * create) +{ + int i,j; + int n = 0; - total1 = 0; - total2 = 0; + rc->avg_weight = 0.0; + rc->tot_quant = 0; - for (i=0; inum_frames; i++) { - stat_t * s = &rc->stats[i]; - if (s->type != XVID_TYPE_IVOP) { - - double dbytes = s->length / rc->movie_curve; - double dbytes2; - total1 += dbytes; + if (create->num_zones == 0) { + for (j = 0; j < rc->num_frames; j++) { + rc->stats[j].zone_mode = XVID_ZONE_WEIGHT; + rc->stats[j].weight = 1.0; + } + rc->avg_weight += rc->num_frames * 1.0; + n += rc->num_frames; + } - if (s->type == XVID_TYPE_BVOP) - dbytes *= avg_pvop / avg_bvop; - if (rc->param.use_alt_curve) { - if (dbytes > avg_pvop) { - if (dbytes >= rc->alt_curve_high) { - dbytes2 = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev); - }else{ - switch(rc->param.alt_curve_type){ - case XVID_CURVE_SINE : - dbytes2 = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev * sin(DEG2RAD * ((dbytes - avg_pvop) * 90.0 / rc->alt_curve_high_diff))); - break; - case XVID_CURVE_LINEAR : - dbytes2 = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev * (dbytes - avg_pvop) / rc->alt_curve_high_diff); - break; - case XVID_CURVE_COSINE : - dbytes2 = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev * (1.0 - cos(DEG2RAD * ((dbytes - avg_pvop) * 90.0 / rc->alt_curve_high_diff)))); - } - } - }else{ - if (dbytes <= rc->alt_curve_low){ - dbytes2 = dbytes; - }else{ - switch(rc->param.alt_curve_type){ - case XVID_CURVE_SINE : - dbytes2 = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev * sin(DEG2RAD * ((dbytes - avg_pvop) * 90.0 / rc->alt_curve_low_diff))); - break; - case XVID_CURVE_LINEAR : - dbytes2 = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev * (dbytes - avg_pvop) / rc->alt_curve_low_diff); - break; - case XVID_CURVE_COSINE : - dbytes2 = dbytes * (rc->alt_curve_mid_qual + rc->alt_curve_qual_dev * (1.0 - cos(DEG2RAD * ((dbytes - avg_pvop) * 90.0 / rc->alt_curve_low_diff)))); - } - } - } - }else{ - if (dbytes > avg_pvop) { - dbytes2 = ((double)dbytes + (avg_pvop - dbytes) * - rc->param.curve_compression_high / 100.0); - }else{ - dbytes2 = ((double)dbytes + (avg_pvop - dbytes) * - rc->param.curve_compression_low / 100.0); - } - } + for(i=0; i < create->num_zones; i++) { + + int next = (i+1num_zones) ? create->zones[i+1].frame : rc->num_frames; - if (s->type == XVID_TYPE_BVOP) { - dbytes2 *= avg_bvop / avg_pvop; + if (i==0 && create->zones[i].frame > 0) { + for (j = 0; j < create->zones[i].frame && j < rc->num_frames; j++) { + rc->stats[j].zone_mode = XVID_ZONE_WEIGHT; + rc->stats[j].weight = 1.0; } + rc->avg_weight += create->zones[i].frame * 1.0; + n += create->zones[i].frame; + } - if (dbytes2 < rc->min_length[s->type-1]) { - dbytes = rc->min_length[s->type-1]; + if (create->zones[i].mode == XVID_ZONE_WEIGHT) { + for (j = create->zones[i].frame; j < next && j < rc->num_frames; j++ ) { + rc->stats[j].zone_mode = XVID_ZONE_WEIGHT; + rc->stats[j].weight = (double)create->zones[i].increment / (double)create->zones[i].base; + } + next -= create->zones[i].frame; + rc->avg_weight += (double)(next * create->zones[i].increment) / (double)create->zones[i].base; + n += next; + }else{ // XVID_ZONE_QUANT + for (j = create->zones[i].frame; j < next && j < rc->num_frames; j++ ) { + rc->stats[j].zone_mode = XVID_ZONE_QUANT; + rc->stats[j].weight = (double)create->zones[i].increment / (double)create->zones[i].base; + rc->tot_quant += rc->stats[j].length; } + } + } + rc->avg_weight = n>0 ? rc->avg_weight/n : 1.0; + + DPRINTF(XVID_DEBUG_RC, "center_weight: %f (for %i frames); fixed_bytes: %i\n", rc->avg_weight, n, rc->tot_quant); +} - total2 += dbytes2; - } - } - rc->curve_comp_scale = total1 / total2; +/* scale the curve */ + +static void internal_scale(rc_2pass2_t *rc) +{ + int64_t target = rc->target - rc->tot_quant; + int64_t pass1_length = rc->tot_length[0] + rc->tot_length[1] + rc->tot_length[2] - rc->tot_quant; + int min_size[3]; + double scaler; + int i; - if (!rc->param.use_alt_curve) { - printf("middle frame size for asymmetric curve compression: %i", - (int)(avg_pvop * rc->curve_comp_scale)); + + /* perform an initial scale pass. + if a frame size is scaled underneath our hardcoded minimums, then we force the + frame size to the minimum, and deduct the original & scaled frmae length from the + original and target total lengths */ + + min_size[0] = ((rc->stats[0].blks[0]*22) + 240) / 8; + min_size[1] = (rc->stats[0].blks[0] + 88) / 8; + min_size[2] = 8; + + scaler = (double)target / (double)pass1_length; + + if (target <= 0 || pass1_length <= 0 || target >= pass1_length) { + DPRINTF(XVID_DEBUG_RC, "undersize warning\n"); + scaler = 1.0; } -}*/ + DPRINTF(XVID_DEBUG_RC, "target=%i, tot_length=%i, scaler=%f\n", (int)target, (int)pass1_length, scaler); + for (i=0; inum_frames; i++) { + stat_t * s = &rc->stats[i]; + int len; + if (s->zone_mode == XVID_ZONE_QUANT) { + s->scaled_length = s->length; + }else { + len = (int)((double)s->length * scaler * s->weight / rc->avg_weight); + if (len < min_size[s->type-1]) { /* force frame size */ + s->scaled_length = min_size[s->type-1]; + target -= s->scaled_length; + pass1_length -= s->length; + }else{ + s->scaled_length = 0; + } + } + } -static void print_stats(rc_2pass2_t * rc) -{ - int i; - for (i = 0; i < rc->num_frames; i++) { - stat_t * s = &rc->stats[i]; - printf("%i %i %i %i\n", s->type, s->quant, s->length, s->scaled_length); + scaler = (double)target / (double)pass1_length; + if (target <= 0 || pass1_length <= 0 || target >= pass1_length) { + DPRINTF(XVID_DEBUG_RC,"undersize warning\n"); + scaler = 1.0; + } - } + DPRINTF(XVID_DEBUG_RC, "target=%i, tot_length=%i, scaler=%f\n", (int)target, (int)pass1_length, scaler); + + for (i=0; inum_frames; i++) { + stat_t * s = &rc->stats[i]; + + if (s->scaled_length==0) { /* ignore frame with forced frame sizes */ + s->scaled_length = (int)((double)s->length * scaler * s->weight / rc->avg_weight); + } + } } -/* pre-process the statistics data - this is a clone of vfw/src/2pass.c:codec_2pass_init minus file reading, alt_curve, internal scale -*/ -void pre_process(rc_2pass2_t * rc) + +void pre_process1(rc_2pass2_t * rc) { - int i,j; + int i; double total1, total2; uint64_t ivop_boost_total; @@ -345,40 +368,18 @@ rc->curve_comp_error = 0; for (i=0; i<3; i++) { - rc->count[i]=0; - rc->tot_length[i] = 0; rc->tot_scaled_length[i] = 0; - rc->last_quant[i] = 0; - } - - for (i=0; i<32;i++) { - rc->pquant_error[i] = 0; - rc->bquant_error[i] = 0; - rc->quant_count[i] = 0; } - for (i=j=0; inum_frames; i++) { + for (i=0; inum_frames; i++) { stat_t * s = &rc->stats[i]; - rc->count[s->type-1]++; - rc->tot_length[s->type-1] += s->length; rc->tot_scaled_length[s->type-1] += s->scaled_length; - if (i == 0 || s->length < rc->min_length[s->type-1]) { - rc->min_length[s->type-1] = s->length; - } - - if (i == 0 || s->length > rc->max_length) { - rc->max_length = s->length; - } - if (s->type == XVID_TYPE_IVOP) { ivop_boost_total += s->scaled_length * rc->param.keyframe_boost / 100; - rc->keyframe_locations[j] = i; - j++; } } - rc->keyframe_locations[j] = i; rc->movie_curve = ((double)(rc->tot_scaled_length[XVID_TYPE_PVOP-1] + rc->tot_scaled_length[XVID_TYPE_BVOP-1] + ivop_boost_total) / (rc->tot_scaled_length[XVID_TYPE_PVOP-1] + rc->tot_scaled_length[XVID_TYPE_BVOP-1])); @@ -391,7 +392,6 @@ } } - printf("--\n"); /* alt curve stuff here */ if (rc->param.use_alt_curve) { @@ -440,7 +440,7 @@ total1=total2=0; - for (i=j=0; inum_frames; i++) { + for (i=0; inum_frames; i++) { stat_t * s = &rc->stats[i]; if (s->type != XVID_TYPE_IVOP) { @@ -511,7 +511,7 @@ rc->curve_comp_scale = total1 / total2; if (!rc->param.use_alt_curve) { - printf("middle frame size for asymmetric curve compression: %i\n", + DPRINTF(XVID_DEBUG_RC, "middle frame size for asymmetric curve compression: %i\n", (int)(rc->avg_length[XVID_TYPE_PVOP-1] * rc->curve_comp_scale)); } @@ -528,8 +528,8 @@ /* special info for alt curve: bias bonus and quantizer thresholds */ - printf("avg scaled framesize:%i", (int)rc->avg_length[XVID_TYPE_PVOP-1]); - printf("bias bonus:%i bytes", (int)rc->alt_curve_curve_bias_bonus); + DPRINTF(XVID_DEBUG_RC, "avg scaled framesize:%i", (int)rc->avg_length[XVID_TYPE_PVOP-1]); + DPRINTF(XVID_DEBUG_RC, "bias bonus:%i bytes", (int)rc->alt_curve_curve_bias_bonus); for (i=1; i <= (int)(rc->alt_curve_high*2)+1; i++) { double curve_temp, dbytes; @@ -578,7 +578,7 @@ if (newquant != oldquant) { int percent = (int)((i - rc->avg_length[XVID_TYPE_PVOP-1]) * 100.0 / rc->avg_length[XVID_TYPE_PVOP-1]); oldquant = newquant; - printf("quant:%i threshold at %i : %i percent", newquant, i, percent); + DPRINTF(XVID_DEBUG_RC, "quant:%i threshold at %i : %i percent", newquant, i, percent); } } } @@ -598,6 +598,7 @@ { xvid_plugin_2pass2_t * param = (xvid_plugin_2pass2_t *)create->param; rc_2pass2_t * rc; + int i; rc = malloc(sizeof(rc_2pass2_t)); if (rc == NULL) @@ -612,12 +613,6 @@ if (rc->param.curve_compression_low <= 0) rc->param.curve_compression_low = 0; if (rc->param.max_overflow_improvement <= 0) rc->param.max_overflow_improvement = 60; if (rc->param.max_overflow_degradation <= 0) rc->param.max_overflow_degradation = 60; - if (rc->param.min_quant[0] <= 0) rc->param.min_quant[0] = 2; - if (rc->param.max_quant[0] <= 0) rc->param.max_quant[0] = 31; - if (rc->param.min_quant[1] <= 0) rc->param.min_quant[1] = 2; - if (rc->param.max_quant[1] <= 0) rc->param.max_quant[1] = 31; - if (rc->param.min_quant[2] <= 0) rc->param.min_quant[2] = 2; - if (rc->param.max_quant[2] <= 0) rc->param.max_quant[2] = 31; if (rc->param.use_alt_curve <= 0) rc->param.use_alt_curve = 0; if (rc->param.alt_curve_high_dist <= 0) rc->param.alt_curve_high_dist = 500; @@ -633,8 +628,8 @@ if (rc->param.kfreduction <= 0) rc->param.kfreduction = 20; if (rc->param.min_key_interval <= 0) rc->param.min_key_interval = 300; - if (!det_stats_length(rc, param->filename1)){ - DPRINTF(DPRINTF_RC,"fopen %s failed\n", param->filename1); + if (!det_stats_length(rc, param->filename)){ + DPRINTF(XVID_DEBUG_RC,"fopen %s failed\n", param->filename); free(rc); return XVID_ERR_FAIL; } @@ -651,8 +646,8 @@ return XVID_ERR_MEMORY; } - if (!load_stats(rc, param->filename1, param->filename2)) { - DPRINTF(DPRINTF_RC,"fopen %s,%s failed\n", param->filename1, param->filename2); + if (!load_stats(rc, param->filename)) { + DPRINTF(XVID_DEBUG_RC,"fopen %s failed\n", param->filename); free(rc->keyframe_locations); free(rc->stats); free(rc); @@ -660,7 +655,41 @@ } /* pre-process our stats */ - pre_process(rc); + + if (rc->num_frames < create->fbase/create->fincr) { + rc->target = rc->param.bitrate / 8; /* one second */ + }else{ + rc->target = (rc->param.bitrate * rc->num_frames * create->fincr) / (create->fbase * 8); + } + + DPRINTF(XVID_DEBUG_RC, "rc->target : %i\n", rc->target); + + rc->target -= rc->num_frames*24; /* avi file header */ + + + pre_process0(rc); + + if (rc->param.bitrate) { + zone_process(rc, create); + internal_scale(rc); + }else{ + /* external scaler: ignore zone */ + for (i=0;inum_frames;i++) { + rc->stats[i].zone_mode = XVID_ZONE_WEIGHT; + rc->stats[i].weight = 1.0; + } + rc->avg_weight = 1.0; + rc->tot_quant = 0; + } + pre_process1(rc); + + for (i=0; i<32;i++) { + rc->pquant_error[i] = 0; + rc->bquant_error[i] = 0; + rc->quant_count[i] = 0; + } + + rc->fq_error = 0; *handle = rc; return(0); @@ -686,242 +715,262 @@ double curve_temp; int capped_to_max_framesize = 0; - if (data->frame_num >= rc->num_frames) { - /* insufficent stats data */ - return 0; - } - - overflow = rc->overflow / 8; /* XXX: why by 8 */ - - if (s->type == XVID_TYPE_IVOP) { /* XXX: why */ - overflow = 0; - } - - desired = s->scaled_length; - - dbytes = desired; - if (s->type == XVID_TYPE_IVOP) { - dbytes += desired * rc->param.keyframe_boost / 100; - } - dbytes /= rc->movie_curve; - - if (s->type == XVID_TYPE_BVOP) { - dbytes *= rc->avg_length[XVID_TYPE_PVOP-1] / rc->avg_length[XVID_TYPE_BVOP-1]; - } - - if (rc->param.payback_method == XVID_PAYBACK_BIAS) { - desired =(int)(rc->curve_comp_error / rc->param.bitrate_payback_delay); - }else{ - desired = (int)(rc->curve_comp_error * dbytes / - rc->avg_length[XVID_TYPE_PVOP-1] / rc->param.bitrate_payback_delay); - - if (labs(desired) > fabs(rc->curve_comp_error)) { - desired = (int)rc->curve_comp_error; - } - } - - rc->curve_comp_error -= desired; - - /* alt curve */ - - curve_temp = 0; /* XXX: warning */ + if (data->quant <= 0) { - if (rc->param.use_alt_curve) { - if (s->type != XVID_TYPE_IVOP) { - if (dbytes > rc->avg_length[XVID_TYPE_PVOP-1]) { - if (dbytes >= rc->alt_curve_high) { - curve_temp = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev); - }else{ - switch(rc->param.alt_curve_type) { - case XVID_CURVE_SINE : - curve_temp = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev * sin(DEG2RAD * ((dbytes - rc->avg_length[XVID_TYPE_PVOP-1]) * 90.0 / rc->alt_curve_high_diff))); - break; - case XVID_CURVE_LINEAR : - curve_temp = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev * (dbytes - rc->avg_length[XVID_TYPE_PVOP-1]) / rc->alt_curve_high_diff); - break; - case XVID_CURVE_COSINE : - curve_temp = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev * (1.0 - cos(DEG2RAD * ((dbytes - rc->avg_length[XVID_TYPE_PVOP-1]) * 90.0 / rc->alt_curve_high_diff)))); - } - } - }else{ - if (dbytes <= rc->alt_curve_low){ - curve_temp = dbytes; - }else{ - switch(rc->param.alt_curve_type) { - case XVID_CURVE_SINE : - curve_temp = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev * sin(DEG2RAD * ((dbytes - rc->avg_length[XVID_TYPE_PVOP-1]) * 90.0 / rc->alt_curve_low_diff))); - break; - case XVID_CURVE_LINEAR : - curve_temp = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev * (dbytes - rc->avg_length[XVID_TYPE_PVOP-1]) / rc->alt_curve_low_diff); - break; - case XVID_CURVE_COSINE : - curve_temp = dbytes * (rc->alt_curve_mid_qual + rc->alt_curve_qual_dev * (1.0 - cos(DEG2RAD * ((dbytes - rc->avg_length[XVID_TYPE_PVOP-1]) * 90.0 / rc->alt_curve_low_diff)))); - } - } - } - if (s->type == XVID_TYPE_BVOP) - curve_temp *= rc->avg_length[XVID_TYPE_BVOP-1] / rc->avg_length[XVID_TYPE_PVOP-1]; + if (s->zone_mode == XVID_ZONE_QUANT) { - curve_temp = curve_temp * rc->curve_comp_scale + rc->alt_curve_curve_bias_bonus; + rc->fq_error += s->weight; + data->quant = (int)rc->fq_error; + rc->fq_error -= data->quant; - desired += ((int)curve_temp); - rc->curve_comp_error += curve_temp - (int)curve_temp; - }else{ - if (s->type == XVID_TYPE_BVOP) - dbytes *= rc->avg_length[XVID_TYPE_BVOP-1] / rc->avg_length[XVID_TYPE_PVOP-1]; + s->desired_length = s->length; - desired += ((int)dbytes); - rc->curve_comp_error += dbytes - (int)dbytes; - } + }else { /* XVID_ZONE_WEIGHT */ - }else if ((rc->param.curve_compression_high + rc->param.curve_compression_low) && s->type != XVID_TYPE_IVOP) { - - curve_temp = rc->curve_comp_scale; - if (dbytes > rc->avg_length[XVID_TYPE_PVOP-1]) { - curve_temp *= ((double)dbytes + (rc->avg_length[XVID_TYPE_PVOP-1] - dbytes) * rc->param.curve_compression_high / 100.0); - } else { - curve_temp *= ((double)dbytes + (rc->avg_length[XVID_TYPE_PVOP-1] - dbytes) * rc->param.curve_compression_low / 100.0); - } + if (data->frame_num >= rc->num_frames) { + /* insufficent stats data */ + return 0; + } - if (s->type == XVID_TYPE_BVOP){ - curve_temp *= rc->avg_length[XVID_TYPE_BVOP-1] / rc->avg_length[XVID_TYPE_PVOP-1]; - } + overflow = rc->overflow / 8; /* XXX: why by 8 */ - desired += (int)curve_temp; - rc->curve_comp_error += curve_temp - (int)curve_temp; - }else{ - if (s->type == XVID_TYPE_BVOP){ - dbytes *= rc->avg_length[XVID_TYPE_BVOP-1] / rc->avg_length[XVID_TYPE_PVOP-1]; - } + if (s->type == XVID_TYPE_IVOP) { /* XXX: why */ + overflow = 0; + } - desired += (int)dbytes; - rc->curve_comp_error += dbytes - (int)dbytes; - } + desired = s->scaled_length; - if (desired > s->length){ - rc->curve_comp_error += desired - s->length; - desired = s->length; - }else{ - if (desired < rc->min_length[s->type-1]) { - if (s->type == XVID_TYPE_IVOP){ - rc->curve_comp_error -= rc->min_length[XVID_TYPE_IVOP-1] - desired; + dbytes = desired; + if (s->type == XVID_TYPE_IVOP) { + dbytes += desired * rc->param.keyframe_boost / 100; } - desired = rc->min_length[s->type-1]; - } - } + dbytes /= rc->movie_curve; - s->desired_length = desired; + if (s->type == XVID_TYPE_BVOP) { + dbytes *= rc->avg_length[XVID_TYPE_PVOP-1] / rc->avg_length[XVID_TYPE_BVOP-1]; + } - - /* if this keyframe is too close to the next, reduce it's byte allotment - XXX: why do we do this after setting the desired length */ + if (rc->param.payback_method == XVID_PAYBACK_BIAS) { + desired =(int)(rc->curve_comp_error / rc->param.bitrate_payback_delay); + }else{ + //printf("desired=%i, dbytes=%i\n", desired,dbytes); + desired = (int)(rc->curve_comp_error * dbytes / + rc->avg_length[XVID_TYPE_PVOP-1] / rc->param.bitrate_payback_delay); + //printf("desired=%i\n", desired); + + if (labs(desired) > fabs(rc->curve_comp_error)) { + desired = (int)rc->curve_comp_error; + } + } - if (s->type == XVID_TYPE_IVOP) { - int KFdistance = rc->keyframe_locations[rc->KF_idx] - rc->keyframe_locations[rc->KF_idx - 1]; + rc->curve_comp_error -= desired; - if (KFdistance < rc->param.kftreshold) { - - KFdistance = KFdistance - rc->param.min_key_interval; + /* alt curve */ - if (KFdistance >= 0) { - int KF_min_size; + curve_temp = 0; /* XXX: warning */ - KF_min_size = desired * (100 - rc->param.kfreduction) / 100; - if (KF_min_size < 1) - KF_min_size = 1; + if (rc->param.use_alt_curve) { + if (s->type != XVID_TYPE_IVOP) { + if (dbytes > rc->avg_length[XVID_TYPE_PVOP-1]) { + if (dbytes >= rc->alt_curve_high) { + curve_temp = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev); + }else{ + switch(rc->param.alt_curve_type) { + case XVID_CURVE_SINE : + curve_temp = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev * sin(DEG2RAD * ((dbytes - rc->avg_length[XVID_TYPE_PVOP-1]) * 90.0 / rc->alt_curve_high_diff))); + break; + case XVID_CURVE_LINEAR : + curve_temp = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev * (dbytes - rc->avg_length[XVID_TYPE_PVOP-1]) / rc->alt_curve_high_diff); + break; + case XVID_CURVE_COSINE : + curve_temp = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev * (1.0 - cos(DEG2RAD * ((dbytes - rc->avg_length[XVID_TYPE_PVOP-1]) * 90.0 / rc->alt_curve_high_diff)))); + } + } + }else{ + if (dbytes <= rc->alt_curve_low){ + curve_temp = dbytes; + }else{ + switch(rc->param.alt_curve_type) { + case XVID_CURVE_SINE : + curve_temp = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev * sin(DEG2RAD * ((dbytes - rc->avg_length[XVID_TYPE_PVOP-1]) * 90.0 / rc->alt_curve_low_diff))); + break; + case XVID_CURVE_LINEAR : + curve_temp = dbytes * (rc->alt_curve_mid_qual - rc->alt_curve_qual_dev * (dbytes - rc->avg_length[XVID_TYPE_PVOP-1]) / rc->alt_curve_low_diff); + break; + case XVID_CURVE_COSINE : + curve_temp = dbytes * (rc->alt_curve_mid_qual + rc->alt_curve_qual_dev * (1.0 - cos(DEG2RAD * ((dbytes - rc->avg_length[XVID_TYPE_PVOP-1]) * 90.0 / rc->alt_curve_low_diff)))); + } + } + } + if (s->type == XVID_TYPE_BVOP) + curve_temp *= rc->avg_length[XVID_TYPE_BVOP-1] / rc->avg_length[XVID_TYPE_PVOP-1]; + + curve_temp = curve_temp * rc->curve_comp_scale + rc->alt_curve_curve_bias_bonus; + + desired += ((int)curve_temp); + rc->curve_comp_error += curve_temp - (int)curve_temp; + }else{ + if (s->type == XVID_TYPE_BVOP) + dbytes *= rc->avg_length[XVID_TYPE_BVOP-1] / rc->avg_length[XVID_TYPE_PVOP-1]; + + desired += ((int)dbytes); + rc->curve_comp_error += dbytes - (int)dbytes; + } - desired = KF_min_size + (desired - KF_min_size) * KFdistance / - (rc->param.kftreshold - rc->param.min_key_interval); + }else if ((rc->param.curve_compression_high + rc->param.curve_compression_low) && s->type != XVID_TYPE_IVOP) { - if (desired < 1) - desired = 1; - } - } - } + curve_temp = rc->curve_comp_scale; + if (dbytes > rc->avg_length[XVID_TYPE_PVOP-1]) { + curve_temp *= ((double)dbytes + (rc->avg_length[XVID_TYPE_PVOP-1] - dbytes) * rc->param.curve_compression_high / 100.0); + } else { + curve_temp *= ((double)dbytes + (rc->avg_length[XVID_TYPE_PVOP-1] - dbytes) * rc->param.curve_compression_low / 100.0); + } - overflow = (int)((double)overflow * desired / rc->avg_length[XVID_TYPE_PVOP-1]); + if (s->type == XVID_TYPE_BVOP){ + curve_temp *= rc->avg_length[XVID_TYPE_BVOP-1] / rc->avg_length[XVID_TYPE_PVOP-1]; + } - // Foxer: reign in overflow with huge frames - if (labs(overflow) > labs(rc->overflow)) { - overflow = rc->overflow; - } + desired += (int)curve_temp; + rc->curve_comp_error += curve_temp - (int)curve_temp; + }else{ + if (s->type == XVID_TYPE_BVOP){ + dbytes *= rc->avg_length[XVID_TYPE_BVOP-1] / rc->avg_length[XVID_TYPE_PVOP-1]; + } - // Foxer: make sure overflow doesn't run away + desired += (int)dbytes; + rc->curve_comp_error += dbytes - (int)dbytes; + } - if (overflow > desired * rc->param.max_overflow_improvement / 100) { - desired += (overflow <= desired) ? desired * rc->param.max_overflow_improvement / 100 : - overflow * rc->param.max_overflow_improvement / 100; - }else if (overflow < desired * rc->param.max_overflow_degradation / -100){ - desired += desired * rc->param.max_overflow_degradation / -100; - }else{ - desired += overflow; - } - if (desired > rc->max_length) { - capped_to_max_framesize = 1; - desired = rc->max_length; - } + if (desired > s->length) { /* if desired length exceeds the pass1 length.. */ + rc->curve_comp_error += desired - s->length; + desired = s->length; + }else{ + if (desired < rc->min_length[s->type-1]) { + if (s->type == XVID_TYPE_IVOP){ + rc->curve_comp_error -= rc->min_length[XVID_TYPE_IVOP-1] - desired; + } + desired = rc->min_length[s->type-1]; + } + } - // make sure to not scale below the minimum framesize - if (desired < rc->min_length[s->type-1]) { - desired = rc->min_length[s->type-1]; - } + s->desired_length = desired; + + /* if this keyframe is too close to the next, reduce it's byte allotment + XXX: why do we do this after setting the desired length */ + + if (s->type == XVID_TYPE_IVOP) { + int KFdistance = rc->keyframe_locations[rc->KF_idx] - rc->keyframe_locations[rc->KF_idx - 1]; + + if (KFdistance < rc->param.kftreshold) { + + KFdistance = KFdistance - rc->param.min_key_interval; + + if (KFdistance >= 0) { + int KF_min_size; + + KF_min_size = desired * (100 - rc->param.kfreduction) / 100; + if (KF_min_size < 1) + KF_min_size = 1; + + desired = KF_min_size + (desired - KF_min_size) * KFdistance / + (rc->param.kftreshold - rc->param.min_key_interval); + + if (desired < 1) + desired = 1; + } + } + } + + overflow = (int)((double)overflow * desired / rc->avg_length[XVID_TYPE_PVOP-1]); + + // Foxer: reign in overflow with huge frames + if (labs(overflow) > labs(rc->overflow)) { + overflow = rc->overflow; + } + + // Foxer: make sure overflow doesn't run away + + if (overflow > desired * rc->param.max_overflow_improvement / 100) { + desired += (overflow <= desired) ? desired * rc->param.max_overflow_improvement / 100 : + overflow * rc->param.max_overflow_improvement / 100; + }else if (overflow < desired * rc->param.max_overflow_degradation / -100){ + desired += desired * rc->param.max_overflow_degradation / -100; + }else{ + desired += overflow; + } + + if (desired > rc->max_length) { + capped_to_max_framesize = 1; + desired = rc->max_length; + } + + // make sure to not scale below the minimum framesize + if (desired < rc->min_length[s->type-1]) { + desired = rc->min_length[s->type-1]; + } - // very 'simple' quant<->filesize relationship - data->quant= (s->quant * s->length) / desired; - if (data->quant < 1) { - data->quant = 1; - } else if (data->quant > 31) { - data->quant = 31; - } - else if (s->type != XVID_TYPE_IVOP) - { - // Foxer: aid desired quantizer precision by accumulating decision error - if (s->type== XVID_TYPE_BVOP) { - rc->bquant_error[data->quant] += ((double)(s->quant * s->length) / desired) - data->quant; - - if (rc->bquant_error[data->quant] >= 1.0) { - rc->bquant_error[data->quant] -= 1.0; - data->quant++; - } - }else{ - rc->pquant_error[data->quant] += ((double)(s->quant * s->length) / desired) - data->quant; + // very 'simple' quant<->filesize relationship + data->quant= (s->quant * s->length) / desired; - if (rc->pquant_error[data->quant] >= 1.0) { - rc->pquant_error[data->quant] -= 1.0; - ++data->quant; - } - } - } + if (data->quant < 1) { + data->quant = 1; + } else if (data->quant > 31) { + data->quant = 31; + } + else if (s->type != XVID_TYPE_IVOP) + { + // Foxer: aid desired quantizer precision by accumulating decision error + if (s->type== XVID_TYPE_BVOP) { + rc->bquant_error[data->quant] += ((double)(s->quant * s->length) / desired) - data->quant; + + if (rc->bquant_error[data->quant] >= 1.0) { + rc->bquant_error[data->quant] -= 1.0; + data->quant++; + } + }else{ + rc->pquant_error[data->quant] += ((double)(s->quant * s->length) / desired) - data->quant; + + if (rc->pquant_error[data->quant] >= 1.0) { + rc->pquant_error[data->quant] -= 1.0; + ++data->quant; + } + } + } + + /* cap to min/max quant */ + + if (data->quant < data->min_quant[s->type-1]) { + data->quant = data->min_quant[s->type-1]; + }else if (data->quant > data->max_quant[s->type-1]) { + data->quant = data->max_quant[s->type-1]; + } - /* cap to min/max quant */ + /* subsequent p/b frame quants can only be +- 2 */ + if (s->type != XVID_TYPE_IVOP && rc->last_quant[s->type-1] && capped_to_max_framesize == 0) { - if (data->quant < rc->param.min_quant[s->type-1]) { - data->quant = rc->param.min_quant[s->type-1]; - }else if (data->quant > rc->param.max_quant[s->type-1]) { - data->quant = rc->param.max_quant[s->type-1]; - } + if (data->quant > rc->last_quant[s->type-1] + 2) { + data->quant = rc->last_quant[s->type-1] + 2; + DPRINTF(XVID_DEBUG_RC, "p/b-frame quantizer prevented from rising too steeply"); + } + if (data->quant < rc->last_quant[s->type-1] - 2) { + data->quant = rc->last_quant[s->type-1] - 2; + DPRINTF(XVID_DEBUG_RC, "p/b-frame quantizer prevented from falling too steeply"); + } + } - /* subsequent p/b frame quants can only be +- 2 */ - if (s->type != XVID_TYPE_IVOP && rc->last_quant[s->type-1] && capped_to_max_framesize == 0) { + if (capped_to_max_framesize == 0) { + rc->last_quant[s->type-1] = data->quant; + } - if (data->quant > rc->last_quant[s->type-1] + 2) { - data->quant = rc->last_quant[s->type-1] + 2; - DPRINTF(DPRINTF_RC, "p/b-frame quantizer prevented from rising too steeply"); - } - if (data->quant < rc->last_quant[s->type-1] - 2) { - data->quant = rc->last_quant[s->type-1] - 2; - DPRINTF(DPRINTF_RC, "p/b-frame quantizer prevented from falling too steeply"); - } - } + + } /* if */ - if (capped_to_max_framesize == 0) { - rc->last_quant[s->type-1] = data->quant; - } + } - return 0; + return 0; } @@ -957,7 +1006,7 @@ rc->KFoverflow -= rc->KFoverflow_partial; } - printf("[%i] quant:%i stats1:%i scaled:%i actual:%i overflow:%i\n", + DPRINTF(XVID_DEBUG_RC, "[%i] quant:%i stats1:%i scaled:%i actual:%i overflow:%i\n", data->frame_num, data->quant, s->length,