[MPlayer-dev-eng] Re: ve_xvid.c ?

Rémi Guyomarch rguyom at pobox.com
Thu Sep 19 23:10:57 CEST 2002


On Thu, Sep 19, 2002 at 09:44:52PM +0200, Arpi wrote:
> Hi,
> 
> Anyone is working on native xvid encoding?

I'm not working on it, but I have a very rough xvid support
working. Patches & files attached.

Warning ! This code has a lot of quirks :
- works with CVS-current mplayer/mencoder *and* CVS-current XViD
- you need to configure mplayer/mencoder with 
  ./configure --with-extraincdir=/foo/bar/xvid/xvidcore/src/ \
              --with-xvidcore=/foo/bar/xvid/xvidcore/build/generic/libxvidcore.a
- no support for 2-pass mode
- no compile-time (./configure) detection
- lacks a few #ifdef XVID_NATIVESUPPORT here and there
- not very well tested
  (I mean, I can encode mplayer-playable [with "-vc xvid"] .avi files
   with this code, but I didn't checked on Windows)

Enjoy ;)

Btw, during the limited testing I did, this codec seems to be ~3 times
slower than libavcodec on my XP 1800+ :-/

-- 
Rémi
-------------- next part --------------
Index: cfg-mencoder.h
===================================================================
RCS file: /cvsroot/mplayer/main/cfg-mencoder.h,v
retrieving revision 1.50
diff -u -u -r1.50 cfg-mencoder.h
--- cfg-mencoder.h	29 Aug 2002 20:50:48 -0000	1.50
+++ cfg-mencoder.h	19 Sep 2002 21:16:26 -0000
@@ -19,6 +19,7 @@
 #ifdef HAVE_DIVX4ENCORE
 extern struct config divx4opts_conf[];
 #endif
+extern struct config xvidopts_conf[];
 
 #ifdef HAVE_MP3LAME
 struct config lameopts_conf[]={
@@ -49,6 +50,7 @@
 	{"copy", &out_video_codec, CONF_TYPE_FLAG, 0, 0, VCODEC_COPY, NULL},
 	{"frameno", &out_video_codec, CONF_TYPE_FLAG, 0, 0, VCODEC_FRAMENO, NULL},
 	{"divx4", &out_video_codec, CONF_TYPE_FLAG, 0, 0, VCODEC_DIVX4, NULL},
+	{"xvid", &out_video_codec, CONF_TYPE_FLAG, 0, 0, VCODEC_XVID, NULL},
 //	{"raw", &out_video_codec, CONF_TYPE_FLAG, 0, 0, VCODEC_RAW, NULL},
 	{"lavc", &out_video_codec, CONF_TYPE_FLAG, 0, 0, VCODEC_LIBAVCODEC, NULL},
 //	{"null", &out_video_codec, CONF_TYPE_FLAG, 0, 0, VCODEC_NULL, NULL},
@@ -156,6 +158,7 @@
 #ifdef HAVE_DIVX4ENCORE
 	{"divx4opts", divx4opts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
 #endif
+	{"xvidopts", xvidopts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
 #ifdef HAVE_MP3LAME
 	{"lameopts", lameopts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
 #endif
Index: mencoder.c
===================================================================
RCS file: /cvsroot/mplayer/main/mencoder.c,v
retrieving revision 1.159
diff -u -u -r1.159 mencoder.c
--- mencoder.c	14 Sep 2002 10:47:34 -0000	1.159
+++ mencoder.c	19 Sep 2002 21:16:32 -0000
@@ -6,6 +6,7 @@
 #define VCODEC_RAWRGB 6
 #define VCODEC_VFW 7
 #define VCODEC_LIBDV 8
+#define VCODEC_XVID 9
 
 #define ACODEC_COPY 0
 #define ACODEC_PCM 1
@@ -651,6 +652,8 @@
         sh_video->vfilter=vf_open_encoder(NULL,"vfw",(char *)mux_v); break;
     case VCODEC_LIBDV:
         sh_video->vfilter=vf_open_encoder(NULL,"libdv",(char *)mux_v); break;
+    case VCODEC_XVID:
+        sh_video->vfilter=vf_open_encoder(NULL,"xvid",(char *)mux_v); break;
     }
     if(!mux_v->bih || !sh_video->vfilter){
         mp_msg(MSGT_MENCODER,MSGL_FATAL,MSGTR_EncoderOpenFailed);
Index: libmpcodecs/Makefile
===================================================================
RCS file: /cvsroot/mplayer/main/libmpcodecs/Makefile,v
retrieving revision 1.61
diff -u -u -r1.61 Makefile
--- libmpcodecs/Makefile	10 Sep 2002 23:18:31 -0000	1.61
+++ libmpcodecs/Makefile	19 Sep 2002 21:16:32 -0000
@@ -7,7 +7,7 @@
 AUDIO_SRCS=dec_audio.c ad.c ad_liba52.c ad_acm.c ad_alaw.c ad_dk3adpcm.c ad_dshow.c ad_dvdpcm.c ad_ffmpeg.c ad_hwac3.c ad_imaadpcm.c ad_mp3lib.c ad_msadpcm.c ad_pcm.c ad_roqaudio.c ad_msgsm.c ad_faad.c ad_libvorbis.c ad_libmad.c ad_realaud.c ad_libdv.c
 VIDEO_SRCS=dec_video.c vd.c vd_null.c vd_realvid.c vd_cinepak.c vd_qtrpza.c vd_ffmpeg.c vd_dshow.c vd_vfw.c vd_vfwex.c vd_odivx.c vd_divx4.c vd_raw.c vd_xanim.c vd_msvidc.c vd_fli.c vd_qtrle.c vd_qtsmc.c vd_roqvideo.c vd_cyuv.c vd_nuv.c vd_libmpeg2.c vd_msrle.c vd_huffyuv.c vd_mpegpes.c vd_svq1.c vd_xvid.c vd_libdv.c vd_lcl.c vd_mtga.c
 VFILTER_SRCS=vf.c vf_vo.c vf_crop.c vf_expand.c vf_pp.c vf_scale.c vf_format.c vf_yuy2.c vf_flip.c vf_rgb2bgr.c vf_rotate.c vf_mirror.c vf_palette.c vf_lavc.c vf_dvbscale.c vf_cropdetect.c vf_test.c vf_noise.c vf_yvu9.c vf_rectangle.c vf_lavcdeint.c vf_eq.c vf_halfpack.c vf_dint.c
-ENCODER_SRCS=ve.c ve_divx4.c ve_lavc.c ve_vfw.c ve_rawrgb.c ve_libdv.c
+ENCODER_SRCS=ve.c ve_divx4.c ve_lavc.c ve_vfw.c ve_rawrgb.c ve_libdv.c ve_xvid.c
 NATIVE_SRCS=native/RTjpegN.c native/cinepak.c native/cyuv.c native/fli.c native/minilzo.c native/msvidc.c native/nuppelvideo.c native/qtrle.c native/qtrpza.c native/qtsmc.c native/roqav.c native/xa_gsm.c native/svq1.c
 
 ifeq ($(FAME),yes)
Index: libmpcodecs/ve.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpcodecs/ve.c,v
retrieving revision 1.3
diff -u -u -r1.3 ve.c
--- libmpcodecs/ve.c	13 Apr 2002 19:14:31 -0000	1.3
+++ libmpcodecs/ve.c	19 Sep 2002 21:16:32 -0000
@@ -14,6 +14,7 @@
 extern vf_info_t ve_info_vfw;
 extern vf_info_t ve_info_rawrgb;
 extern vf_info_t ve_info_libdv;
+extern vf_info_t ve_info_xvid;
 
 static vf_info_t* encoder_list[]={
 #ifdef HAVE_DIVX4ENCORE
@@ -29,6 +30,7 @@
     &ve_info_libdv,
 #endif
     &ve_info_rawrgb,
+    &ve_info_xvid,
     NULL
 };
 
-------------- next part --------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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

#define HAVE_XVIDENCORE

#ifdef HAVE_XVIDENCORE

#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"

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

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

#include <xvid.h>

#define XVID_API_VERSION_NEEDED ((2 << 16) | (1))
#if (API_VERSION != XVID_API_VERSION_NEEDED)
  #error "XViD version change detected, can't compile"
#endif

#include "cfgparser.h"

static int xvid_bitrate;
static int xvid_rc_averaging_period;
static int xvid_rc_reaction_delay_factor;
static int xvid_rc_buffer;
static int xvid_min_quantizer;
static int xvid_max_quantizer;
static int xvid_max_key_interval;
static int xvid_quality;

struct config xvidopts_conf[]={
	{"bitrate", &xvid_bitrate, CONF_TYPE_INT, CONF_RANGE, 4, 24000000, NULL},
	{"rc_reaction_delay_factor", &xvid_rc_reaction_delay_factor, CONF_TYPE_INT, 0,0,0, NULL},
	{"rc_averaging_period", &xvid_rc_averaging_period, CONF_TYPE_INT, 0,0,0, NULL},
	{"rc_buffer", &xvid_rc_buffer, CONF_TYPE_INT, 0,0,0, NULL},
	{"min_quant", &xvid_min_quantizer, CONF_TYPE_INT, CONF_RANGE,1,31, NULL},
	{"max_quant", &xvid_max_quantizer, CONF_TYPE_INT, CONF_RANGE,1,31, NULL},
	{"key", &xvid_max_key_interval, CONF_TYPE_INT, CONF_MIN,0,0, NULL},
	{"q", &xvid_quality, CONF_TYPE_INT, CONF_RANGE, 0, 6, NULL},
	{"help", "TODO: xvidopts help!\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL},
	{NULL, NULL, 0, 0, 0, 0, NULL}
};

static int motion_presets[7] = {
	0,                                                              // Q 0
	PMV_EARLYSTOP16,                                                // Q 1
	PMV_EARLYSTOP16,						// Q 2
	PMV_EARLYSTOP16 | PMV_HALFPELREFINE16,				// Q 3
	PMV_EARLYSTOP16 | PMV_HALFPELREFINE16,				// Q 4
	PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 | PMV_EARLYSTOP8	 	// Q 5
 			| PMV_HALFPELREFINE8, 	
	PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 | PMV_EXTSEARCH16 	// Q 6
			| PMV_USESQUARES16 | PMV_EARLYSTOP8 | PMV_HALFPELREFINE8
	};

static int general_presets[7] = {
	XVID_H263QUANT,	/* or use XVID_MPEGQUANT */		// Q 0
	XVID_MPEGQUANT, 					// Q 1
	XVID_H263QUANT, 			    		// Q 2
	XVID_H263QUANT | XVID_HALFPEL,				// Q 3
	XVID_H263QUANT | XVID_HALFPEL | XVID_INTER4V,		// Q 4
	XVID_H263QUANT | XVID_HALFPEL | XVID_INTER4V,		// Q 5
	XVID_H263QUANT | XVID_HALFPEL | XVID_INTER4V };		// Q 6


struct vf_priv_s {
    aviwrite_stream_t* mux;
    XVID_ENC_PARAM enc_param;
    XVID_ENC_FRAME enc_frame;
    XVID_ENC_STATS enc_stats;
    XVID_INIT_PARAM init_param;
    void *handle;
    FILE *stats_file;
    int frame_count;
};

#define mux_v (vf->priv->mux)

static int config(struct vf_instance_s* vf,
        int width, int height, int d_width, int d_height,
	unsigned int flags, unsigned int outfmt){

    int xerr;

    mux_v->bih->biWidth = width;
    mux_v->bih->biHeight = height;
    mux_v->bih->biSizeImage = mux_v->bih->biWidth * mux_v->bih->biHeight * 3;

    printf("videocodec: xvid (%dx%d fourcc=%x [%.4s])\n",
	mux_v->bih->biWidth, mux_v->bih->biHeight, mux_v->bih->biCompression,
	    (char *)&mux_v->bih->biCompression);

    // check input values and set some useful defaults
    if( !xvid_bitrate ) xvid_bitrate = 800000;
    else if( xvid_bitrate <= 16000 ) xvid_bitrate *= 1000;
    if( !xvid_quality ) xvid_quality = 4;
    if( !xvid_min_quantizer ) xvid_min_quantizer = 2;
    if( !xvid_max_quantizer ) xvid_max_quantizer = 15;
    if( !xvid_max_key_interval )
	xvid_max_key_interval = (int)(10.0 * (float)mux_v->h.dwRate / mux_v->h.dwScale);

    // initialise XViD
    vf->priv->init_param.cpu_flags = 0; // FIXME: use mencoder values
    xvid_init( NULL, 0, &vf->priv->init_param, NULL );
    if( vf->priv->init_param.api_version != API_VERSION ) {
	mp_msg( MSGT_MENCODER, MSGL_ERR, 
		"XViD: API version mismatch, header = %04x, library = %04x\n",
		API_VERSION, vf->priv->init_param.api_version );
	return 0;
    }

    // create a new encoding instance
    vf->priv->enc_param.width = width;
    vf->priv->enc_param.height = height;
    vf->priv->enc_param.fbase = mux_v->h.dwRate;
    vf->priv->enc_param.fincr = mux_v->h.dwScale;
    vf->priv->enc_param.min_quantizer = xvid_min_quantizer;
    vf->priv->enc_param.max_quantizer = xvid_max_quantizer;
    vf->priv->enc_param.rc_bitrate = xvid_bitrate;
    vf->priv->enc_param.max_key_interval = xvid_max_key_interval;
    vf->priv->enc_param.rc_averaging_period = xvid_rc_averaging_period;
    vf->priv->enc_param.rc_reaction_delay_factor = xvid_rc_reaction_delay_factor;
    vf->priv->enc_param.rc_buffer = xvid_rc_buffer;
    xerr = xvid_encore( &vf->priv->handle, XVID_ENC_CREATE, &vf->priv->enc_param, NULL );
    if( xerr != XVID_ERR_OK ) {
	mp_msg( MSGT_MENCODER, MSGL_ERR, "XViD: initialisation error = %d\n", xerr );
	return 0;
    }

    // pre-fill various things used in the actual encoding
    // FIXME: check if RGB24 & BGR24 shoud be mapped to the same
    // xvid colospace
    switch(outfmt){
    case IMGFMT_YV12:  vf->priv->enc_frame.colorspace = XVID_CSP_YV12; break;
    case IMGFMT_IYUV:
    case IMGFMT_I420:  vf->priv->enc_frame.colorspace = XVID_CSP_I420; break;
    case IMGFMT_YUY2:  vf->priv->enc_frame.colorspace = XVID_CSP_YUY2; break;
    case IMGFMT_UYVY:  vf->priv->enc_frame.colorspace = XVID_CSP_UYVY; break;
    case IMGFMT_RGB24:
    case IMGFMT_BGR24: vf->priv->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;
    }
    vf->priv->enc_frame.general = general_presets[ xvid_quality ];
    vf->priv->enc_frame.motion = motion_presets[ xvid_quality ];
    vf->priv->enc_frame.quant_intra_matrix = NULL;
    vf->priv->enc_frame.quant_inter_matrix = NULL;
    vf->priv->frame_count = 0;
    
    // FIXME: implement 2-pass encoding
    // FIXME: handle errors here
    vf->priv->stats_file = fopen( "xvid_stats.txt", "wt" );

    return 1;
}

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){
	// FIXME: check if IMGFMT_I420 is really supported without conversion
    case IMGFMT_YV12:
    case IMGFMT_IYUV:
    case IMGFMT_I420:
	return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW; // no conversion
    case IMGFMT_YUY2:
    case IMGFMT_UYVY:
	return VFCAP_CSP_SUPPORTED; // conversion
    case IMGFMT_RGB24:
    case IMGFMT_BGR24:
	// FIXME: check that
	return VFCAP_CSP_SUPPORTED | VFCAP_FLIPPED; // conversion+flipped
    }
    return 0;
}

static void put_image( struct vf_instance_s* vf, mp_image_t *mpi ) {
    int xerr;

    // FIXME: implement 2-pass code
    // FIXME: use HINTEDMV in pass 2

    vf->priv->enc_frame.image = mpi->planes[0];
    vf->priv->enc_frame.bitstream = mux_v->buffer;
    vf->priv->enc_frame.length = mux_v->buffer_size;

    vf->priv->enc_frame.quant = 0;
    vf->priv->enc_frame.intra = -1;
    xerr = xvid_encore( vf->priv->enc_param.handle, XVID_ENC_ENCODE, &vf->priv->enc_frame, &vf->priv->enc_stats );
    if( xerr == XVID_ERR_OK ) {
	if( vf->priv->stats_file )
	    fprintf( vf->priv->stats_file, 
		     "frame:%d q:%d slen:%d qlen:%d kblks:%d mblks:%d ublks:%d type:%c\n", 
		     vf->priv->frame_count, vf->priv->enc_stats.quant, vf->priv->enc_stats.hlength * 8, 
		     (vf->priv->enc_frame.length - vf->priv->enc_stats.hlength) * 8,
		     vf->priv->enc_stats.kblks, vf->priv->enc_stats.mblks, vf->priv->enc_stats.ublks,
		     vf->priv->enc_frame.intra ? 'I':'P' );
	vf->priv->frame_count++;
	mencoder_write_chunk( mux_v, vf->priv->enc_frame.length, vf->priv->enc_frame.intra ? 0x10 : 0 );
    } else
	mp_msg( MSGT_MENCODER, MSGL_ERR, "XViD: encoding error = %d\n", xerr );
}

static void uninit(struct vf_instance_s* vf) {
    xvid_encore( vf->priv->handle, XVID_ENC_DESTROY, NULL, NULL );
    if( vf->priv->stats_file )
	fclose( vf->priv->stats_file );
}

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

static int vf_open( vf_instance_t *vf, char* args ) {
    vf->uninit = uninit;
    vf->config = config;
    vf->control = control;
    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;

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

    return 1;
}

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

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


More information about the MPlayer-dev-eng mailing list