changeset 7332:dd32b0c95c95

Code to XviD VBR Library from transcode.
author kmkaplan
date Mon, 09 Sep 2002 12:12:30 +0000
parents 7ec253a97341
children e7ddd1923b67
files libmpcodecs/ve_divx4.c
diffstat 1 files changed, 91 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/libmpcodecs/ve_divx4.c	Mon Sep 09 11:47:54 2002 +0000
+++ b/libmpcodecs/ve_divx4.c	Mon Sep 09 12:12:30 2002 +0000
@@ -1,3 +1,4 @@
+#define HAVE_XVID_VBR
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -18,9 +19,28 @@
 #include "mp_image.h"
 #include "vf.h"
 
+/* About XviD VBR Library, Edouard Gomez (GomGom) said:
+  <GomGom> header bytes == frame header bytes :-)
+  <GomGom> total bytes = frame bytes == texture + header
+  <GomGom> quant = quant returned by xvidcore
+  <GomGom> it's possible that xvid lowers or increases the passed quant because of lumimasking
+  <GomGom> kblks = blocks coded as intra blocks
+  <GomGom> mblks = blocks coded as predicted blocks
+  <GomGom> ublks = skipped blocks
+  <GomGom> at the moemnt le vbr lib uses total bytes, and quant
+  <GomGom> so it's easy to use it with divx5 (wo bframes)
+  <klOUg> bframes breaks what assumptions?
+  <GomGom> quant estimation for next frame
+  <GomGom> because of the bframe quant multiplier given to divx5
+  <GomGom> that the vbr lib does not "know"
+*/
+
 //===========================================================================//
 
 #include "divx4_vbr.h"
+#ifdef HAVE_XVID_VBR
+#include "xvid_vbr.h"
+#endif
 
 extern int pass;
 extern char* passtmpfile;
@@ -34,6 +54,10 @@
 
 ENC_PARAM divx4_param;
 int divx4_crispness;
+#ifdef HAVE_XVID_VBR
+static int vbrpass = -1;
+static int vbrdebug = 0;
+#endif
 
 #include "cfgparser.h"
 
@@ -62,6 +86,10 @@
 	{"spatial", &divx4_param.extensions.spatial_passes, CONF_TYPE_INT, 0,0,1, NULL},
 	{"mv_file", &divx4_param.extensions.mv_file, CONF_TYPE_STRING, 0,0,1, NULL},
 #endif
+#ifdef HAVE_XVID_VBR
+	{"vbrpass", &vbrpass, CONF_TYPE_INT, CONF_RANGE, 0, 2, NULL},
+	{"vbrdebug", &vbrdebug, CONF_TYPE_INT, CONF_RANGE, 0, 1, NULL},
+#endif
 	{"help", "TODO: divx4opts help!\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL},
 	{NULL, NULL, 0, 0, 0, 0, NULL}
 };
@@ -71,6 +99,9 @@
     ENC_RESULT enc_result;
     ENC_FRAME enc_frame;
     void* enc_handle;
+#ifdef HAVE_XVID_VBR
+    vbr_control_t vbr_state;
+#endif
 };
 
 #define mux_v (vf->priv->mux)
@@ -98,6 +129,32 @@
     if(!divx4_param.rc_reaction_period) divx4_param.rc_reaction_period=10;
     if(!divx4_param.rc_reaction_ratio) divx4_param.rc_reaction_ratio=20;
 
+#ifdef HAVE_XVID_VBR
+    if (vbrpass >= 0) {
+	vbrSetDefaults(&vf->priv->vbr_state);
+	vf->priv->vbr_state.desired_bitrate = divx4_param.bitrate;
+	switch (vbrpass) {
+	case 0:
+	    vf->priv->vbr_state.mode = VBR_MODE_1PASS;
+	    break;
+	case 1:
+	    vf->priv->vbr_state.mode = VBR_MODE_2PASS_1;
+	    break;
+	case 2:
+	    vf->priv->vbr_state.mode = VBR_MODE_2PASS_2;
+	    break;
+	default:
+	    abort();
+	}
+	vf->priv->vbr_state.debug = vbrdebug;
+	if (vbrInit(&vf->priv->vbr_state) == -1)
+	    abort();
+	/* XXX - kludge to workaround some DivX encoder limitations */
+	if (vf->priv->vbr_state.mode != VBR_MODE_2PASS_2)
+	    divx4_param.min_quantizer = divx4_param.max_quantizer = vbrGetQuant(&vf->priv->vbr_state);
+    }
+#endif
+
     divx4_param.handle=NULL;
     encore(NULL,ENC_OPT_INIT,&divx4_param,NULL);
     vf->priv->enc_handle=divx4_param.handle;
@@ -138,6 +195,13 @@
     return 1;
 }
 
+#ifdef HAVE_XVID_VBR
+static void uninit(struct vf_instance_s* vf){
+    if (vbrpass >= 0 && vbrFinish(&vf->priv->vbr_state) == -1)
+	    abort();
+}
+#endif
+
 static int control(struct vf_instance_s* vf, int request, void* data){
 
     return CONTROL_UNKNOWN;
@@ -165,6 +229,30 @@
     vf->priv->enc_frame.bitstream=mux_v->buffer;
     vf->priv->enc_frame.length=mux_v->buffer_size;
     vf->priv->enc_frame.mvs=NULL;
+#ifdef HAVE_XVID_VBR
+    if (vbrpass >= 0) {
+	int quant = vbrGetQuant(&vf->priv->vbr_state);
+	int intra = vbrGetIntra(&vf->priv->vbr_state);
+	vf->priv->enc_frame.quant = quant ? quant : 1;
+	vf->priv->enc_frame.intra = intra;
+	/* XXX - kludge to workaround some DivX encoder limitations:
+	   only pass 2 needs to call encore with VBR, and then it does
+	   not report quantizer and intra*/
+	if (vf->priv->vbr_state.mode != VBR_MODE_2PASS_2)
+	    encore(vf->priv->enc_handle, ENC_OPT_ENCODE, &vf->priv->enc_frame, &enc_result);
+	else {
+	    encore(vf->priv->enc_handle, ENC_OPT_ENCODE_VBR, &vf->priv->enc_frame, &enc_result);
+	    enc_result.quantizer = quant;
+	    if (intra >= 0)
+		enc_result.is_key_frame = intra;
+	}
+	if (vbrUpdate(&vf->priv->vbr_state, enc_result.quantizer, enc_result.is_key_frame,
+		      (enc_result.total_bits - enc_result.texture_bits) / 8, enc_result.total_bits / 8,
+		      0, 0, 0) == -1)
+	    abort();
+    }
+    else
+#endif
     if(pass==2){	// handle 2-pass:
     	vf->priv->enc_frame.quant = VbrControl_get_quant();
 	vf->priv->enc_frame.intra = VbrControl_get_intra();
@@ -194,6 +282,9 @@
     vf->control=control;
     vf->query_format=query_format;
     vf->put_image=put_image;
+#ifdef HAVE_XVID_VBR
+    vf->uninit = uninit;
+#endif
     vf->priv=malloc(sizeof(struct vf_priv_s));
     memset(vf->priv,0,sizeof(struct vf_priv_s));
     vf->priv->mux=(aviwrite_stream_t*)args;