libxvid视频编码代码实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <sys/time.h>

//#include "portab.h" /* for pthread */

#include "xvid.h"

// Equivalent to vfw's pmvfast_presets
static const int motion_presets[] = {
	/* quality 0 */
	0,

	/* quality 1 */
	0,

	/* quality 2 */
	0,

	/* quality 3 */
	0,

	/* quality 4 */
	0 | XVID_ME_HALFPELREFINE16 | 0,

	/* quality 5 */
	0 | XVID_ME_HALFPELREFINE16 | 0 | XVID_ME_ADVANCEDDIAMOND16,

	/* quality 6 */
	XVID_ME_HALFPELREFINE16 | XVID_ME_EXTSEARCH16 |	XVID_ME_HALFPELREFINE8 | 0 | XVID_ME_USESQUARES16

};
#define ME_ELEMENTS (sizeof(motion_presets)/sizeof(motion_presets[0]))

static const int vop_presets[] = {
	/* quality 0 */
	0,

	/* quality 1 */
	0,

	/* quality 2 */
	0,

	/* quality 3 */
	0,

	/* quality 4 */
	0,

	/* quality 5 */
	XVID_VOP_INTER4V,

	/* quality 6 */
	XVID_VOP_INTER4V,

};
#define VOP_ELEMENTS (sizeof(vop_presets)/sizeof(vop_presets[0]))

#define MAX_XDIM 4096
#define MAX_YDIM 4096

#ifndef READ_PNM
#define IMAGE_SIZE(x,y) ((x)*(y)*3/2)
#else
#define IMAGE_SIZE(x,y) ((x)*(y)*3)
#endif

typedef struct 
 {
    void *enc_handle;              /**< Handle for Xvid encoder */
    int xsize;                     /**< Frame x size */
    int ysize;                     /**< Frame y size */
	int bitrate;
	float framerate;
	int me_quality;                /**< Motion estimation quality. 0: fast 6: best. */
    //int vop_flags;                 /**< VOP flags for Xvid encoder */
    //int vol_flags;                 /**< VOL flags for Xvid encoder */
    //int me_flags;                  /**< Motion Estimation flags */
    //int qscale;                    /**< Do we use constant scale? */
    //int quicktime_format;          /**< Are we in a QT-based format? */
    //char *twopassbuffer;           /**< Character buffer for two-pass */
    //char *old_twopassbuffer;       /**< Old character buffer (two-pass) */
    //char *twopassfile;             /**< second pass temp file name */
    //int twopassfd;
    //unsigned char *intra_matrix;   /**< P-Frame Quant Matrix */
    //unsigned char *inter_matrix;   /**< I-Frame Quant Matrix */
    //int lumi_aq;                   /**< Lumi masking as an aq method */
    //int variance_aq;               /**< Variance adaptive quantization */
    //int ssim;                      /**< SSIM information display mode */
    //int ssim_acc;                  /**< SSIM accuracy. 0: accurate. 4: fast. */
    //int gmc;
    //int mpeg_quant;                /**< Quantization type. 0: H.263, 1: MPEG */
} xvid_context;

static 	int ARG_DWRATE = 25;
static 	int ARG_DWSCALE = 1;
static 	int ARG_MAXKEYINTERVAL = 300;

//static 	int ARG_NUM_APP_THREADS = 1;

static 	char *ARG_INPUTFILE = NULL;
static 	char *ARG_OUTPUTFILE = NULL;

static 	int ARG_QUANTS[6] = {2, 31, 2, 31, 2, 31};
const char userdata_start_code[] = "\0\0\x01\xb2";

static double msecond();
int gcd(int a, int b);

static int read_yuvdata(FILE * handle, xvid_context *x, unsigned char *image);
static void enc_gbl(int use_assembler);

static int xvid_encode_init(xvid_context *x);
static int xvid_encode_frame(xvid_context *x, 
                            unsigned char *image, 
							unsigned char *bitstream, 
							int *key, 
							int *stats_type);
static int xvid_encode_close(xvid_context* x);

void removedivxp(char *buf, int size);

static double msecond()
{
#ifndef WIN32
	struct timeval tv;

	gettimeofday(&tv, 0);
	return (tv.tv_sec * 1.0e3 + tv.tv_usec * 1.0e-3);
#else
	clock_t clk;

	clk = clock();
	return (clk * 1000.0 / CLOCKS_PER_SEC);
#endif
}

int gcd(int a, int b)
{
	int r ;

	if (b > a) {
		r = a;
		a = b;
		b = r;
	}

	while ((r = a % b)) {
		a = b;
		b = r;
	}
	return b;
}

static int read_yuvdata(FILE * handle, xvid_context* x, unsigned char *image)
{
	if (fread(image, 1, IMAGE_SIZE(x->xsize, x->ysize), handle) !=
		(unsigned int) IMAGE_SIZE(x->xsize, x->ysize))
		return (1);
	else
		return (0);
}

static void enc_gbl(int use_assembler)
{
	xvid_gbl_init_t xvid_gbl_init;

	/*------------------------------------------------------------------------
	 * Xvid core initialization
	 *----------------------------------------------------------------------*/
	/* Set version -- version checking will done by xvidcore */
	memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init));
	xvid_gbl_init.version = XVID_VERSION;
    xvid_gbl_init.debug = 0;//ARG_DEBUG;

    if (use_assembler) 
	    xvid_gbl_init.cpu_flags = 0;
	else 
	    xvid_gbl_init.cpu_flags = XVID_CPU_FORCE;

	/* Initialize Xvid core -- Should be done once per __process__ */
	xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL);
    //ARG_CPU_FLAGS = xvid_gbl_init.cpu_flags;
	----------------------------------------------
	xvid_gbl_info_t xvid_gbl_info;
	int ret;
	memset(&xvid_gbl_info, 0, sizeof(xvid_gbl_info));
	xvid_gbl_info.version = XVID_VERSION;
	ret = xvid_global(NULL, XVID_GBL_INFO, &xvid_gbl_info, NULL);
}

void removedivxp(char *buf, int bufsize) {
	int i;
	char* userdata;

	for (i=0; i <= (int)(bufsize-sizeof(userdata_start_code)); i++) {
		if (memcmp((void*)userdata_start_code, (void*)(buf+i), strlen(userdata_start_code))==0) {
			if ((userdata = strstr(buf+i+4, "DivX"))!=NULL) {
				userdata[strlen(userdata)-1] = '\0';
				return;
			}
		}
	}
}

int main(int argc, char *argv[])
{
    int i;
	int result;
	int key;
	int type;
	int m4v_size;
    FILE *in_file;
	FILE *out_file;

    //memset(framestats, 0, sizeof(framestats));
    xvid_context *x = (xvid_context*)malloc(sizeof(xvid_context));

    for (i = 1; i < argc; i++) 
	{
        if (strcmp("-w", argv[i]) == 0 && i < argc - 1) {
			i++;
			x->xsize = atoi(argv[i]);
		} else if (strcmp("-h", argv[i]) == 0 && i < argc - 1) {
			i++;
			x->ysize = atoi(argv[i]);
		} else if (strcmp("-bitrate", argv[i]) == 0) {
			i++;
			x->bitrate = atoi(argv[i]);
		} else if (strcmp("-framerate", argv[i]) == 0 && i < argc - 1) {
			int exponent;
			i++;
			x->framerate = (float) atof(argv[i]);
			exponent = (int) strcspn(argv[i], ".");
			if (exponent<(int)strlen(argv[i]))
				exponent=(int)pow(10.0, (int)(strlen(argv[i])-1-exponent));
			else
				exponent=1;
			ARG_DWRATE = (int)(atof(argv[i])*exponent);
			ARG_DWSCALE = exponent;
			exponent = gcd(ARG_DWRATE, ARG_DWSCALE);
			ARG_DWRATE /= exponent;
			ARG_DWSCALE /= exponent;
		} else if (strcmp("-i", argv[i]) == 0 && i < argc - 1) {
			i++;
			ARG_INPUTFILE = argv[i];
		} else if (strcmp("-o", argv[i]) == 0 && i < argc - 1) {
			i++;
			ARG_OUTPUTFILE = argv[i];
		}
    }

	fprintf(stdout, "xsize value - ysize value %d - %d \n", x->xsize, x->ysize);

    //---------------------------------------------------------------------------//
	if (ARG_INPUTFILE != NULL) {
		in_file = fopen(ARG_INPUTFILE, "rb");
		if (in_file == NULL) {
			fprintf(stderr, "Error opening input file %s\n", ARG_INPUTFILE);
			return (-1);
		}
	}
	
	if (ARG_OUTPUTFILE != NULL) {
		out_file = fopen(ARG_OUTPUTFILE, "w+b");
		if (out_file == NULL) {
			fprintf(stderr, "Error opening output file %s\n", ARG_OUTPUTFILE);
			return (-1);
		}
	}

	fseek(in_file, 0, SEEK_SET);

	/* now we know the sizes, so allocate memory */
	unsigned char *image = (unsigned char *) malloc(4*x->xsize*x->ysize);
	if (!image)
		goto release_all;

	/* this should really be enough memory ! */
	unsigned char *mp4_buffer = (unsigned char *) malloc(IMAGE_SIZE(x->xsize, x->ysize) * 2);
	if (!mp4_buffer)
		goto release_all;
	
	// ------------------------------------------------------------------------//
	result = xvid_encode_init(x);
	if (result) {
		fprintf(stderr, "Encore INIT problem, return value %d\n", result);
		goto release_all;
	}

	// ------------------------------------------------------------------------//
	i = 0;
	do {
        result = read_yuvdata(in_file, x, image);

	    double enctime = msecond();
		m4v_size = xvid_encode_frame(x, !result ? image : 0, mp4_buffer, &key, &type);
		enctime = msecond() - enctime;

		fprintf(stdout, "frame_num= %d, ", ++i);
		//fprintf(stdout, "m4v_size= %d\n", m4v_size);
	    if (m4v_size < 0)
		    break;

        if (m4v_size > 0) {
        	/* Save ES stream */
            //fprintf(stdout, "type= %d\n", type);

			if (out_file && (type != XVID_TYPE_BVOP) || (m4v_size > 8) ) 
			{
				fwrite(mp4_buffer, 1, m4v_size, out_file);
			}
    	}
		
	} while(1);

	// ----------------------------------------------------------------------------//
	result = xvid_encode_close(x);

	//----------------------------------------------------------//
release_all:
    if (in_file)
	    fclose(in_file);
	if (out_file)
		fclose(out_file);

	if (mp4_buffer)
	    free(mp4_buffer);
	if (image)
	    free(image);

    return (0);
//-------------------------------------------------------------------------------------------//
}

static int xvid_encode_init(xvid_context *x)
{
    /* Init xvidcore */
    enc_gbl(/*use_assembler*/ 1);

    int xerr;
	//xvid_plugin_cbr_t cbr;
    xvid_plugin_single_t single;
	//xvid_plugin_fixed_t rcfixed;
	xvid_enc_plugin_t plugins[8];
	xvid_enc_create_t xvid_enc_create;

	/*------------------------------------------------------------------------
	 * Xvid encoder initialization
	 *----------------------------------------------------------------------*/

	/* Version again */
	memset(&xvid_enc_create, 0, sizeof(xvid_enc_create));
	xvid_enc_create.version = XVID_VERSION;

	/* Width and Height of input frames */
	xvid_enc_create.width = x->xsize;
	xvid_enc_create.height = x->ysize;
	xvid_enc_create.profile = 0xf5; /* Unrestricted */

	/* init plugins  */

	xvid_enc_create.plugins = plugins;
	xvid_enc_create.num_plugins = 0;

	if (1/*ARG_SINGLE*/) {
		memset(&single, 0, sizeof(xvid_plugin_single_t));
		single.version = XVID_VERSION;
		single.bitrate = x->bitrate;
		single.reaction_delay_factor = 16;//ARG_REACTION;
		single.averaging_period = 100;//ARG_AVERAGING;
		single.buffer = 100;//ARG_SMOOTHER;
		

		plugins[xvid_enc_create.num_plugins].func = xvid_plugin_single;
		plugins[xvid_enc_create.num_plugins].param = &single;
		xvid_enc_create.num_plugins++;
	}

	/* We don't use zones */
    xvid_enc_create.zones     = NULL;
    xvid_enc_create.num_zones = 0;

	xvid_enc_create.num_threads = 1;//ARG_THREADS;
	xvid_enc_create.num_slices  = 1;//ARG_SLICES;

	/* Frame rate  */
	xvid_enc_create.fincr = ARG_DWSCALE;
	xvid_enc_create.fbase = ARG_DWRATE;

	/* Maximum key frame interval */
    if (ARG_MAXKEYINTERVAL > 0) {
        xvid_enc_create.max_key_interval = ARG_MAXKEYINTERVAL;
    }else {
	    xvid_enc_create.max_key_interval = (int) x->framerate *10;
    }

	xvid_enc_create.min_quant[0]=ARG_QUANTS[0];
	xvid_enc_create.min_quant[1]=ARG_QUANTS[2];
	xvid_enc_create.min_quant[2]=ARG_QUANTS[4];
	xvid_enc_create.max_quant[0]=ARG_QUANTS[1];
	xvid_enc_create.max_quant[1]=ARG_QUANTS[3];
	xvid_enc_create.max_quant[2]=ARG_QUANTS[5];

	/* Bframes settings */
	xvid_enc_create.max_bframes = 2;//ARG_MAXBFRAMES;
	xvid_enc_create.bquant_ratio = 150;//ARG_BQRATIO;
	xvid_enc_create.bquant_offset = 100;//ARG_BQOFFSET;

	/* Frame drop ratio */
	xvid_enc_create.frame_drop_ratio = 0;//ARG_FRAMEDROP;

	/* Start frame number */
	xvid_enc_create.start_frame_num = 0;//start_num;

	/* Global encoder options */
	xvid_enc_create.global = 0;

	if (1/*ARG_PACKED*/)
		xvid_enc_create.global |= XVID_GLOBAL_PACKED;

	if (1/*ARG_CLOSED_GOP*/)
		xvid_enc_create.global |= XVID_GLOBAL_CLOSED_GOP;

	/* I use a small value here, since will not encode whole movies, but short clips */
	xerr = xvid_encore(NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL);

	/* Retrieve the encoder instance from the structure */
	x->enc_handle = xvid_enc_create.handle;
	x->me_quality = 6;

	free(xvid_enc_create.zones);
	return (xerr);
}

static int xvid_encode_frame(
	xvid_context *x, unsigned char *image, unsigned char *bitstream, int *key, int *stats_type)
 {
    int ret;
    do {
		xvid_enc_frame_t xvid_enc_frame;
		xvid_enc_stats_t xvid_enc_stats;

		/* Version for the frame and the stats */
		memset(&xvid_enc_frame, 0, sizeof(xvid_enc_frame));
		xvid_enc_frame.version = XVID_VERSION;

		memset(&xvid_enc_stats, 0, sizeof(xvid_enc_stats));
		xvid_enc_stats.version = XVID_VERSION;

		/* Bind output buffer */
		xvid_enc_frame.bitstream = bitstream;
		xvid_enc_frame.length = -1;

		/* Initialize input image fields */
		if (image) {
    	    xvid_enc_frame.input.plane[0] = image;
			xvid_enc_frame.input.csp = XVID_CSP_I420;
			xvid_enc_frame.input.stride[0] = x->xsize;
		} else {
			xvid_enc_frame.input.csp = XVID_CSP_NULL;
		}

		/* Set up core's general features */
		xvid_enc_frame.vol_flags = 0;

        xvid_enc_frame.par = 1;

		//int div;
		//div = gcd(x->xsize, x->ysize);
		//xvid_enc_frame.par = XVID_PAR_EXT;
		//xvid_enc_frame.par_width = x->xsize/div;
		//xvid_enc_frame.par_height = x->ysize/div;

		// /* Set up core's general features */
		xvid_enc_frame.vop_flags = vop_presets[x->me_quality];

		xvid_enc_frame.vop_flags |= XVID_VOP_HALFPEL;
		xvid_enc_frame.vop_flags |= XVID_VOP_HQACPRED;

		//if (ARG_TRELLIS)
   		xvid_enc_frame.vop_flags |= XVID_VOP_TRELLISQUANT;

		/* Frame type -- taken from function call parameter */
		/* Sometimes we might want to force the last frame to be a P Frame */
		xvid_enc_frame.type = XVID_TYPE_AUTO;

		/* Force the right quantizer -- It is internally managed by RC plugins */
		xvid_enc_frame.quant = 0;

		//if (ARG_CHROMAME)
		xvid_enc_frame.motion |= XVID_ME_CHROMA_PVOP + XVID_ME_CHROMA_BVOP;

		/* Set up motion estimation flags */
		xvid_enc_frame.motion |= motion_presets[x->me_quality];

		// switch (ARG_VHQMODE) /* this is the same code as for vfw */
		// {
		// case 1: /* VHQ_MODE_DECISION */
		 	xvid_enc_frame.vop_flags |= XVID_VOP_MODEDECISION_RD;
		// 	break;

		// case 2: /* VHQ_LIMITED_SEARCH */
		// 	xvid_enc_frame.vop_flags |= XVID_VOP_MODEDECISION_RD;
		// 	xvid_enc_frame.motion |= XVID_ME_HALFPELREFINE16_RD;
		// 	xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE16_RD;
		// 	break;

		// case 3: /* VHQ_MEDIUM_SEARCH */
		// 	xvid_enc_frame.vop_flags |= XVID_VOP_MODEDECISION_RD;
		// 	xvid_enc_frame.motion |= XVID_ME_HALFPELREFINE16_RD;
		// 	xvid_enc_frame.motion |= XVID_ME_HALFPELREFINE8_RD;
		// 	xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE16_RD;
		// 	xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE8_RD;
		// 	xvid_enc_frame.motion |= XVID_ME_CHECKPREDICTION_RD;
		// 	break;

		//case 4: /* VHQ_WIDE_SEARCH */
			// xvid_enc_frame.vop_flags |= XVID_VOP_MODEDECISION_RD;
			// xvid_enc_frame.motion |= XVID_ME_HALFPELREFINE16_RD;
			// xvid_enc_frame.motion |= XVID_ME_HALFPELREFINE8_RD;
			// xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE16_RD;
			// xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE8_RD;
			// xvid_enc_frame.motion |= XVID_ME_CHECKPREDICTION_RD;
			// xvid_enc_frame.motion |= XVID_ME_EXTSEARCH_RD;
		//	break;

		//default :
		//	break;
		//}

		/* Not sure what this does */
		// force keyframe spacing in 2-pass 1st pass

		/* frame-based stuff */
		//apply_zone_modifiers(&xvid_enc_frame, framenum);

		/* Encode the frame */
		ret = xvid_encore(x->enc_handle, XVID_ENC_ENCODE, &xvid_enc_frame, 
			&xvid_enc_stats);

		*key = (xvid_enc_frame.out_flags & XVID_KEYFRAME);
		*stats_type = xvid_enc_stats.type;
    } while (0);

	return (ret);
}

static int xvid_encode_close(xvid_context* x)
{
	int xerr;
	/* Destroy the encoder instance */
	xerr = xvid_encore(x->enc_handle, XVID_ENC_DESTROY, NULL, NULL);

	return (xerr);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值