changeset 7331:7ec253a97341

Import transcode-0.6.1.20020829 XviD VBR Library into mencoder DivX4 encoder
author kmkaplan
date Mon, 09 Sep 2002 11:47:54 +0000
parents 2f3fe8274028
children dd32b0c95c95
files Makefile mencoder.c xvid_vbr.c xvid_vbr.h
diffstat 4 files changed, 1876 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Mon Sep 09 04:16:16 2002 +0000
+++ b/Makefile	Mon Sep 09 11:47:54 2002 +0000
@@ -27,7 +27,7 @@
 INSTALL = install
 
 SRCS_COMMON = cpudetect.c codec-cfg.c cfgparser.c my_profile.c spudec.c playtree.c playtreeparser.c asxparser.c vobsub.c subreader.c sub_cc.c find_sub.c
-SRCS_MENCODER = mencoder.c mp_msg-mencoder.c $(SRCS_COMMON) libao2/afmt.c divx4_vbr.c libvo/aclib.c libvo/osd.c libvo/sub.c libvo/font_load.c libvo/font_load_ft.c me-opt-reg.c
+SRCS_MENCODER = mencoder.c mp_msg-mencoder.c $(SRCS_COMMON) libao2/afmt.c divx4_vbr.c libvo/aclib.c libvo/osd.c libvo/sub.c libvo/font_load.c libvo/font_load_ft.c me-opt-reg.c xvid_vbr.c
 SRCS_MPLAYER = mplayer.c mp_msg.c $(SRCS_COMMON) mixer.c mp-opt-reg.c
 
 OBJS_MENCODER = $(SRCS_MENCODER:.c=.o)
--- a/mencoder.c	Mon Sep 09 04:16:16 2002 +0000
+++ b/mencoder.c	Mon Sep 09 11:47:54 2002 +0000
@@ -1239,6 +1239,8 @@
 printf(MSGTR_AudioStreamResult,
     (float)(mux_a->size/mux_a->timer*8.0f/1000.0f), (int)(mux_a->size/mux_a->timer), (int)mux_a->size, (float)mux_a->timer);
 
+if(sh_video) uninit_video(sh_video);
+sh_video=NULL;
 if(stream) free_stream(stream); // kill cache thread
 
 return interrupted;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xvid_vbr.c	Mon Sep 09 11:47:54 2002 +0000
@@ -0,0 +1,1642 @@
+/******************************************************************************
+ *
+ *   XviD VBR Library
+ *   
+ *   Copyright (C) 2002 Edouard Gomez <ed.gomez@wanadoo.fr>
+ *
+ *   The curve treatment algorithm is based on work done by Foxer <email?> and
+ *   Dirk Knop <dknop@gwdg.de> for the XviD vfw dynamic library.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *****************************************************************************/
+
+/* Standard Headers */
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <math.h>
+
+/* Local headers */
+#include "xvid_vbr.h"
+
+/******************************************************************************
+ * Build time constants
+ *****************************************************************************/
+
+/*
+ * Portability note
+ * Perhaps the msvc headers define Pi with another constant name
+ */
+#define DEG2RAD (M_PI / 180.0)
+
+/* Defaults settings will be computed with the help of these constants */
+#define DEFAULT_DESIRED_SIZE    700
+#define DEFAULT_AUDIO_BITRATE   128
+#define DEFAULT_MOVIE_LENGTH      2
+#define DEFAULT_TWOPASS_BOOST   150
+#define DEFAULT_FPS           25.0f
+#define DEFAULT_CREDITS_SIZE     10
+
+#define DEFAULT_XVID_DBG_FILE   "xvid.dbg"
+#define DEFAULT_XVID_STATS_FILE "xvid.stats"
+
+
+/******************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+
+/* Sub vbrInit cases functions */
+static vbr_init_function vbr_init_dummy;
+static vbr_init_function vbr_init_2pass1;
+static vbr_init_function vbr_init_2pass2;
+static vbr_init_function vbr_init_fixedquant;
+
+/* Sub vbrGetQuant cases functions */
+static vbr_get_quant_function vbr_getquant_1pass;
+static vbr_get_quant_function vbr_getquant_2pass1;
+static vbr_get_quant_function vbr_getquant_2pass2;
+static vbr_get_quant_function vbr_getquant_fixedquant;
+
+/* Sub vbrGetIntra cases functions */
+static vbr_get_intra_function vbr_getintra_1pass;
+static vbr_get_intra_function vbr_getintra_2pass1;
+static vbr_get_intra_function vbr_getintra_2pass2;
+static vbr_get_intra_function vbr_getintra_fixedquant;
+
+/* Sub vbrUpdate prototypes */
+static vbr_update_function vbr_update_dummy;
+static vbr_update_function vbr_update_2pass1;
+static vbr_update_function vbr_update_2pass2;
+
+/* Sub vbrFinish cases functions */
+static vbr_finish_function vbr_finish_dummy;
+static vbr_finish_function vbr_finish_2pass1;
+static vbr_finish_function vbr_finish_2pass2;
+
+/* Is the encoder in the credits */
+#define FRAME_TYPE_NORMAL_MOVIE     0x00
+#define FRAME_TYPE_STARTING_CREDITS 0x01
+#define FRAME_TYPE_ENDING_CREDITS   0x02
+
+/******************************************************************************
+ * Inline utility functions
+ *****************************************************************************/
+
+static __inline int util_frametype(vbr_control_t *state)
+{
+
+	if(state->credits_start) {
+
+		if(state->cur_frame >= state->credits_start_begin &&
+		   state->cur_frame < state->credits_start_end)
+			return(FRAME_TYPE_STARTING_CREDITS);
+
+	}
+
+	if(state->credits_end) {
+
+		if(state->cur_frame >= state->credits_end_begin &&
+		   state->cur_frame < state->credits_end_end)
+			return(FRAME_TYPE_STARTING_CREDITS);
+
+	}
+
+	return(FRAME_TYPE_NORMAL_MOVIE);
+
+
+}
+
+static __inline int util_creditsframes(vbr_control_t *state)
+{
+
+	int frames = 0;
+
+	if(state->credits_start)
+		frames += state->credits_start_end - state->credits_start_begin;
+	if(state->credits_end)
+		frames += state->credits_end_end - state->credits_end_begin;
+
+	return(frames);
+
+}
+
+/******************************************************************************
+ * Functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Function description :
+ *
+ * This function initialiazes the vbr_control_t with safe defaults for all
+ * modes.
+ *
+ * Return Values :
+ *   = 0
+ ****************************************************************************/
+
+int vbrSetDefaults(vbr_control_t *state)
+{
+
+	/* Set all the structure to zero */
+	memset(state, 0, sizeof(state));
+
+	/* Default mode is CBR */
+	state->mode = VBR_MODE_1PASS;
+
+	/* Default statistic filename */
+	state->filename = DEFAULT_XVID_STATS_FILE;
+
+	/* Default is a 2hour movie on 700Mo CD-ROM + 128kbit sound track */
+	state->desired_size = DEFAULT_DESIRED_SIZE*1024*1024 -
+		DEFAULT_MOVIE_LENGTH*3600*DEFAULT_AUDIO_BITRATE*1000/8;
+
+	/* Credits */
+	state->credits_mode = VBR_CREDITS_MODE_RATE;
+	state->credits_start = 0;
+	state->credits_start_begin = 0;
+	state->credits_start_end = 0;
+	state->credits_end = 0;
+	state->credits_end_begin = 0;
+	state->credits_end_end = 0;
+	state->credits_quant_ratio = 20;
+	state->credits_fixed_quant = 20;
+	state->credits_quant_i = 20;
+	state->credits_quant_p = 20;
+	state->credits_start_size = DEFAULT_CREDITS_SIZE*1024*1024;
+	state->credits_end_size = DEFAULT_CREDITS_SIZE*1024*1024;
+
+	/* Keyframe boost */
+	state->keyframe_boost = 0;
+	state->kftreshold = 10;
+	state->kfreduction = 20;
+	state->min_key_interval = 1;
+	state->max_key_interval = (int)DEFAULT_FPS*10;
+
+	/* Normal curve treatment */
+	state->curve_compression_high = 25;
+	state->curve_compression_low = 10;
+
+	/* Alt curve */
+	state->use_alt_curve = 1;
+	state->alt_curve_type = VBR_ALT_CURVE_LINEAR; 
+	state->alt_curve_low_dist = 90;
+	state->alt_curve_high_dist = 500;
+	state->alt_curve_min_rel_qual = 50;
+	state->alt_curve_use_auto = 1;
+	state->alt_curve_auto_str = 30;
+	state->alt_curve_use_auto_bonus_bias = 1;
+	state->alt_curve_bonus_bias = 50;
+	state->bitrate_payback_method = VBR_PAYBACK_BIAS;
+	state->bitrate_payback_delay = 250;
+	state->twopass_max_bitrate = state->desired_size*8 / (120*60);
+	state->twopass_max_overflow_improvement = 60;
+	state->twopass_max_overflow_degradation = 60;
+	state->max_iquant = 31;
+	state->min_iquant = 1;
+	state->max_pquant = 31;
+	state->min_pquant = 1;
+	state->fixed_quant = 3;
+
+	state->max_framesize = (1.0/(float)DEFAULT_FPS) * state->twopass_max_bitrate / 8;
+
+	state->fps = (float)DEFAULT_FPS;
+
+	return(0);
+
+}
+
+/*****************************************************************************
+ * Function description :
+ *
+ * This function initialiaze the vbr_control_t state passed in parameter.
+ * 
+ * The initialization depends on state->mode, there are 4 modes allowed.
+ * Each mode description is done in the README file shipped with the lib.
+ *
+ * Return values :
+ *
+ *    =  0 on success
+ *    = -1 on error
+ *****************************************************************************/
+
+int vbrInit(vbr_control_t *state)
+{
+
+	if(state == NULL) return(-1);
+
+	/* Function pointers safe initialization */
+	state->init     = NULL;
+	state->getquant = NULL;
+	state->getintra = NULL;
+	state->update   = NULL;
+	state->finish   = NULL;
+
+	if(state->debug) {
+
+		state->debug_file = fopen(DEFAULT_XVID_DBG_FILE, "w+");
+
+		if(state->debug_file == NULL)
+			return(-1);
+
+		setvbuf(state->debug_file, NULL, _IOLBF, 0);
+		fprintf(state->debug_file, "# XviD Debug output\n");
+		fprintf(state->debug_file, "# quant | intra | header bytes"
+			"| total bytes | kblocks | mblocks | ublocks"
+			"| vbr overflow | vbr kf overflow"
+			"| vbr kf partial overflow\n\n");
+	}
+
+	/* Function pointers sub case initialization */
+	switch(state->mode) {
+	case VBR_MODE_1PASS:
+		state->init     = vbr_init_dummy;
+		state->getquant = vbr_getquant_1pass;
+		state->getintra = vbr_getintra_1pass;
+		state->update   = vbr_update_dummy;
+		state->finish   = vbr_finish_dummy;
+		break;
+	case VBR_MODE_2PASS_1:
+		state->init     = vbr_init_2pass1;
+		state->getquant = vbr_getquant_2pass1;
+		state->getintra = vbr_getintra_2pass1;
+		state->update   = vbr_update_2pass1;
+		state->finish   = vbr_finish_2pass1;
+		break;
+	case VBR_MODE_FIXED_QUANT:
+		state->init     = vbr_init_fixedquant;
+		state->getquant = vbr_getquant_fixedquant;
+		state->getintra = vbr_getintra_fixedquant;
+		state->update   = vbr_update_dummy;
+		state->finish   = vbr_finish_dummy;
+		break;
+	case VBR_MODE_2PASS_2:
+		state->init     = vbr_init_2pass2;
+		state->getintra = vbr_getintra_2pass2;
+		state->getquant = vbr_getquant_2pass2;
+		state->update   = vbr_update_2pass2;
+		state->finish   = vbr_finish_2pass2;
+		break;
+	default:
+		return(-1);
+	}
+	
+	return(state->init(state));
+
+}
+
+/******************************************************************************
+ * Function description :
+ *
+ * This function returns an adapted quantizer according to the current vbr
+ * controler state
+ *
+ * Return values :
+ *  the quantizer value (0 <= value <= 31)
+ *  (0 is a special case, means : let XviD decide)
+ *
+ *****************************************************************************/
+
+int vbrGetQuant(vbr_control_t *state)
+{
+
+	/* Returns Zero, so XviD decides alone */
+	if(state == NULL || state->getquant == NULL) return(0);
+
+	return(state->getquant(state));
+
+}
+
+/******************************************************************************
+ * Function description :
+ *
+ * This function returns the type of the frame to be encoded next (I or P/B)
+ *
+ * Return values :
+ *  = -1 let the XviD encoder decide wether or not the next frame is I
+ *  =  0 no I frame
+ *  =  1 force keyframe
+ *
+ *****************************************************************************/
+
+int vbrGetIntra(vbr_control_t *state)
+{
+
+	/* Returns -1, means let XviD decide */
+	if(state == NULL || state->getintra == NULL) return(-1);
+
+	return(state->getintra(state));
+
+}
+
+/******************************************************************************
+ * Function description :
+ *
+ * This function updates the vbr control state according to collected statistics
+ * from XviD core
+ *
+ * Return values :
+ *
+ *    =  0 on success
+ *    = -1 on error
+ *****************************************************************************/
+
+int vbrUpdate(vbr_control_t *state,
+	      int quant,
+	      int intra,
+	      int header_bytes,
+	      int total_bytes,
+	      int kblocks,
+	      int mblocks,
+	      int ublocks)
+{
+
+	if(state == NULL || state->update == NULL) return(-1);
+
+	if(state->debug && state->debug_file != NULL) {
+		int idx;
+
+		fprintf(state->debug_file, "%d %d %d %d %d %d %d %d %d %d\n",
+			quant, intra, header_bytes, total_bytes, kblocks,
+			mblocks, ublocks, state->overflow, state->KFoverflow,
+			state->KFoverflow_partial);
+
+		idx = quant;
+
+		if(quant < 1)
+			idx = 1;
+		if(quant > 31)
+			idx = 31;
+
+		idx--;
+
+		state->debug_quant_count[idx]++; 
+
+	}
+
+	return(state->update(state, quant, intra, header_bytes, total_bytes,
+			     kblocks, mblocks, ublocks));
+
+}
+
+/******************************************************************************
+ * Function description :
+ *
+ * This function stops the vbr controller
+ *
+ * Return values :
+ *
+ *    =  0 on success
+ *    = -1 on error
+ *****************************************************************************/
+
+int vbrFinish(vbr_control_t *state)
+{
+
+	if(state == NULL || state->finish == NULL) return(-1);
+
+	if(state->debug && state->debug_file != NULL) {
+
+		int i;
+
+		fprintf(state->debug_file, "\n\n");
+
+		for(i=0; i<79; i++)
+			fprintf(state->debug_file, "#");
+
+		fprintf(state->debug_file, "\n# Quantizer distribution :\n\n");
+
+		for(i=0;i<32; i++) {
+
+			fprintf(state->debug_file, "# quant %d : %d\n",
+				i+1,
+				state->debug_quant_count[i]);
+
+		}
+
+		fclose(state->debug_file);
+
+	}
+
+	return(state->finish(state));
+
+}
+
+/******************************************************************************
+ * Dummy functions - Used when a mode does not need such a function
+ *****************************************************************************/
+
+static int vbr_init_dummy(void *sstate)
+{
+
+	vbr_control_t *state = sstate;
+
+	state->cur_frame = 0;
+
+	return(0);
+
+}
+
+static int vbr_update_dummy(void *state,
+			    int quant,
+			    int intra,
+			    int header_bytes,
+			    int total_bytes,
+			    int kblocks,
+			    int mblocks,
+			    int ublocks)
+{
+
+	((vbr_control_t*)state)->cur_frame++;
+
+	return(0);
+
+}
+
+static int vbr_finish_dummy(void *state)
+{
+
+	return(0);
+
+}
+
+/******************************************************************************
+ * 1 pass mode - XviD will do its job alone.
+ *****************************************************************************/
+
+static int vbr_getquant_1pass(void *state)
+{
+
+	return(0);
+
+}
+
+static int vbr_getintra_1pass(void *state)
+{
+
+	return(-1);
+
+}
+
+/******************************************************************************
+ * 2 pass mode - first pass functions
+ *****************************************************************************/
+
+static int vbr_init_2pass1(void *sstate)
+{
+
+	FILE *f;
+	vbr_control_t *state = sstate;
+
+	/* Check the filename */
+	if(state->filename == NULL || state->filename[0] == '\0')
+		return(-1);
+
+	/* Initialize safe defaults for 2pass 1 */ 
+	state->pass1_file = NULL;
+	state->nb_frames = 0;
+	state->nb_keyframes = 0;
+	state->cur_frame = 0;
+
+	/* Open the 1st pass file */
+	if((f = fopen(state->filename, "w+")) == NULL)
+		return(-1);
+
+	/*
+	 * The File Header
+	 *
+	 * The extra white spaces will be used during the vbrFinish to write
+	 * the resulting number of frames and keyframes (10 spaces == maximum
+	 * string length of an int on 32bit machines, i don't think anyone is
+	 * encoding more than 4 billion frames :-)
+	 */
+	fprintf(f, "# ASCII XviD vbr stat file version %d\n#\n", VBR_VERSION);
+	fprintf(f, "# frames    :           \n");
+	fprintf(f, "# keyframes :           \n");
+	fprintf(f, "#\n# quant | intra | header bytes | total bytes | kblocks |"
+		" mblocks | ublocks\n\n"); 
+
+	/* Save file pointer */
+	state->pass1_file   = f;
+
+	return(0);
+
+}
+
+static int vbr_getquant_2pass1(void *state)
+{
+
+	return(2);
+
+}
+
+static int vbr_getintra_2pass1(void *state)
+{
+
+	return(-1);
+
+}
+
+static int vbr_update_2pass1(void *sstate,
+			     int quant,
+			     int intra,
+			     int header_bytes,
+			     int total_bytes,
+			     int kblocks,
+			     int mblocks,
+			     int ublocks)
+			     
+
+{
+
+	vbr_control_t *state = sstate;
+
+	if(state->pass1_file == NULL)
+		return(-1);
+
+	/* Writes the resulting statistics */
+	fprintf(state->pass1_file, "%d %d %d %d %d %d %d\n",
+		quant,
+		intra,
+		header_bytes,
+		total_bytes,
+		kblocks,
+		mblocks,
+		ublocks);
+
+	/* Update vbr control state */
+	if(intra) state->nb_keyframes++;
+	state->nb_frames++;
+	state->cur_frame++;
+
+	return(0);
+	
+}
+
+static int vbr_finish_2pass1(void *sstate)
+{
+
+	int c, i;
+	vbr_control_t *state = sstate;
+
+	if(state->pass1_file == NULL)
+		return(-1);
+
+	/* Goto to the file beginning */
+	fseek(state->pass1_file, 0, SEEK_SET);
+
+	/* Skip the version line  and the empty line */
+	c = i = 0;
+	do {
+		c = fgetc(state->pass1_file);
+
+		if(c == EOF) return(-1);
+		if(c == '\n') i++;
+
+	}while(i < 2);
+
+	/* Overwrite the frame field - safe as we have written extra spaces */
+	fprintf(state->pass1_file, "# frames    : %.10d\n", state->nb_frames);
+
+	/* Overwrite the keyframe field */
+	fprintf(state->pass1_file, "# keyframes : %.10d\n",
+		state->nb_keyframes);
+
+	/* Close the file */
+	if(fclose(state->pass1_file) != 0)
+		return(-1);
+
+	return(0);
+
+}
+
+/******************************************************************************
+ * 2 pass mode - 2nd pass functions (Need to be finished)
+ *****************************************************************************/
+
+static int vbr_init_2pass2(void *sstate)
+{
+
+	FILE *f;
+	int c, n, pos_firstframe, credits_frames;
+	long long credits1_bytes;
+	long long credits2_bytes;
+	long long desired;
+	long long total_bytes;
+	long long itotal_bytes;
+	long long start_curved;
+	long long end_curved;
+	double total1;
+	double total2;
+
+	vbr_control_t *state = sstate;
+
+	/* Check the filename */
+	if(state->filename == NULL || state->filename[0] == '\0')
+		return(-1);
+
+	/* Initialize safe defaults for 2pass 2 */ 
+	state->pass1_file = NULL;
+	state->nb_frames = 0;
+	state->nb_keyframes = 0;
+
+	/* Open the 1st pass file */
+	if((f = fopen(state->filename, "r")) == NULL)
+		return(-1);
+
+	state->pass1_file = f;
+
+	/* Get the file version and check against current version */
+	fscanf(state->pass1_file, "# ASCII XviD vbr stat file version %d\n", &n);
+
+	if(n != VBR_VERSION) {
+		fclose(state->pass1_file);
+		state->pass1_file = NULL;
+		return(-1);
+	}
+
+	/* Skip the blank commented line */
+	c = n = 0;
+	do {
+
+		c = fgetc(state->pass1_file);
+
+		if(c == EOF) {
+			fclose(state->pass1_file);
+			state->pass1_file = NULL;
+			return(-1);
+		}
+
+		if(c == '\n') n++;
+
+	}while(n < 1);
+
+
+	/* Get the number of frames */
+	fscanf(state->pass1_file, "# frames : %d\n", &state->nb_frames);
+
+	/* Compute the desired size */
+	state->desired_size = (long long)
+		(((long long)state->nb_frames * (long long)state->desired_bitrate) /
+		 (state->fps * 8.0));
+
+	/* Get the number of keyframes */
+	fscanf(state->pass1_file, "# keyframes : %d\n", &state->nb_keyframes);
+
+	/* Allocate memory space for the keyframe_location array */
+	if((state->keyframe_locations
+	    = (int*)malloc((state->nb_keyframes+1)*sizeof(int))) == NULL) {
+		fclose(state->pass1_file);
+		state->pass1_file = NULL;
+		return(-1);
+	}
+
+	/* Skip the blank commented line and the colum description */
+	c = n = 0;
+	do {
+
+		c = fgetc(state->pass1_file);
+
+		if(c == EOF) {
+			fclose(state->pass1_file);
+			state->pass1_file = NULL;
+			return(-1);
+		}
+
+		if(c == '\n') n++;
+
+	}while(n < 2);
+
+	/* Save position for future use */
+	pos_firstframe = ftell(state->pass1_file);
+
+	/* Read and initialize some variables */
+	credits1_bytes = credits2_bytes = 0;
+	total_bytes = itotal_bytes = 0;
+	start_curved = end_curved = 0;
+	credits_frames = 0;
+
+	for(state->cur_frame = c = 0; state->cur_frame<state->nb_frames; state->cur_frame++) {
+
+		int quant, keyframe, frame_hbytes, frame_bytes;
+		int kblocks, mblocks, ublocks;
+
+		fscanf(state->pass1_file, "%d %d %d %d %d %d %d\n",
+		       &quant, &keyframe, &frame_hbytes, &frame_bytes,
+		       &kblocks, &mblocks, &ublocks);
+
+		/* Is the frame in the beginning credits */
+		if(util_frametype(state) == FRAME_TYPE_STARTING_CREDITS) {
+			credits1_bytes += frame_bytes;
+			credits_frames++;
+			continue;
+		}
+
+		/* Is the frame in the eding credits */
+		if(util_frametype(state) == FRAME_TYPE_ENDING_CREDITS) {
+			credits2_bytes += frame_bytes;
+			credits_frames++;
+			continue;
+		}
+
+		/* We only care about Keyframes when not in credits */
+		if(keyframe) {
+			itotal_bytes +=	frame_bytes + frame_bytes *
+				state->keyframe_boost / 100;
+			total_bytes  += frame_bytes *
+				state->keyframe_boost / 100;
+			state->keyframe_locations[c++] = state->cur_frame;
+		}
+
+		total_bytes += frame_bytes;		
+
+	}
+
+	/*
+	 * Last frame is treated like an I Frame so we can dispatch overflow
+	 * all other the last film segment
+	 */
+	state->keyframe_locations[c] = state->cur_frame;
+
+	/* Compensate AVI overhead */
+	desired = state->desired_size -  state->nb_frames*24;
+
+	switch(state->credits_mode) {
+	case VBR_CREDITS_MODE_QUANT :
+
+		state->movie_curve = (double)
+			(total_bytes - credits1_bytes - credits2_bytes) /
+			(desired  - credits1_bytes - credits2_bytes);
+
+		start_curved = credits1_bytes;
+		end_curved   = credits2_bytes;
+
+		break;
+	case VBR_CREDITS_MODE_SIZE:
+
+		/* start curve = (start / start desired size) */
+		state->credits_start_curve = (double)
+			(credits1_bytes / state->credits_start_size);
+
+		/* end curve = (end / end desired size) */
+		state->credits_end_curve = (double)
+			(credits2_bytes / state->credits_end_size);
+
+		start_curved = (long long)
+			(credits1_bytes / state->credits_start_curve);
+
+		end_curved   = (long long)
+			(credits2_bytes / state->credits_end_curve);
+
+		/* movie curve=(total-credits)/(desired_size-curved credits) */
+		state->movie_curve = (double)
+			(total_bytes - credits1_bytes - credits2_bytes) /
+			(desired - start_curved - end_curved);
+
+		break;
+	case VBR_CREDITS_MODE_RATE:
+	default:
+
+		/* credits curve = (total/desired_size)*(100/credits_rate) */
+		state->credits_start_curve = state->credits_end_curve =
+			((double)total_bytes / desired) *
+			((double)100 / state->credits_quant_ratio);
+
+		start_curved =
+			(long long)(credits1_bytes/state->credits_start_curve);
+
+		end_curved   =
+			(long long)(credits2_bytes/state->credits_end_curve);
+
+		state->movie_curve = (double)
+			(total_bytes - credits1_bytes - credits2_bytes) /
+			(desired - start_curved - end_curved);
+
+		break;
+	}
+
+	/*
+	 * average frame size = (desired - curved credits - curved keyframes) /
+	 *                      (frames - credits frames - keyframes)
+	 */
+	state->average_frame = (double)
+		(desired - start_curved - end_curved -
+		 (itotal_bytes / state->movie_curve)) /
+		(state->nb_frames - util_creditsframes(state) -
+		 state->nb_keyframes);
+
+	/* Initialize alt curve parameters */
+	if (state->use_alt_curve) {
+
+		state->alt_curve_low =
+			state->average_frame - state->average_frame *
+			(double)(state->alt_curve_low_dist / 100.0);
+
+		state->alt_curve_low_diff =
+			state->average_frame - state->alt_curve_low;
+
+		state->alt_curve_high =
+			state->average_frame + state->average_frame *
+			(double)(state->alt_curve_high_dist / 100.0);
+
+		state->alt_curve_high_diff =
+			state->alt_curve_high - state->average_frame;
+
+		if (state->alt_curve_use_auto) {
+
+			if (state->movie_curve > 1.0)	{
+
+				state->alt_curve_min_rel_qual =
+					(int)(100.0 - (100.0 - 100.0 / state->movie_curve) *
+					      (double)state->alt_curve_auto_str / 100.0);
+
+				if (state->alt_curve_min_rel_qual < 20)
+					state->alt_curve_min_rel_qual = 20;
+			}
+			else {
+				state->alt_curve_min_rel_qual = 100;
+			}
+
+		}
+
+		state->alt_curve_mid_qual =
+		(1.0 + (double)state->alt_curve_min_rel_qual / 100.0) / 2.0;
+
+		state->alt_curve_qual_dev = 1.0 - state->alt_curve_mid_qual;
+
+		if (state->alt_curve_low_dist > 100) {
+
+			switch(state->alt_curve_type) {
+			case VBR_ALT_CURVE_AGGRESIVE:
+				/* Sine Curve (high aggressiveness) */
+				state->alt_curve_qual_dev *=
+					2.0 /
+					(1.0 +  sin(DEG2RAD * (state->average_frame * 90.0 / state->alt_curve_low_diff)));
+
+				state->alt_curve_mid_qual =
+					1.0 - state->alt_curve_qual_dev *
+					sin(DEG2RAD * (state->average_frame * 90.0 / state->alt_curve_low_diff));
+				break;
+
+			default:
+			case VBR_ALT_CURVE_LINEAR:
+				/* Linear (medium aggressiveness) */
+				state->alt_curve_qual_dev *=
+					2.0 /
+					(1.0 + state->average_frame / state->alt_curve_low_diff);
+
+				state->alt_curve_mid_qual =
+					1.0 - state->alt_curve_qual_dev *
+					state->average_frame / state->alt_curve_low_diff;
+
+				break;
+
+			case VBR_ALT_CURVE_SOFT:
+				/* Cosine Curve (low aggressiveness) */
+				state->alt_curve_qual_dev *=
+					2.0 /
+					(1.0 + (1.0 - cos(DEG2RAD * (state->average_frame * 90.0 / state->alt_curve_low_diff))));
+
+				state->alt_curve_mid_qual =
+					1.0 - state->alt_curve_qual_dev *
+					(1.0 - cos(DEG2RAD * (state->average_frame * 90.0 / state->alt_curve_low_diff)));
+
+				break;
+			}
+		}
+	}
+
+	/* Go to the first non credits frame stats line into file */
+	fseek(state->pass1_file, pos_firstframe, SEEK_SET);
+
+	/* Perform prepass to compensate for over/undersizing */
+	total1 = total2 = 0.0;
+	for(state->cur_frame=0; state->cur_frame<state->nb_frames; state->cur_frame++) {
+
+		int quant, keyframe, frame_hbytes, frame_bytes;
+		int kblocks, mblocks, ublocks;
+
+		fscanf(state->pass1_file, "%d %d %d %d %d %d %d\n",
+		       &quant, &keyframe, &frame_hbytes, &frame_bytes,
+		       &kblocks, &mblocks, &ublocks);
+
+		if(util_frametype(state) != FRAME_TYPE_NORMAL_MOVIE)
+			continue;
+
+		if(!keyframe) {
+
+			double dbytes = frame_bytes / state->movie_curve;
+			total1 += dbytes;
+
+			if (state->use_alt_curve) {
+
+				if (dbytes > state->average_frame) {
+
+					if (dbytes >= state->alt_curve_high) {
+						total2 += dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev);
+					}
+					else {
+
+						switch(state->alt_curve_type) {
+						case VBR_ALT_CURVE_AGGRESIVE:
+
+							total2 +=
+								dbytes *
+								(state->alt_curve_mid_qual - state->alt_curve_qual_dev *
+								 sin(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_high_diff)));
+							break;
+						default:
+						case VBR_ALT_CURVE_LINEAR:
+
+							total2 +=
+								dbytes *
+								(state->alt_curve_mid_qual - state->alt_curve_qual_dev *
+								 (dbytes - state->average_frame) / state->alt_curve_high_diff);
+							break;
+						case VBR_ALT_CURVE_SOFT:
+							total2 +=
+								dbytes *
+								(state->alt_curve_mid_qual - state->alt_curve_qual_dev *
+								 (1.0 - cos(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_high_diff))));
+						}
+					}
+				}
+				else {
+
+					if (dbytes <= state->alt_curve_low) {
+						total2 += dbytes;
+					}
+					else {
+
+						switch(state->alt_curve_type) {
+						case VBR_ALT_CURVE_AGGRESIVE:
+							total2 +=
+								dbytes *
+								(state->alt_curve_mid_qual - state->alt_curve_qual_dev *
+								 sin(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_low_diff)));
+							break;
+						default:
+						case VBR_ALT_CURVE_LINEAR:
+							total2 +=
+								dbytes * 
+								(state->alt_curve_mid_qual - state->alt_curve_qual_dev *
+								 (dbytes - state->average_frame) / state->alt_curve_low_diff);
+							break;
+						case VBR_ALT_CURVE_SOFT:
+							total2 +=
+								dbytes *
+								(state->alt_curve_mid_qual + state->alt_curve_qual_dev *
+								 (1.0 - cos(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_low_diff))));
+						}
+					}
+				}
+			}
+			else {
+				if (dbytes > state->average_frame) {
+					total2 +=
+						((double)dbytes +
+						 (state->average_frame - dbytes) *
+						 state->curve_compression_high / 100.0);
+				}
+				else {
+					total2 +=
+						((double)dbytes +
+						 (state->average_frame - dbytes) *
+						 state->curve_compression_low / 100.0);
+				}
+			}
+		}
+	}
+	
+	state->curve_comp_scale = total1 / total2;
+
+	if (state->use_alt_curve) {
+
+		double curve_temp, dbytes;
+		int newquant, percent;
+		int oldquant = 1;
+
+		if (state->alt_curve_use_auto_bonus_bias)
+			state->alt_curve_bonus_bias = state->alt_curve_min_rel_qual;
+
+		state->curve_bias_bonus =
+			(total1 - total2) * (double)state->alt_curve_bonus_bias /
+			(100.0 * (double)(state->nb_frames - util_creditsframes(state) - state->nb_keyframes));
+		state->curve_comp_scale =
+			((total1 - total2) * (1.0 - (double)state->alt_curve_bonus_bias / 100.0) + total2) /
+			total2;
+
+
+		for (n=1; n <= (int)(state->alt_curve_high*2) + 1; n++) {
+			dbytes = n;
+			if (dbytes > state->average_frame)
+			{
+				if (dbytes >= state->alt_curve_high) {
+					curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev);
+				}
+				else {
+					switch(state->alt_curve_type) {
+					case VBR_ALT_CURVE_AGGRESIVE:
+						curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev *
+								       sin(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_high_diff)));
+						break;
+					default:
+					case VBR_ALT_CURVE_LINEAR:
+						curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev *
+								       (dbytes - state->average_frame) / state->alt_curve_high_diff);
+						break;
+					case VBR_ALT_CURVE_SOFT:
+						curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev *
+								       (1.0 - cos(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_high_diff))));
+					}
+				}
+			}
+			else {
+				if (dbytes <= state->alt_curve_low) {
+					curve_temp = dbytes;
+				}
+				else {
+					switch(state->alt_curve_type) {
+					case VBR_ALT_CURVE_AGGRESIVE:
+						curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev *
+								       sin(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_low_diff)));
+						break;
+					default:
+					case VBR_ALT_CURVE_LINEAR:
+						curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev *
+								       (dbytes - state->average_frame) / state->alt_curve_low_diff);
+						break;
+					case VBR_ALT_CURVE_SOFT:
+						curve_temp = dbytes * (state->alt_curve_mid_qual + state->alt_curve_qual_dev *
+								       (1.0 - cos(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_low_diff))));
+					}
+				}
+			}
+
+			if (state->movie_curve > 1.0)
+				dbytes *= state->movie_curve;
+
+			newquant = (int)(dbytes * 2.0 / (curve_temp * state->curve_comp_scale + state->curve_bias_bonus));
+			if (newquant > 1)
+			{
+				if (newquant != oldquant)
+				{
+					oldquant = newquant;
+					percent = (int)((n - state->average_frame) * 100.0 / state->average_frame);
+				}
+
+			}
+		      
+		}
+
+	}
+
+	state->overflow = 0;
+	state->KFoverflow = 0;
+	state->KFoverflow_partial = 0;
+	state->KF_idx = 1;
+
+	for (n=0 ; n < 32 ; n++) {
+		state->quant_error[n] = 0.0;
+		state->quant_count[n] = 0;
+	}
+
+	state->curve_comp_error = 0.0;
+	state->last_quant = 0;
+
+	/* Two pass maximum boost computed from frame mean */
+	state->twopass_max_bitrate = DEFAULT_TWOPASS_BOOST/100.0 *
+		state->average_frame * state->fps * 8;
+
+	state->max_framesize = state->average_frame *
+		DEFAULT_TWOPASS_BOOST/100.0;
+
+	/* Get back to the beginning of frame statistics */
+	fseek(state->pass1_file, pos_firstframe, SEEK_SET);
+
+	/* 
+	 * Small hack : We have to get next frame stats before the
+	 * getintra/quant calls
+	 * User clients update the data when they call vbrUpdate
+	 * we are just bypassing this because we don't have to update
+	 * the overflow and so on...
+	 */
+	{
+
+		/* Fake vars */
+		int next_hbytes, next_kblocks, next_mblocks, next_ublocks;
+ 
+		fscanf(state->pass1_file, "%d %d %d %d %d %d %d\n",
+		       &state->pass1_quant, &state->pass1_intra, &next_hbytes,
+		       &state->pass1_bytes, &next_kblocks, &next_mblocks,
+		       &next_ublocks);
+
+	}
+
+	/* Initialize the frame counter */
+	state->cur_frame = 0;
+	state->last_keyframe = 0;
+
+	return(0);
+
+}
+
+static int vbr_getquant_2pass2(void *sstate)
+{
+
+	int quant;
+	int intra;
+	int bytes1, bytes2;
+	int overflow;
+	int capped_to_max_framesize = 0;
+	int KFdistance, KF_min_size;
+	vbr_control_t *state = sstate;
+
+	bytes1 = state->pass1_bytes;
+	overflow = state->overflow / 8;
+	/* To shut up gcc warning */
+	bytes2 = bytes1;
+
+
+	if (state->pass1_intra)
+	{
+		overflow = 0;
+	}
+
+	if (util_frametype(state) != FRAME_TYPE_NORMAL_MOVIE) {
+
+
+		switch (state->credits_mode) {
+		case VBR_CREDITS_MODE_QUANT :
+			if (state->credits_quant_i != state->credits_quant_p) {
+				quant = state->pass1_intra ?
+					state->credits_quant_i:
+					state->credits_quant_p;
+			}
+			else {
+				quant = state->credits_quant_p;
+			}
+
+			state->bytes1 = bytes1;
+			state->bytes2 = bytes1;
+			state->desired_bytes2 = bytes1;
+			return(quant);
+		default:
+		case VBR_CREDITS_MODE_RATE :
+		case VBR_CREDITS_MODE_SIZE :
+			if(util_frametype(state) == FRAME_TYPE_STARTING_CREDITS)
+				bytes2 = (int)(bytes1 / state->credits_start_curve);
+			else
+				bytes2 = (int)(bytes1 / state->credits_end_curve);
+			break;
+		}
+	}
+	else {
+		/* Foxer: apply curve compression outside credits */
+		double dbytes, curve_temp;
+
+		bytes2 = bytes1;
+
+		if (state->pass1_intra)
+			dbytes = ((int)(bytes2 + bytes2 * state->keyframe_boost / 100)) /
+				state->movie_curve;
+		else
+			dbytes = bytes2 / state->movie_curve;
+
+		/* spread the compression error accross payback_delay frames */
+		if (state->bitrate_payback_method == VBR_PAYBACK_BIAS)	{
+			bytes2 = (int)(state->curve_comp_error / state->bitrate_payback_delay);
+		}
+		else {
+			bytes2 = (int)(state->curve_comp_error * dbytes /
+				state->average_frame / state->bitrate_payback_delay);
+
+			if (labs(bytes2) > fabs(state->curve_comp_error))
+				bytes2 = (int)state->curve_comp_error;
+		}
+
+		state->curve_comp_error -= bytes2;
+
+		if (state->use_alt_curve) {
+
+			if (!state->pass1_intra) {
+
+				if (dbytes > state->average_frame) {
+					if (dbytes >= state->alt_curve_high)
+						curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev);
+					else {
+						switch(state->alt_curve_type) {
+						case VBR_ALT_CURVE_AGGRESIVE:
+							curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev *
+									       sin(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_high_diff)));
+							break;
+						default:
+						case VBR_ALT_CURVE_LINEAR:
+							curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev *
+									       (dbytes - state->average_frame) / state->alt_curve_high_diff);
+							break;
+						case VBR_ALT_CURVE_SOFT:
+							curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev *
+									       (1.0 - cos(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_high_diff))));
+						}
+					}
+				}
+				else {
+					if (dbytes <= state->alt_curve_low)
+						curve_temp = dbytes;
+					else {
+						switch(state->alt_curve_type) {
+						case VBR_ALT_CURVE_AGGRESIVE:
+							curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev *
+									       sin(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_low_diff)));
+							break;
+						default:
+						case VBR_ALT_CURVE_LINEAR:
+							curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev *
+									       (dbytes - state->average_frame) / state->alt_curve_low_diff);
+							break;
+						case VBR_ALT_CURVE_SOFT:
+							curve_temp = dbytes * (state->alt_curve_mid_qual + state->alt_curve_qual_dev *
+									       (1.0 - cos(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_low_diff))));
+						}
+					}
+				}
+
+				curve_temp = curve_temp * state->curve_comp_scale + state->curve_bias_bonus;
+
+				bytes2 += ((int)curve_temp);
+				state->curve_comp_error += curve_temp - ((int)curve_temp);
+
+			}
+			else {
+				state->curve_comp_error += dbytes - ((int)dbytes);
+				bytes2 += ((int)dbytes);
+			}
+		}
+		else if ((state->curve_compression_high + state->curve_compression_low) &&
+			!state->pass1_intra) {
+
+			if (dbytes > state->average_frame) {
+				curve_temp = state->curve_comp_scale *
+					((double)dbytes + (state->average_frame - dbytes) *
+					state->curve_compression_high / 100.0);
+			}
+			else {
+				curve_temp = state->curve_comp_scale *
+					((double)dbytes + (state->average_frame - dbytes) *
+					state->curve_compression_low / 100.0);
+			}
+
+			bytes2 += ((int)curve_temp);
+			state->curve_comp_error += curve_temp - ((int)curve_temp);
+		}
+		else {
+			state->curve_comp_error += dbytes - ((int)dbytes);
+			bytes2 += ((int)dbytes);
+		}
+
+		/* cap bytes2 to first pass size, lowers number of quant=1 frames */
+		if (bytes2 > bytes1) {
+			state->curve_comp_error += bytes2 - bytes1;
+			bytes2 = bytes1;
+		}
+		else if (bytes2 < 1) {
+			state->curve_comp_error += --bytes2;
+			bytes2 = 1;
+		}
+	}
+
+	state->desired_bytes2 = bytes2;
+
+	/* Ugly dependance between getquant and getintra */
+	intra = state->getintra(state);
+
+	if(intra) {
+
+		KFdistance = state->keyframe_locations[state->KF_idx] -
+			state->keyframe_locations[state->KF_idx - 1];
+
+		if (KFdistance < state->kftreshold) {
+			KFdistance = KFdistance - state->min_key_interval;
+
+			if (KFdistance >= 0) {
+
+				KF_min_size = bytes2 * (100 - state->kfreduction) / 100;
+				if (KF_min_size < 1)
+					KF_min_size = 1;
+
+				bytes2 = KF_min_size + (bytes2 - KF_min_size) * KFdistance /
+					(state->kftreshold - state->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 / state->average_frame);
+
+	/* Foxer: reign in overflow with huge frames */
+	if (labs(overflow) > labs(state->overflow)) {
+		overflow = state->overflow;
+	}
+
+	/* Foxer: make sure overflow doesn't run away */
+	if(overflow > bytes2 * state->twopass_max_overflow_improvement / 100) {
+		bytes2 += (overflow <= bytes2) ? bytes2 * state->twopass_max_overflow_improvement / 100 :
+			overflow * state->twopass_max_overflow_improvement / 100;
+	}
+	else if(overflow < bytes2 * state->twopass_max_overflow_degradation / -100) {
+		bytes2 += bytes2 * state->twopass_max_overflow_degradation / -100;
+	}
+	else {
+		bytes2 += overflow;
+	}
+
+	if(bytes2 > state->max_framesize) {
+		capped_to_max_framesize = 1;
+		bytes2 = state->max_framesize;
+	}
+
+	if(bytes2 < 1) {
+		bytes2 = 1;
+	}
+
+	state->bytes1 = bytes1;
+	state->bytes2 = bytes2;
+
+	/* very 'simple' quant<->filesize relationship */
+	quant = state->pass1_quant * bytes1 / bytes2;
+
+	if(quant < 1)
+		quant = 1;
+	else if(quant > 31)
+		quant = 31;
+	else if(!state->pass1_intra) {
+
+		/* Foxer: aid desired quantizer precision by accumulating decision error */
+		state->quant_error[quant] += ((double)(state->pass1_quant * bytes1) / bytes2) - quant;
+
+		if (state->quant_error[quant] >= 1.0) {
+			state->quant_error[quant] -= 1.0;
+			quant++;
+		}
+	}
+
+	/* we're done with credits */
+	if(util_frametype(state) != FRAME_TYPE_NORMAL_MOVIE) {
+		return(quant);
+	}
+
+	if(intra) {
+
+		if (quant < state->min_iquant)
+			quant = state->min_iquant;
+		if (quant > state->max_iquant)
+			quant = state->max_iquant;
+	}
+	else {
+
+		if(quant > state->max_pquant)
+			quant = state->max_pquant;
+		if(quant < state->min_pquant)
+			quant = state->min_pquant;
+
+		/* subsequent frame quants can only be +- 2 */
+		if(state->last_quant && capped_to_max_framesize == 0) {
+			if (quant > state->last_quant + 2)
+				quant = state->last_quant + 2;
+			if (quant < state->last_quant - 2)
+				quant = state->last_quant - 2;
+		}
+	}
+
+	return(quant);
+
+}
+
+static int vbr_getintra_2pass2(void *sstate)
+{
+
+	int intra;
+	vbr_control_t *state = sstate;
+
+	
+	/* Get next intra state (fetched by update) */
+	intra = state->pass1_intra;
+
+	/* During credits, XviD will decide itself */
+	if(util_frametype(state) != FRAME_TYPE_NORMAL_MOVIE) {
+
+
+		switch(state->credits_mode) {
+		default:
+		case VBR_CREDITS_MODE_RATE :
+		case VBR_CREDITS_MODE_SIZE :
+			intra = -1;
+			break;
+		case VBR_CREDITS_MODE_QUANT :
+			/* Except in this case */
+			if (state->credits_quant_i == state->credits_quant_p)
+				intra = -1;
+			break;
+		}
+
+	}
+
+	/* Force I Frame when max_key_interval is reached */
+	if((state->cur_frame - state->last_keyframe) > state->max_key_interval)
+		intra = 1;
+
+	/*
+	 * Force P or B Frames for frames whose distance is less than the
+	 * requested minimum
+	 */
+	if((state->cur_frame - state->last_keyframe) < state->min_key_interval)
+		intra = 0;
+
+
+	/* Return the given intra mode except for first frame */
+	return((state->cur_frame==0)?1:intra);
+
+}
+
+static int vbr_update_2pass2(void *sstate,
+			     int quant,
+			     int intra,
+			     int header_bytes,
+			     int total_bytes,
+			     int kblocks,
+			     int mblocks,
+			     int ublocks)
+			     
+
+{
+
+
+	int next_hbytes, next_kblocks, next_mblocks, next_ublocks;
+	int tempdiv;
+
+	vbr_control_t *state = sstate;
+
+	/*
+	 * We do not depend on getintra/quant because we have the real results
+	 * from the xvid core
+	 */
+
+	if (util_frametype(state) == FRAME_TYPE_NORMAL_MOVIE) {
+
+		state->quant_count[quant]++;
+
+		if (state->pass1_intra) {
+
+			state->overflow += state->KFoverflow;
+			state->KFoverflow = state->desired_bytes2 - total_bytes;
+
+			tempdiv = (state->keyframe_locations[state->KF_idx] -
+				   state->keyframe_locations[state->KF_idx - 1]);
+
+			/* redistribute correctly (by koepi) */
+			if (tempdiv > 1) {
+				/* non-consecutive keyframes */
+				state->KFoverflow_partial = state->KFoverflow /
+					(tempdiv - 1);
+			}
+			else {
+				state->overflow  += state->KFoverflow;
+				state->KFoverflow = 0;
+				state->KFoverflow_partial = 0;
+			}
+			state->KF_idx++;
+
+		}
+		else {
+			state->overflow += state->desired_bytes2 - total_bytes +
+				state->KFoverflow_partial;
+			state->KFoverflow -= state->KFoverflow_partial;
+		}
+	}
+	else {
+
+		state->overflow += state->desired_bytes2 - total_bytes;
+		state->overflow += state->KFoverflow;
+		state->KFoverflow = 0;
+		state->KFoverflow_partial = 0;
+	}
+
+	/* Save old quant */
+	state->last_quant = quant;
+
+	/* Update next frame data */
+	fscanf(state->pass1_file, "%d %d %d %d %d %d %d\n",
+	       &state->pass1_quant, &state->pass1_intra, &next_hbytes,
+	       &state->pass1_bytes, &next_kblocks, &next_mblocks,
+	       &next_ublocks);
+
+	/* Save the last Keyframe pos */
+	if(intra)
+		state->last_keyframe = state->cur_frame;
+
+	/* Ok next frame */
+	state->cur_frame++;
+	   
+	return(0);
+
+}
+
+static int vbr_finish_2pass2(void *sstate)
+{
+
+	vbr_control_t *state = sstate;
+
+	if(state->pass1_file == NULL)
+		return(-1);
+
+	/* Close the file */
+	if(fclose(state->pass1_file) != 0)
+		return(-1);
+
+	/* Free the memory */
+	if(state->keyframe_locations)
+		free(state->keyframe_locations);
+
+	return(0);
+
+}
+
+
+/******************************************************************************
+ * Fixed quant mode - Most of the functions will be dummy functions
+ *****************************************************************************/
+
+static int vbr_init_fixedquant(void *sstate)
+{
+
+	vbr_control_t *state = sstate;
+
+	if(state->fixed_quant < 1)
+		state->fixed_quant = 1;
+
+	if(state->fixed_quant > 31)
+		state->fixed_quant = 31;
+
+	state->cur_frame = 0;
+
+	return(0);
+
+}
+
+static int vbr_getquant_fixedquant(void *sstate)
+{
+
+	vbr_control_t *state = sstate;
+
+	/* Credits' frame ? */
+	if(util_frametype(state) != FRAME_TYPE_NORMAL_MOVIE) {
+
+		int quant;
+
+		switch(state->credits_mode) {
+		case VBR_CREDITS_MODE_RATE:
+			quant = state->fixed_quant * state->credits_quant_ratio;
+			break;
+		case VBR_CREDITS_MODE_QUANT:
+			quant = state->credits_fixed_quant;
+			break;
+		default:
+			quant = state->fixed_quant;
+
+		}
+
+		return(quant);
+
+	}
+		
+	/* No credit frame - return fixed quant */
+	return(state->fixed_quant);
+
+}
+
+static int vbr_getintra_fixedquant(void *state)
+{
+
+	return(-1);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xvid_vbr.h	Mon Sep 09 11:47:54 2002 +0000
@@ -0,0 +1,231 @@
+/******************************************************************************
+ *
+ *   XviD VBR Library
+ *   
+ *   Copyright (C) 2002 Edouard Gomez <ed.gomez@wanadoo.fr>
+ *
+ *   The curve treatment algorithm is based on work done by Foxer <email?> and
+ *   Dirk Knop <dknop@gwdg.de> for the XviD vfw dynamic library.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *****************************************************************************/
+
+#ifndef __XVID_VBR_H__
+#define __XVID_VBR_H__
+
+#define VBR_VERSION 0
+
+/******************************************************************************
+ * Function types used in the vbr controler
+ *****************************************************************************/
+
+typedef int (vbr_init_function)(void *state);
+typedef vbr_init_function *vbr_init_function_ptr;
+
+typedef int (vbr_get_quant_function)(void *state);
+typedef vbr_get_quant_function *vbr_get_quant_function_ptr;
+
+typedef int (vbr_get_intra_function)(void *state);
+typedef vbr_get_intra_function *vbr_get_intra_function_ptr;
+
+typedef int (vbr_update_function)(void *state,
+				  int quant,
+				  int intra,
+				  int header_bytes,
+				  int total_bytes,
+				  int kblocks,
+				  int mblocks,
+				  int ublocks);
+typedef vbr_update_function *vbr_update_function_ptr;
+
+typedef int (vbr_finish_function)(void *state);
+typedef vbr_finish_function *vbr_finish_function_ptr;
+
+/******************************************************************************
+ * The VBR CONTROLER structure - the spin of the library
+ *****************************************************************************/
+
+typedef struct _vbr_control_t
+{
+
+	/* All modes - specifies what VBR algorithm has to be used */
+	int mode;
+
+	/* All modes - specifies what fps the movie uses */
+	float fps;
+
+	/* All modes */
+	int debug;
+
+	/*
+	 * For VBR_MODE_2PASS_1/2 - specifies from/to what file the vbr
+	 * controller has to write/read stats
+	 */
+	char *filename;
+
+	/* For VBR_MODE_2PASS_2 - Target size */
+	int desired_bitrate;
+
+	/* For VBR_MODE_2PASS_2 - Credits parameters */
+	int credits_mode;
+	int credits_start;
+	int credits_start_begin;
+	int credits_start_end;
+	int credits_end;
+	int credits_end_begin;
+	int credits_end_end;
+	int credits_quant_ratio;
+	int credits_fixed_quant;
+	int credits_quant_i;
+	int credits_quant_p;
+	int credits_start_size;
+	int credits_end_size;
+
+	/* For VBR_MODE_2PASS_2 - keyframe parameters */
+	int keyframe_boost;
+	int kftreshold;
+	int kfreduction;
+	int min_key_interval;
+	int max_key_interval;
+
+	/* For VBR_MODE_2PASS_2 - Normal curve */
+	int curve_compression_high;
+	int curve_compression_low;
+
+	/* For VBR_MODE_2PASS_2 - Alternate curve parameters */
+	int use_alt_curve;
+	int alt_curve_type;
+	int alt_curve_low_dist;
+	int alt_curve_high_dist;
+	int alt_curve_min_rel_qual;
+	int alt_curve_use_auto;
+	int alt_curve_auto_str;
+	int alt_curve_use_auto_bonus_bias;
+	int alt_curve_bonus_bias;
+	int bitrate_payback_method;
+	int bitrate_payback_delay;
+	int twopass_max_bitrate;
+	int twopass_max_overflow_improvement;
+	int twopass_max_overflow_degradation;
+	int max_iquant;
+	int min_iquant;
+	int max_pquant;
+	int min_pquant;
+
+	/*
+	 * For VBR_MODE_FIXED_QUANT - the quantizer that has to be used for all
+	 * frames
+	 */
+	int fixed_quant;
+
+	/* ----------- Internal data - Do not modify ----------- */
+	void *debug_file;
+	void *pass1_file;
+
+	long long desired_size;
+
+	int cur_frame;
+	int nb_frames;
+	int nb_keyframes;
+
+	int *keyframe_locations;
+	int last_keyframe;
+
+	double credits_start_curve;
+	double credits_end_curve;
+	double movie_curve;
+	double average_frame;
+	double alt_curve_low;
+	double alt_curve_low_diff;
+	double alt_curve_high;
+	double alt_curve_high_diff;
+	double alt_curve_mid_qual;
+	double alt_curve_qual_dev;
+	double curve_bias_bonus;
+	double curve_comp_scale;
+	double curve_comp_error;
+
+	int pass1_quant;
+	int pass1_intra;
+	int pass1_bytes;
+
+	int bytes1;
+	int bytes2;
+	int desired_bytes2;
+	int max_framesize;
+	int last_quant;
+	int quant_count[32];
+	double quant_error[32];
+
+	int overflow;
+	int KFoverflow;
+	int KFoverflow_partial;
+	int KF_idx;
+
+	int debug_quant_count[32];
+
+	/* ----------- Internal data - do not modify ----------- */
+	vbr_init_function_ptr      init;
+	vbr_get_quant_function_ptr getquant;
+	vbr_get_intra_function_ptr getintra;	
+	vbr_update_function_ptr    update;
+	vbr_finish_function_ptr    finish;
+
+}vbr_control_t;
+
+/******************************************************************************
+ * Constants
+ *****************************************************************************/
+
+/* Constants for the mode member */
+#define VBR_MODE_1PASS       0x01
+#define VBR_MODE_2PASS_1     0x02
+#define VBR_MODE_2PASS_2     0x04
+#define VBR_MODE_FIXED_QUANT 0x08
+
+/* Constants for the credits mode */
+#define VBR_CREDITS_MODE_RATE  0x01
+#define VBR_CREDITS_MODE_QUANT 0x02
+#define VBR_CREDITS_MODE_SIZE  0x04
+
+/* Alternate curve treatment types */
+#define VBR_ALT_CURVE_SOFT      0x01
+#define VBR_ALT_CURVE_LINEAR    0x02
+#define VBR_ALT_CURVE_AGGRESIVE 0x04
+
+/* Payback modes */
+#define VBR_PAYBACK_BIAS            0x01
+#define VBR_PAYBACK_PROPORTIONAL    0x02
+
+/******************************************************************************
+ * VBR API
+ *****************************************************************************/
+
+extern int vbrSetDefaults(vbr_control_t *state);
+extern int vbrInit(vbr_control_t *state);
+extern int vbrGetQuant(vbr_control_t *state);
+extern int vbrGetIntra(vbr_control_t *state);
+extern int vbrUpdate(vbr_control_t *state,
+		     int quant,
+		     int intra,
+		     int header_bytes,
+		     int total_bytes,
+		     int kblocks,
+		     int mblocks,
+		     int ublocks);
+extern int vbrFinish(vbr_control_t *state);
+
+#endif