view libmpcodecs/ve_xvid.c @ 8514:a1ff87c254ff

I have rewritten the gif89a vo in order to solve some problems I had with it. These are: 1) current code is messy 2) poor comments, if any 3) inaccurate frame dropping and delay code 4) output filename hardcoded 5) output framerate as integer You may specify the output filename and framerate like so: -vo gif89a:4.33 4.33 fps output -vo gif89a:some.gif output to some.gif -vo gif89a:5.02:new.gif output to new.gif at 5.02 fps The filename defaults to out.gif, and the framerate defaults to 5 fps. by Joey Parrish <joey@nicewarrior.org>
author arpi
date Sat, 21 Dec 2002 21:07:16 +0000
parents ce25d80dd6c3
children 36da960c94e3
line wrap: on
line source

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include "../config.h"
#include "../mp_msg.h"

#ifdef HAVE_XVID

#include "codec-cfg.h"
#include "stream.h"
#include "demuxer.h"
#include "stheader.h"

#include "aviwrite.h"

#include "img_format.h"
#include "mp_image.h"
#include "vf.h"

#include <xvid.h>
#include "xvid_vbr.h"

#include "cfgparser.h"


#ifdef XVID_API_UNSTABLE
#warning *******************************************************************
#warning **                                                               **
#warning **  Y O U '' R E   U S I N G   U N S T A B L E   S O F T W A R E  **
#warning **                                                               **
#warning ** Streams produced by this version aren''nt probably compatible  **
#warning ** with anything else, even the xvid decoder itself. There are   **
#warning ** bugs, this code could crash, could blow up your PC or the     **
#warning ** whole building !                                              **
#warning ** If you want stable code and compatible streams, use stable    **
#warning ** XViD releases (currently 0.9.x).                              **
#warning **                                                               **
#warning *******************************************************************
#endif

/**********************************************************************/
/* motion estimation quality presets */
static int const motion_presets[7] = {
#ifdef XVID_API_UNSTABLE
	0,
	PMV_QUICKSTOP16,
	0,
	0,
	PMV_HALFPELREFINE16 | PMV_HALFPELDIAMOND8,
	PMV_HALFPELREFINE16 | PMV_HALFPELDIAMOND8 | PMV_ADVANCEDDIAMOND16,
	PMV_HALFPELREFINE16 | PMV_EXTSEARCH16 | PMV_HALFPELREFINE8 | PMV_HALFPELDIAMOND8 | PMV_USESQUARES16
#else
        0,
	PMV_QUICKSTOP16,
	PMV_EARLYSTOP16,
	PMV_EARLYSTOP16 | PMV_EARLYSTOP8,
        PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 | PMV_EARLYSTOP8 | PMV_HALFPELDIAMOND8,
        PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 | PMV_EARLYSTOP8 | PMV_HALFPELDIAMOND8 | PMV_ADVANCEDDIAMOND16,
	PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 | PMV_EXTSEARCH16 | PMV_EARLYSTOP8 | PMV_HALFPELREFINE8 | 
	PMV_HALFPELDIAMOND8 | PMV_USESQUARES16

#endif
};

extern char* passtmpfile;
extern void mencoder_write_chunk(aviwrite_stream_t *s,int len,unsigned int flags);

static int xvidenc_pass = 0;
static int xvidenc_quality = 4;
static int xvidenc_4mv = 0;
static int xvidenc_bitrate = -1;
static int xvidenc_rc_reaction_delay_factor = -1;
static int xvidenc_rc_averaging_period = -1;
static int xvidenc_rc_buffer = -1;
static char* xvidenc_quant_range = "2-31/2-31";
static int xvidenc_min_key_interval = -1;
static int xvidenc_max_key_interval = -1;
static int xvidenc_mpeg_quant = 0;
static int xvidenc_mod_quant = 0;
static int xvidenc_lumi_mask = 0;
static int xvidenc_keyframe_boost = -1;
static int xvidenc_kfthreshold = -1;
static int xvidenc_kfreduction = -1;
static int xvidenc_fixed_quant = 0;
static int xvidenc_debug = 0;
static int xvidenc_hintedme = 0;
static char* xvidenc_hintfile = "xvid_hint_me.dat";
#ifdef XVID_API_UNSTABLE
static int xvidenc_qpel = 0;
static int xvidenc_max_bframes = 0;
static int xvidenc_bquant_ratio = 125;
static int xvidenc_bquant_offset = 60;
static int xvidenc_gmc = 0;
static int xvidenc_me_colour = 0;
static int xvidenc_reduced = 0;
#endif

struct config xvidencopts_conf[] = {
    { "pass", &xvidenc_pass, CONF_TYPE_INT, CONF_RANGE, 0, 2, NULL},
    { "me_quality", &xvidenc_quality, CONF_TYPE_INT, CONF_RANGE, 0,
      sizeof(motion_presets) / sizeof(motion_presets[0]) - 1, NULL},
    { "4mv", &xvidenc_4mv, CONF_TYPE_FLAG, 0, 0, 1, NULL},
    { "bitrate", &xvidenc_bitrate, CONF_TYPE_INT, CONF_RANGE, 4, 24000000, NULL},
    { "rc_reaction_delay_factor", &xvidenc_rc_reaction_delay_factor, CONF_TYPE_INT, 0, 0, 0, NULL},
    { "rc_averaging_period", &xvidenc_rc_averaging_period, CONF_TYPE_INT, 0, 0, 0, NULL},
    { "rc_buffer", &xvidenc_rc_buffer, CONF_TYPE_INT, 0, 0, 0, NULL},
    { "quant_range", &xvidenc_quant_range, CONF_TYPE_STRING, 0, 0, 0, NULL},
    { "min_key_interval", &xvidenc_min_key_interval, CONF_TYPE_INT, 0, 0, 0, NULL}, /* for XVID_MODE_2PASS_2 */
    { "max_key_interval", &xvidenc_max_key_interval, CONF_TYPE_INT, 0, 0, 0, NULL},
    { "mpeg_quant", &xvidenc_mpeg_quant, CONF_TYPE_FLAG, 0, 0, 1, NULL},
    { "mod_quant", &xvidenc_mod_quant, CONF_TYPE_FLAG, 0, 0, 1, NULL},
    { "lumi_mask", &xvidenc_lumi_mask, CONF_TYPE_FLAG, 0, 0, 1, NULL},
    { "keyframe_boost", &xvidenc_keyframe_boost, CONF_TYPE_INT, CONF_RANGE, 0, 1000, NULL}, /* for XVID_MODE_2PASS_2 */
    { "kfthreshold", &xvidenc_kfthreshold, CONF_TYPE_INT, 0, 0, 0, NULL}, /* for XVID_MODE_2PASS_2 */
    { "kfreduction", &xvidenc_kfreduction, CONF_TYPE_INT, CONF_RANGE, 0, 100, NULL}, /* for XVID_MODE_2PASS_2 */
    { "fixed_quant", &xvidenc_fixed_quant, CONF_TYPE_INT, CONF_RANGE, 1, 31, NULL}, /* for XVID_MODE_FIXED_QUANT */
    { "debug", &xvidenc_debug, CONF_TYPE_FLAG, 0, 0, 1, NULL},
    { "hintedme", &xvidenc_hintedme, CONF_TYPE_FLAG, 0, 0, 1, NULL},
    { "hintfile", &xvidenc_hintfile, CONF_TYPE_STRING, 0, 0, 0, NULL},
#ifdef XVID_API_UNSTABLE
    { "qpel", &xvidenc_qpel, CONF_TYPE_FLAG, 0, 0, 1, NULL},
    { "max_bframes", &xvidenc_max_bframes, CONF_TYPE_INT, CONF_RANGE, 0, 4, NULL},
    { "bquant_ratio", &xvidenc_bquant_ratio, CONF_TYPE_INT, CONF_RANGE, 0, 1000, NULL},
    { "bquant_offset", &xvidenc_bquant_offset, CONF_TYPE_INT, CONF_RANGE, -1000, 1000, NULL},
    { "reduced", &xvidenc_reduced, CONF_TYPE_FLAG, 0, 0, 1, NULL},
    { "gmc", &xvidenc_gmc, CONF_TYPE_FLAG, 0, 0, 1, NULL},
    { "me_colour", &xvidenc_me_colour, CONF_TYPE_FLAG, 0, 0, 1, NULL},
#endif
    { NULL, NULL, 0, 0, 0, 0, NULL}
};

struct vf_priv_s {
    aviwrite_stream_t* mux;
    XVID_ENC_FRAME enc_frame;
    void* enc_handle;
    vbr_control_t vbr_state;
    FILE *hintfile;
    void *hintstream;
};

static int
config(struct vf_instance_s* vf,
       int width, int height, int d_width, int d_height,
       unsigned int flags, unsigned int outfmt)
{
    XVID_ENC_PARAM enc_param;
    struct vf_priv_s *fp = vf->priv;
    unsigned int min_iq, max_iq, min_pq, max_pq;

    fp->mux->bih->biWidth = width;
    fp->mux->bih->biHeight = height;
    fp->mux->bih->biSizeImage = fp->mux->bih->biWidth * fp->mux->bih->biHeight * 3;
    mp_msg(MSGT_MENCODER,MSGL_INFO,"videocodec: XViD (%dx%d fourcc=%x [%.4s])\n",
	width, height, fp->mux->bih->biCompression, (char *)&fp->mux->bih->biCompression);

    // {min,max}_{i,p}quantizer parsing & validation
    if (sscanf (xvidenc_quant_range, "%u-%u/%u-%u", &min_iq, &max_iq, &min_pq, &max_pq) < 4) {
	mp_msg (MSGT_MENCODER, MSGL_ERR, 
		"xvid: ERROR: cannot parse \"quant_range=%s\"\n", xvidenc_quant_range);
	return 0;
    }
    if (min_iq < 1 || min_iq > 31 || max_iq < 1 || max_iq > 31 || min_iq > max_iq ||
	min_pq < 1 || min_pq > 31 || max_pq < 1 || max_pq > 31 || min_pq > max_pq) {
	mp_msg (MSGT_MENCODER, MSGL_ERR,
		"xvid: ERROR: {min,max} {I,P} quantizer must be in [1,31] and min must be <= max.\n");
	mp_msg (MSGT_MENCODER, MSGL_ERR,
		"xvid: ERROR: cannot use \"quant_range=%s\"\n", xvidenc_quant_range);
	return -1;
    }

#ifdef XVID_API_UNSTABLE
    mp_msg (MSGT_MENCODER, MSGL_WARN,
	    "\n"
	    "*******************************************************************\n"
	    "**                                                               **\n"
	    "**  Y O U ' R E   U S I N G   U N S T A B L E   S O F T W A R E  **\n"
	    "**                                                               **\n"
	    "** Streams produced by this version aren'nt probably compatible  **\n"
	    "** with anything else, even the xvid decoder itself. There are   **\n"
	    "** bugs, this code could crash, could blow up your PC or the     **\n"
	    "** whole building !                                              **\n"
	    "** If you want stable code and compatible streams, use stable    **\n"
	    "** XViD releases (currently 0.9.x).                              **\n"
	    "**                                                               **\n"
	    "*******************************************************************\n"
	    "\n");
#endif

    // initialize XViD core parameters
    // ===============================
    memset(&enc_param, 0, sizeof(enc_param));
    enc_param.width = width;
    enc_param.height = height;
    enc_param.fincr = fp->mux->h.dwScale;
    enc_param.fbase = fp->mux->h.dwRate;
    if (xvidenc_bitrate > 16000)
	enc_param.rc_bitrate = xvidenc_bitrate;
    else if (xvidenc_bitrate > 0)
	enc_param.rc_bitrate = xvidenc_bitrate * 1000;
    else
	enc_param.rc_bitrate = -1;
#ifdef XVID_API_UNSTABLE
    if (xvidenc_max_bframes >= 1 && xvidenc_pass >= 1) {
	mp_msg(MSGT_MENCODER,MSGL_WARN, "xvid: cannot use bframes with 2-pass, disabling bframes\n");
	xvidenc_max_bframes = 0;
    }
    enc_param.max_bframes = xvidenc_max_bframes;
    enc_param.bquant_ratio = xvidenc_bquant_ratio;
    enc_param.bquant_offset = xvidenc_bquant_offset;
    if (xvidenc_reduced)
	enc_param.global |= XVID_GLOBAL_REDUCED;
#endif
    enc_param.rc_reaction_delay_factor = xvidenc_rc_reaction_delay_factor;
    enc_param.rc_averaging_period = xvidenc_rc_averaging_period;
    enc_param.rc_buffer = xvidenc_rc_buffer;
    enc_param.min_quantizer = min_iq;
    enc_param.max_quantizer = max_iq;
    if( xvidenc_max_key_interval <= 0 )
	xvidenc_max_key_interval = 10 * enc_param.fbase / enc_param.fincr;
    enc_param.max_key_interval = xvidenc_max_key_interval;
    switch (xvid_encore(NULL, XVID_ENC_CREATE, &enc_param, NULL)) {
    case XVID_ERR_FAIL:
	mp_msg(MSGT_MENCODER,MSGL_ERR, "xvid: encoder creation failed\n");
	return 0;
    case XVID_ERR_MEMORY:
	mp_msg(MSGT_MENCODER,MSGL_ERR, "xvid: encoder creation failed, out of memory\n");
	return 0;
    case XVID_ERR_FORMAT:
	mp_msg(MSGT_MENCODER,MSGL_ERR, "xvid: encoder creation failed, bad format\n");
	return 0;
    }
    fp->enc_handle = enc_param.handle;

    // initialize XViD per-frame static parameters
    // ===========================================
    fp->enc_frame.motion = motion_presets[xvidenc_quality];
    fp->enc_frame.general = XVID_HALFPEL | (xvidenc_mpeg_quant ? XVID_MPEGQUANT : XVID_H263QUANT);
    if (xvidenc_4mv)
	fp->enc_frame.general |= XVID_INTER4V;
    if (xvidenc_lumi_mask)
	fp->enc_frame.general |= XVID_LUMIMASKING;
#ifdef XVID_API_UNSTABLE
    if (xvidenc_qpel) {
	fp->enc_frame.general |= XVID_QUARTERPEL;
	fp->enc_frame.motion |= PMV_QUARTERPELREFINE16 | PMV_QUARTERPELREFINE8;
    }
    if (xvidenc_gmc)
	fp->enc_frame.general |= XVID_GMC;
    if (xvidenc_me_colour)
	fp->enc_frame.general |= XVID_ME_COLOUR;
    if(xvidenc_reduced)
	fp->enc_frame.general |= XVID_REDUCED;
#endif

    switch (outfmt) {
    case IMGFMT_YV12:
	fp->enc_frame.colorspace = XVID_CSP_YV12;
	break;
    case IMGFMT_IYUV: case IMGFMT_I420:
	fp->enc_frame.colorspace = XVID_CSP_I420;
	break;
    case IMGFMT_YUY2:
	fp->enc_frame.colorspace = XVID_CSP_YUY2;
	break;
    case IMGFMT_UYVY:
	fp->enc_frame.colorspace = XVID_CSP_UYVY;
	break;
    case IMGFMT_RGB24: case IMGFMT_BGR24:
    	fp->enc_frame.colorspace = XVID_CSP_RGB24;
	break;
    default:
	mp_msg(MSGT_MENCODER,MSGL_ERR,"xvid: unsupported picture format (%s)!\n",
	       vo_format_name(outfmt));
	return 0;
    }
    fp->enc_frame.quant_intra_matrix = 0;
    fp->enc_frame.quant_inter_matrix = 0;

    // hinted ME
    fp->hintstream = NULL;
    fp->hintfile = NULL;
    if (xvidenc_hintedme && (xvidenc_pass == 1 || xvidenc_pass == 2)) {
	fp->hintstream = malloc( 100000 ); // this is what the vfw code in XViD CVS allocates
	if (fp->hintstream == NULL)
	    mp_msg(MSGT_MENCODER,MSGL_ERR, "xvid: cannot allocate memory for hinted ME\n");
	else {
	    fp->hintfile = fopen(xvidenc_hintfile, xvidenc_pass == 1 ? "w" : "r");
	    if (fp->hintfile == NULL) {
		mp_msg(MSGT_MENCODER,MSGL_ERR, "xvid: %s: %s\n", strerror(errno), xvidenc_hintfile);
		free(fp->hintstream);
	    }
	}
	if (fp->hintstream == NULL || fp->hintfile == NULL)
	    xvidenc_hintedme = 0;
    }

    // initialize VBR engine
    // =====================
    vbrSetDefaults(&fp->vbr_state);
    if (xvidenc_min_key_interval < 0)
	xvidenc_min_key_interval = fp->vbr_state.min_key_interval;

    // pass
    if (xvidenc_pass == 0) {
	if (xvidenc_fixed_quant >= 1) {
	    fp->vbr_state.mode = VBR_MODE_FIXED_QUANT;
	    fp->vbr_state.fixed_quant = xvidenc_fixed_quant;
	} else
	    fp->vbr_state.mode = VBR_MODE_1PASS;
    }
    else if (xvidenc_pass == 1)
	fp->vbr_state.mode = VBR_MODE_2PASS_1;
    else if (xvidenc_pass == 2)
	fp->vbr_state.mode = VBR_MODE_2PASS_2;
    else
	return -1;

    // misc
    fp->vbr_state.fps = (double)enc_param.fbase / enc_param.fincr;
    fp->vbr_state.filename = passtmpfile;
    fp->vbr_state.desired_bitrate = enc_param.rc_bitrate;
    fp->vbr_state.min_iquant = min_iq;
    fp->vbr_state.max_iquant = max_iq;
    fp->vbr_state.min_pquant = min_pq;
    fp->vbr_state.max_pquant = max_pq;
    if (xvidenc_keyframe_boost >= 0)
	fp->vbr_state.keyframe_boost = xvidenc_keyframe_boost;
    if (xvidenc_kfthreshold >= 0)
	fp->vbr_state.kftreshold = xvidenc_kfthreshold;
    if (xvidenc_kfreduction >= 0)
	fp->vbr_state.kfreduction = xvidenc_kfreduction;
    if (xvidenc_min_key_interval >= 0)
	fp->vbr_state.min_key_interval = xvidenc_min_key_interval;
    fp->vbr_state.max_key_interval = enc_param.max_key_interval;
    fp->vbr_state.debug = xvidenc_debug;

    vbrInit(&fp->vbr_state);

    return 1;
}

static void
uninit(struct vf_instance_s* vf)
{
    struct vf_priv_s *fp = vf->priv;

    if (fp->hintfile)
	fclose(fp->hintfile);
    if (fp->hintstream)
	free(fp->hintstream);
    vbrFinish(&fp->vbr_state);
}

static int
control(struct vf_instance_s* vf, int request, void* data)
{
    return CONTROL_UNKNOWN;
}

static int
query_format(struct vf_instance_s* vf, unsigned int fmt)
{
    switch(fmt){
    case IMGFMT_YV12: case IMGFMT_IYUV: case IMGFMT_I420:
	return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW;
    case IMGFMT_YUY2: case IMGFMT_UYVY:
	return VFCAP_CSP_SUPPORTED;
    case IMGFMT_RGB24: case IMGFMT_BGR24:
	return VFCAP_CSP_SUPPORTED | VFCAP_FLIPPED;
    }
    return 0;
}

static int
put_image(struct vf_instance_s* vf, mp_image_t *mpi)
{
    XVID_ENC_STATS enc_stats;
    struct vf_priv_s *fp = vf->priv;

    fp->enc_frame.bitstream = fp->mux->buffer;
    fp->enc_frame.length = -1 /* fp->mux->buffer_size */;
    fp->enc_frame.image = mpi->planes[0];

    // get quantizers & I/P decision from the VBR engine
#ifdef XVID_API_UNSTABLE
    if (xvidenc_max_bframes >= 1) {
	if (!xvidenc_fixed_quant) {
	    // hack, the internal VBR engine isn't fixed-quant aware
	    fp->enc_frame.quant = xvidenc_fixed_quant;
	    fp->enc_frame.intra = -1;
	    fp->enc_frame.bquant = (xvidenc_fixed_quant * xvidenc_bquant_ratio + xvidenc_bquant_offset) / 100;
	} else
	    // use the internal VBR engine since the external one isn't bframe aware
	    fp->enc_frame.quant = fp->enc_frame.intra = fp->enc_frame.bquant = -1;
    } else {
	fp->enc_frame.quant = vbrGetQuant(&fp->vbr_state);
	fp->enc_frame.intra = vbrGetIntra(&fp->vbr_state);
    }
#else
    fp->enc_frame.quant = vbrGetQuant(&fp->vbr_state);
    fp->enc_frame.intra = vbrGetIntra(&fp->vbr_state);
#endif

    // modulated quantizer type
    if (xvidenc_mod_quant && xvidenc_pass == 2) {
	fp->enc_frame.general |= (fp->enc_frame.quant < 4) ? XVID_MPEGQUANT : XVID_H263QUANT;
	fp->enc_frame.general &= (fp->enc_frame.quant < 4) ? ~XVID_H263QUANT : ~XVID_MPEGQUANT;
    }

    // hinted ME, 1st part
    if (xvidenc_hintedme && xvidenc_pass == 1) {
	fp->enc_frame.hint.hintstream = fp->hintstream;
	fp->enc_frame.hint.rawhints = 0;
	fp->enc_frame.general |= XVID_HINTEDME_GET;
    }
    else if (xvidenc_hintedme && xvidenc_pass == 2) {
	size_t read;
	int blocksize;
	fp->enc_frame.general &= ~XVID_HINTEDME_SET;
	read = fread(&blocksize, sizeof(blocksize), 1, fp->hintfile);
	if (read == 1) {
	    read = fread(fp->hintstream, (size_t)blocksize, 1, fp->hintfile);
	    if (read == 1) {
		fp->enc_frame.hint.hintstream = fp->hintstream;
		fp->enc_frame.hint.hintlength = 0;
		fp->enc_frame.hint.rawhints = 0;
		fp->enc_frame.general |= XVID_HINTEDME_SET;
	    } 
	    else
		perror("xvid: hint file read block failure");
	} 
	else
	    perror("xvid: hint file read failure");
    }

    // encode frame
    switch (xvid_encore(fp->enc_handle, XVID_ENC_ENCODE, &fp->enc_frame, &enc_stats)) {
    case XVID_ERR_OK:
	break;
    case XVID_ERR_MEMORY:
	mp_msg(MSGT_MENCODER, MSGL_ERR, "xvid: out of memory\n");
	break;
    case XVID_ERR_FORMAT:
	mp_msg(MSGT_MENCODER, MSGL_ERR, "xvid: bad format\n");
	break;
    default:
	mp_msg(MSGT_MENCODER, MSGL_ERR, "xvid: failure\n");
	break;
    }
    
    // write output
    mencoder_write_chunk(fp->mux, fp->enc_frame.length, fp->enc_frame.intra==1 ? 0x10 : 0);

    // update the VBR engine
    vbrUpdate(&fp->vbr_state, enc_stats.quant, fp->enc_frame.intra,
	      enc_stats.hlength, fp->enc_frame.length, enc_stats.kblks, enc_stats.mblks, enc_stats.ublks);

    // hinted ME, 2nd part
    if (fp->enc_frame.general & XVID_HINTEDME_GET) {
	size_t wrote = fwrite(&fp->enc_frame.hint.hintlength, sizeof(fp->enc_frame.hint.hintlength), 1, fp->hintfile);
	if (wrote == 1) {
	    wrote = fwrite(fp->enc_frame.hint.hintstream, fp->enc_frame.hint.hintlength, 1, fp->hintfile);
	    if (wrote != 1)
		perror("xvid: hint write block failure");
	}
	else
	    perror("xvid: hint write failure");
    }
    return 1;
}

//===========================================================================//

static int
vf_open(vf_instance_t *vf, char* args)
{
    XVID_INIT_PARAM params = { 0, 0, 0};
    vf->config = config;
    vf->control = control;
    vf->uninit = uninit;
    vf->query_format = query_format;
    vf->put_image = put_image;
    vf->priv = malloc(sizeof(struct vf_priv_s));
    memset(vf->priv, 0, sizeof(struct vf_priv_s));
    vf->priv->mux = (aviwrite_stream_t*)args;

    vf->priv->mux->bih = malloc(sizeof(BITMAPINFOHEADER));
    vf->priv->mux->bih->biSize = sizeof(BITMAPINFOHEADER);
    vf->priv->mux->bih->biWidth = 0;
    vf->priv->mux->bih->biHeight = 0;
    vf->priv->mux->bih->biPlanes = 1;
    vf->priv->mux->bih->biBitCount = 24;
    vf->priv->mux->bih->biCompression = mmioFOURCC('X','V','I','D');

    if (xvid_init(NULL, 0, &params, NULL) != XVID_ERR_OK) {
	mp_msg(MSGT_MENCODER,MSGL_ERR, "xvid: initialisation failure\n");
	abort();
    }
    if (params.api_version != API_VERSION) {
	mp_msg(MSGT_MENCODER,MSGL_ERR, "xvid: XviD library API version mismatch\n"
		"\texpected %d.%d, got %d.%d, you should recompile MPlayer.\n",
		API_VERSION >> 16, API_VERSION & 0xff,
		params.api_version >> 16, params.api_version & 0xff);
	abort();
    }

    return 1;
}

vf_info_t ve_info_xvid = {
    "XviD encoder",
    "xvid",
    "Kim Minh Kaplan & Rémi Guyomarch",
    "for internal use by mencoder",
    vf_open
};

//===========================================================================//
#endif