--- trunk/xvidcore/examples/xvid_stat.c 2002/09/12 21:18:49 482 +++ trunk/xvidcore/examples/xvid_stat.c 2002/09/14 23:54:17 483 @@ -5,15 +5,6 @@ * * Copyright(C) 2002 Christoph Lampert * - * This program is an implementation of a part of one or more MPEG-4 - * Video tools as specified in ISO/IEC 14496-2 standard. Those intending - * to use this software module in hardware or software products are - * advised that its use may infringe existing patents or copyrights, and - * any such use would be at such party's own risk. The original - * developer of this software module and his/her company, and subsequent - * editors and their companies, will have no liability for use of this - * software or modifications or derivatives thereof. - * * 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 @@ -28,135 +19,560 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id: xvid_stat.c,v 1.5 2002-09-12 19:18:12 chl Exp $ + * $Id: xvid_stat.c,v 1.6 2002-09-14 23:54:17 edgomez Exp $ * ****************************************************************************/ -/************************************************************************ - * - * PSNR and Speed test routine for XviD using the XviD-API - * (C) Christoph Lampert, 2002/04/13 +/***************************************************************************** + * Application notes : * * A sequence of YUV pics in PGM file format is encoded and decoded * The speed is measured and PSNR of decoded picture is calculated. * * The program is plain C and needs no libraries except for libxvidcore, - * and maths-lib ,so with UN*X you simply compile by + * and maths-lib. * - * gcc xvid_stat.c -lxvidcore -lm -o xvid_stat + * Usage : xvid_stat [OPTIONS] + * Options : + * -w integer : frame width ([1.2048]) + * -h integer : frame height ([1.2048]) + * -b integer : target bitrate (>0 | default=900kbit) + * -f float : target framerate (>0) + * -i string : input filename (default=stdin) + * -t integer : input data type (yuv=0, pgm=1) + * -n integer : number of frames to encode + * -q integer : quality ([0..5]) + * -d boolean : save decoder output (0 False*, !=0 True) + * -m boolean : save mpeg4 raw stream (0 False*, !=0 True) + * -h, -help : prints this help message + * -quant integer : fixed quantizer (disables -b setting) + * (* means default) + * + * An input file named "stdin" is treated as standard input stream. + * + * + * PGM input must be in a very specific format, basically it pgm file must + * contain Y plane first just like usual P5 pgm files, and then U and V + * planes are stored just after Y plane so y dimension is y*3/2 in reality * - * Run without or with illegal parameters, then PGM input input is read - * from stdin. - * - * Parameters are: xvid_stat XDIM YDIM QUALITY BITRATE/QUANTIZER FRAMERATE - * - * if XDIM or YDIM are illegal (e.g. 0), they are ignored and input is - * considered to be PGM. Otherwise (X and Y both greater than 0) raw YUV - * is expected, as e.g. the standard MPEG test-files, like "foreman" - * - * 0 <= QUALITY <= 6 (default 5) - * - * BITRATE is in kbps (default 900), - * if BITRATE<32, then value is taken is fixed QUANTIZER - * - * FRAMERATE is a float (with or without decimal dot), default is 25.00 + * See read_pgmheader for more details. * - * input/output and m4v-output is saved, if corresponding flags are set - * - * PGM input must in a very specific format, see read_pgmheader - * it can be generated e.g. from MPEG2 by mpeg2dec -o pgmpipe + * Such a PGM file can be generated from MPEG2 by # mpeg2dec -o pgmpipe * - ************************************************************************/ - -/************************************************************************ - * - * For EXAMPLES how to use this, see the seperate file xvid_stat.examples - * - ************************************************************************/ + ****************************************************************************/ #include #include -#include // needed for log10 -#include // only needed for gettimeofday +#include +#include +#include + +#include "../src/xvid.h" + +/**************************************************************************** + * Prototypes + ***************************************************************************/ + +/* Prints program usage message */ +static void usage(); + +/* Statistical functions */ +static double msecond(); +static double absdistq(int x, int y, + unsigned char* buf1, int stride1, + unsigned char* buf2, int stride2); +static double PSNR(int x, int y, + unsigned char* buf1, int stride1, + unsigned char* buf2, int stride2); + +/* PGM related functions */ +static int read_pgmheader(FILE* handle); +static int read_pgmdata(FILE* handle, unsigned char *image); +static int read_yuvdata(FILE* handle, unsigned char *image); +static int write_pgm(char *filename, unsigned char *image); + +/* Encoder related functions */ +static int enc_init(int use_assembler); +static int enc_stop(); +static int enc_main(unsigned char* image, unsigned char* bitstream, + int *streamlength, int* frametype); + +/* Decoder related functions */ +static int dec_stop(); +static int dec_main(unsigned char *m4v_buffer, unsigned char *out_buffer, + int m4v_size); +static int dec_init(int use_assembler); -#include "../src/xvid.h" /* comes with XviD */ +/***************************************************************************** + * Quality presets + ****************************************************************************/ -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 - }; - -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 +static int const 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 const general_presets[7] = { + XVID_H263QUANT, // 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 +}; -/* my default values for encoding */ +/***************************************************************************** + * Command line global variables + ****************************************************************************/ -#define ABS_MAXFRAMENR 9999 // max number of frames +/* Maximum number of frames to encode */ +#define ABS_MAXFRAMENR 9999 -int ARG_BITRATE=900; -int ARG_QUANTI=0; +static int ARG_BITRATE = 900; +static int ARG_QUANTI = 0; +static int ARG_QUALITY = 6; +static int ARG_MINQUANT = 1; +static int ARG_MAXQUANT = 31; +static float ARG_FRAMERATE = 25.00f; +static int ARG_MAXFRAMENR = ABS_MAXFRAMENR; +static char *ARG_INPUTFILE = NULL; +static int ARG_INPUTTYPE = 0; +static int ARG_SAVEDECOUTPUT = 0; +static int ARG_SAVEMPEGSTREAM = 0; +static int XDIM = 0; +static int YDIM = 0; -int ARG_QUALITY =6; -int ARG_MINQUANT=1; -int ARG_MAXQUANT=31; -float ARG_FRAMERATE=25.00; +#define MAX(A,B) ( ((A)>(B)) ? (A) : (B) ) +#define SMALL_EPS 1e-10 -int ARG_MAXFRAMENR=ABS_MAXFRAMENR; +/**************************************************************************** + * Nasty global vars ;-) + ***************************************************************************/ + +static int i,filenr = 0; +static int save_ref_flag = 0; + +/* the path where to save output */ +static char filepath[256] = "./"; + +/* Internal structures (handles) for encoding and decoding */ +static void *enc_handle = NULL; +static void *dec_handle = NULL; +/***************************************************************************** + * Main program + ****************************************************************************/ -#define MAX(A,B) ( ((A)>(B)) ? (A) : (B) ) -#define SMALL_EPS 1e-10 +int main(int argc, char *argv[]) +{ + + unsigned char *divx_buffer = NULL; + unsigned char *in_buffer = NULL; + unsigned char *out_buffer = NULL; + + double enctime,dectime; + double totalenctime=0.; + double totaldectime=0.; + + long totalsize=0; + int status; + + int m4v_size; + int frame_type[ABS_MAXFRAMENR]; + int Iframes=0, Pframes=0, use_assembler=0; + double framepsnr[ABS_MAXFRAMENR]; + + double Ipsnr=0.,Imaxpsnr=0.,Iminpsnr=999.,Ivarpsnr=0.; + double Ppsnr=0.,Pmaxpsnr=0.,Pminpsnr=999.,Pvarpsnr=0.; + double Bpsnr=0.,Bmaxpsnr=0.,Bminpsnr=999.,Bvarpsnr=0.; + + char filename[256]; + + FILE *filehandle; + FILE *in_file = stdin; + + printf("xvid_stat - XviD core library test program "); + printf("written by Christoph Lampert 2002\n\n"); + +/***************************************************************************** + * Command line parsing + ****************************************************************************/ + + for (i=1; i< argc; i++) { + + if (strcmp("-asm", argv[i]) == 0 ) { + use_assembler = 1; + } + else if (strcmp("-w", argv[i]) == 0 && i < argc - 1 ) { + i++; + XDIM = atoi(argv[i]); + } + else if (strcmp("-h", argv[i]) == 0 && i < argc - 1 ) { + i++; + YDIM = atoi(argv[i]); + } + else if (strcmp("-b", argv[i]) == 0 && i < argc - 1 ) { + i++; + ARG_BITRATE = atoi(argv[i]); + } + else if (strcmp("-q", argv[i]) == 0 && i < argc - 1 ) { + i++; + ARG_QUALITY = atoi(argv[i]); + } + else if (strcmp("-f", argv[i]) == 0 && i < argc - 1 ) { + i++; + ARG_FRAMERATE = (float)atof(argv[i]); + } + else if (strcmp("-i", argv[i]) == 0 && i < argc - 1 ) { + i++; + ARG_INPUTFILE = argv[i]; + } + else if (strcmp("-t", argv[i]) == 0 && i < argc - 1 ) { + i++; + ARG_INPUTTYPE = atoi(argv[i]); + } + else if(strcmp("-n", argv[i]) == 0 && i < argc - 1 ) { + i++; + ARG_MAXFRAMENR = atoi(argv[i]); + } + else if (strcmp("-quant", argv[i]) == 0 && i < argc - 1 ) { + i++; + ARG_QUANTI = atoi(argv[i]); + } + else if (strcmp("-d", argv[i]) == 0 && i < argc - 1 ) { + i++; + ARG_SAVEDECOUTPUT = atoi(argv[i]); + } + else if (strcmp("-m", argv[i]) == 0 && i < argc - 1 ) { + i++; + ARG_SAVEMPEGSTREAM = atoi(argv[i]); + } + else if (strcmp("-h", argv[i]) == 0 || strcmp("-help", argv[i])) { + usage(); + return(0); + } + else { + usage(); + exit(-1); + } + + } + +/***************************************************************************** + * Arguments checking + ****************************************************************************/ + + if ( ARG_INPUTTYPE == 0 && + ((XDIM <= 0) || (XDIM >= 2048) || (YDIM <=0) || (YDIM >= 2048)) ) { + fprintf(stderr, + "Wrong frame sizes width=%d height=%d, trying PGM header infos\n", + XDIM, + YDIM); + ARG_INPUTTYPE = 1; /* pgm */ + } + else { + YDIM = YDIM*3/2; /* YUV */ + } + + if ( ARG_QUALITY < 0 || ARG_QUALITY > 6) { + fprintf(stderr,"Wrong Quality\n"); + return -1; + } + + if ( ARG_BITRATE <= 0 && ARG_QUANTI == 0) { + fprintf(stderr,"Wrong Bitrate\n"); + return -1; + } + + if ( ARG_FRAMERATE <= 0) { + fprintf(stderr,"Wrong Fraterate %s \n",argv[5]); + return -1; + } + + if ( ARG_MAXFRAMENR <= 0) { + fprintf(stderr,"Wrong number of frames\n"); + return -1; + } + + if ( ARG_INPUTFILE == NULL || strcmp(ARG_INPUTFILE, "stdin") == 0) { + in_file = stdin; + } + else { + + in_file = fopen(ARG_INPUTFILE, "rb"); + if (in_file == NULL) { + fprintf(stderr, "Error opening input file %s\n", ARG_INPUTFILE); + return -1; + } + } + + if (ARG_INPUTTYPE) { + if (read_pgmheader(in_file)) { + fprintf(stderr, "Wrong input format, I want YUV encapsulated in PGM\n"); + return -11; + } + } + + /* now we know the sizes, so allocate memory */ + + in_buffer = (unsigned char *) malloc(XDIM*YDIM); + if (!in_buffer) + goto free_all_memory; + + /* this should really be enough memory ! */ + divx_buffer = (unsigned char *) malloc(XDIM*YDIM*2); + if (!divx_buffer) + goto free_all_memory; + + /* PGM is YUV 4:2:0 format, so real image height is *2/3 of PGM picture */ + YDIM = YDIM*2/3; + + out_buffer = (unsigned char *) malloc(XDIM*YDIM*4); + if (!out_buffer) + goto free_all_memory; + + +/***************************************************************************** + * XviD PART Start + ****************************************************************************/ + + + status = enc_init(use_assembler); + if (status) + { + fprintf(stderr, "Encore INIT problem, return value %d\n", status); + goto release_all; + } + + status = dec_init(use_assembler); + if (status) + { + fprintf(stderr, "Decore INIT problem, return value %d\n", status); + goto release_all; + } + + +/***************************************************************************** + * Main loop + ****************************************************************************/ + + do { + + if (ARG_INPUTTYPE) + status = read_pgmdata(in_file, in_buffer); // read PGM data (YUV-format) + else + status = read_yuvdata(in_file, in_buffer); // read raw data (YUV-format) + + if (status) + { + /* Couldn't read image, most likely end-of-file */ + continue; + } + + + if (save_ref_flag) + { + sprintf(filename, "%s%05d.pgm", filepath, filenr); + write_pgm(filename,in_buffer); + } + + +/***************************************************************************** + * Analyse this frame before encoding + ****************************************************************************/ -/* these are global variables. Not very elegant, but easy, and this is an easy program */ +/* + * nothing is done here at the moment, but you could e.g. create + * histograms or measure entropy or apply preprocessing filters... + */ + +/***************************************************************************** + * Encode and decode this frame + ****************************************************************************/ + + enctime = msecond(); + status = enc_main(in_buffer, divx_buffer, &m4v_size, &frame_type[filenr]); + enctime = msecond() - enctime; + + totalenctime += enctime; + totalsize += m4v_size; + + printf("Frame %5d: intra %1d, enctime=%6.1f ms, size=%6d bytes ", + (int)filenr, (int)frame_type[filenr], (float)enctime, (int)m4v_size); + + if (ARG_SAVEMPEGSTREAM) + { + sprintf(filename, "%sframe%05d.m4v", filepath, filenr); + filehandle = fopen(filename, "wb"); + fwrite(divx_buffer, m4v_size, 1, filehandle); + fclose(filehandle); + } + + dectime = msecond(); + status = dec_main(divx_buffer, out_buffer, m4v_size); + dectime = msecond() - dectime; + + totaldectime += dectime; + + +/***************************************************************************** + * Analyse the decoded frame and compare to original + ****************************************************************************/ + + framepsnr[filenr] = PSNR(XDIM,YDIM, in_buffer, XDIM, out_buffer, XDIM ); + + printf("dectime =%6.1f ms PSNR %5.2f\n",dectime, framepsnr[filenr]); + + if (ARG_SAVEDECOUTPUT) + { + sprintf(filename, "%sdec%05d.pgm", filepath, filenr); + write_pgm(filename, out_buffer); + } + + /* Read the header if it's pgm stream */ + if (ARG_INPUTTYPE) + status = read_pgmheader(in_file); + + filenr++; + + } while ( (!status) && (filenr Pmaxpsnr) + Pmaxpsnr = framepsnr[i]; + if (framepsnr[i] < Pminpsnr) + Pminpsnr = framepsnr[i]; + Pvarpsnr += (framepsnr[i] - Ppsnr)*(framepsnr[i] - Ppsnr) /Pframes; + break; + case 1: + if (framepsnr[i] > Imaxpsnr) + Imaxpsnr = framepsnr[i]; + if (framepsnr[i] < Pminpsnr) + Iminpsnr = framepsnr[i]; + Ivarpsnr += (framepsnr[i] - Ipsnr)*(framepsnr[i] - Ipsnr) /Iframes; + default: + break; + } + } -int XDIM=0; -int YDIM=0; // will be set when reading first image -int i,filenr = 0; - -int save_m4v_flag = 0; // save MPEG4-bytestream? -int save_dec_flag = 1; // save decompressed bytestream? -int save_ref_flag = 0; // - -int pgmflag = 0; // a flag, if input is in PGM format, overwritten in init-phase -char filepath[256] = "./"; // the path where to save output - -void *enc_handle = NULL; // internal structures (handles) for encoding -void *dec_handle = NULL; // and decoding - - -/*********************************************************************/ -/* "statistical" functions */ -/* */ -/* these are not needed for encoding or decoding, but for measuring */ -/* time and quality, there in nothing specific to XviD in these */ -/* */ -/*********************************************************************/ + /* Print all statistics */ + printf("Avg. Q%1d %2s ",ARG_QUALITY, (ARG_QUANTI ? " q" : "br")); + printf("%04d ",MAX(ARG_QUANTI,ARG_BITRATE)); + printf("( %.2f bpp) ", (double)ARG_BITRATE*1000/XDIM/YDIM/ARG_FRAMERATE); + printf("size %6d ",totalsize); + printf("( %4d kbps ",(int)(totalsize*8*ARG_FRAMERATE/1000)); + printf("/ %.2f bpp) ",(double)totalsize*8/XDIM/YDIM); + printf("enc: %6.1f fps, dec: %6.1f fps \n",1/totalenctime, 1/totaldectime); + printf("PSNR P(%d): %5.2f ( %5.2f , %5.2f ; %5.4f ) ",Pframes,Ppsnr,Pminpsnr,Pmaxpsnr,sqrt(Pvarpsnr/filenr)); + printf("I(%d): %5.2f ( %5.2f , %5.2f ; %5.4f ) ",Iframes,Ipsnr,Iminpsnr,Imaxpsnr,sqrt(Ivarpsnr/filenr)); + printf("\n"); + +/***************************************************************************** + * XviD PART Stop + ****************************************************************************/ + + release_all: + + if (enc_handle) + { + status = enc_stop(); + if (status) + fprintf(stderr, "Encore RELEASE problem return value %d\n", status); + } + + if (dec_handle) + { + status = dec_stop(); + if (status) + fprintf(stderr, "Decore RELEASE problem return value %d\n", status); + } + + fclose(in_file); + + free_all_memory: + free(out_buffer); + free(divx_buffer); + free(in_buffer); + + return 0; -double msecond() -/* return the current time in seconds(!) */ +} + +/***************************************************************************** + * "statistical" functions + * + * these are not needed for encoding or decoding, but for measuring + * time and quality, there in nothing specific to XviD in these + * + *****************************************************************************/ + + + +/* Return time elapsed time in miliseconds since the program started */ +static double msecond() { - struct timeval tv; - gettimeofday(&tv, 0); - return tv.tv_sec + tv.tv_usec * 1.0e-6; + clock_t clk; + + clk = clock(); + + return clk * 1000 / CLOCKS_PER_SEC; + } -double absdistq(int x,int y, unsigned char* buf1, int stride1, unsigned char* buf2, int stride2) -/* returns the sum of squared distances (SSD) between two images of dimensions x times y */ +/* + * Returns the sum of squared distances (SSD) between two images of dimensions + * x times y + */ +static double absdistq(int x, int y, + unsigned char* buf1, int stride1, + unsigned char* buf2, int stride2) { double dist=0.; int i,j,val; @@ -171,28 +587,68 @@ buf1 += stride1; buf2 += stride2; } - return dist/(x*y); + return dist/(x*y); } -double PSNR(int x,int y, unsigned char* buf1, int stride1, unsigned char* buf2, int stride2 ) -/* return the PSNR between to images */ -/* this is a logarithmic measure for "quality" from the world of signal processing */ -/* if you don't know what it is, simply accept that higher values are better */ +/* + * Returns the PSNR between to images. + * + * This is a common logarithmic measure for "quality" from the world of signal + * processing if you don't know what it is, simply accept that higher values + * are better. + * + * PSNR represents the ratio of useful signal over noise signal. In our case, + * useful signal is refernce image, noise signal is the difference between + * reference and decoded frame from encoded bitstream. + * + * The problem is this type of value is dependant of image source and so, is + * not reliable as a common "quality" indicator. + * So PSNR computes the ratio of maximum/noise. Maximum being set to 2^bpp/channel + * This way, PSNR is not dependant anymore of image data type. + * + */ +static double PSNR(int x, int y, + unsigned char* buf1, int stride1, + unsigned char* buf2, int stride2) { - return 10*(log10(255*255)-log10( absdistq(x, y, buf1, stride1, buf2, stride2) )); + return 10*(log10(255*255)-log10( absdistq(x, y, buf1, stride1, buf2, stride2) )); } +/***************************************************************************** + * Usage message + *****************************************************************************/ + +static void usage() +{ + + fprintf(stderr, "Usage : xvid_stat [OPTIONS]\n"); + fprintf(stderr, "Options :\n"); + fprintf(stderr, " -w integer : frame width ([1.2048])\n"); + fprintf(stderr, " -h integer : frame height ([1.2048])\n"); + fprintf(stderr, " -b integer : target bitrate (>0 | default=900kbit)\n"); + fprintf(stderr, " -f float : target framerate (>0)\n"); + fprintf(stderr, " -i string : input filename (default=stdin)\n"); + fprintf(stderr, " -t integer : input data type (yuv=0, pgm=1)\n"); + fprintf(stderr, " -n integer : number of frames to encode\n"); + fprintf(stderr, " -q integer : quality ([0..5])\n"); + fprintf(stderr, " -d boolean : save decoder output (0 False*, !=0 True)\n"); + fprintf(stderr, " -m boolean : save mpeg4 raw stream (0 False*, !=0 True)\n"); + fprintf(stderr, " -h, -help : prints this help message\n"); + fprintf(stderr, " -quant integer : fixed quantizer (disables -b setting)\n"); + fprintf(stderr, " (* means default)\n"); -/*********************************************************************/ -/* input and output functions */ -/* */ -/* the are small and simple routines to read and write PGM and YUV */ -/* image. It's just for convenience, again nothing specific to XviD */ -/* */ -/*********************************************************************/ +} -int read_pgmheader(FILE* handle) +/***************************************************************************** + * Input and output functions + * + * the are small and simple routines to read and write PGM and YUV + * image. It's just for convenience, again nothing specific to XviD + * + *****************************************************************************/ + +static int read_pgmheader(FILE* handle) { int bytes,xsize,ysize,depth; char dummy[2]; @@ -208,56 +664,56 @@ return 2; } if ( (XDIM==0) || (YDIM==0) ) - { XDIM=xsize; + { + XDIM=xsize; YDIM=ysize; } return 0; } -int read_pgmdata(FILE* handle, unsigned char *image) +static int read_pgmdata(FILE* handle, unsigned char *image) { - int i,status; + int i; char dummy; - + unsigned char* buff1_ptr2 = image + XDIM*YDIM; unsigned char* buff1_ptr3 = image + XDIM*YDIM + XDIM/2*YDIM/2; - fread(image,XDIM*YDIM,1,stdin); // read Y component of picture + fread(image,XDIM*YDIM,1, handle); // read Y component of picture - for (i=0;i + xframe.colorspace = XVID_CSP_YV12; // defined in xframe.intra = -1; // let the codec decide between I-frame (1) and P-frame (0) @@ -351,381 +810,74 @@ xerr = xvid_encore(enc_handle, XVID_ENC_ENCODE, &xframe, &xstats); -/* enc_result->is_key_frame = xframe.intra; - enc_result->quantizer = xframe.quant; - enc_result->total_bits = xframe.length * 8; - enc_result->motion_bits = xstats.hlength * 8; - enc_result->texture_bits = enc_result->total_bits - enc_result->motion_bits; -*/ - -/* This is statictical data, e.g. for 2-pass. - If you are not interested in any of this, you can use NULL instead of &xstats -*/ + /* + * This is statictical data, e.g. for 2-pass. If you are not + * interested in any of this, you can use NULL instead of &xstats + */ *frametype = xframe.intra; *streamlength = xframe.length; return xerr; } +/***************************************************************************** + * Routines for decoding: init encoder, frame step, release encoder + ****************************************************************************/ -/*********************************************************************/ -/* Routines for decoding: init encoder, frame step, release encoder */ -/*********************************************************************/ - -int dec_init(int use_assembler) /* init decoder before first run */ +/* init decoder before first run */ +static int dec_init(int use_assembler) { - int xerr; + int xerr; - XVID_INIT_PARAM xinit; - XVID_DEC_PARAM xparam; + XVID_INIT_PARAM xinit; + XVID_DEC_PARAM xparam; - if(use_assembler) + if(use_assembler) #ifdef ARCH_IA64 - xinit.cpu_flags = XVID_CPU_FORCE | XVID_CPU_IA64; + xinit.cpu_flags = XVID_CPU_FORCE | XVID_CPU_IA64; #else - xinit.cpu_flags = 0; + xinit.cpu_flags = 0; #endif - else - xinit.cpu_flags = XVID_CPU_FORCE; + else + xinit.cpu_flags = XVID_CPU_FORCE; - xvid_init(NULL, 0, &xinit, NULL); - xparam.width = XDIM; - xparam.height = YDIM; + xvid_init(NULL, 0, &xinit, NULL); + xparam.width = XDIM; + xparam.height = YDIM; - xerr = xvid_decore(NULL, XVID_DEC_CREATE, &xparam, NULL); - dec_handle = xparam.handle; + xerr = xvid_decore(NULL, XVID_DEC_CREATE, &xparam, NULL); + dec_handle = xparam.handle; - return xerr; + return xerr; } -int dec_main(unsigned char *m4v_buffer, unsigned char *out_buffer, int m4v_size) -{ /* decode one frame */ - - int xerr; - XVID_DEC_FRAME xframe; +/* decode one frame */ +static int dec_main(unsigned char *m4v_buffer, unsigned char *out_buffer, + int m4v_size) +{ + int xerr; + XVID_DEC_FRAME xframe; - xframe.bitstream = m4v_buffer; - xframe.length = m4v_size; - xframe.image = out_buffer; - xframe.stride = XDIM; - xframe.colorspace = XVID_CSP_YV12; // XVID_CSP_USER is fastest (no memcopy involved) + xframe.bitstream = m4v_buffer; + xframe.length = m4v_size; + xframe.image = out_buffer; + xframe.stride = XDIM; + xframe.colorspace = XVID_CSP_YV12; // XVID_CSP_USER is fastest (no memcopy involved) - xerr = xvid_decore(dec_handle, XVID_DEC_DECODE, &xframe, NULL); + xerr = xvid_decore(dec_handle, XVID_DEC_DECODE, &xframe, NULL); - return xerr; + return xerr; } -int dec_stop() /* close decoder to release resources */ +/* close decoder to release resources */ +static int dec_stop() { - int xerr; - xerr = xvid_decore(dec_handle, XVID_DEC_DESTROY, NULL, NULL); + int xerr; + xerr = xvid_decore(dec_handle, XVID_DEC_DESTROY, NULL, NULL); - return xerr; + return xerr; } - -/*********************************************************************/ -/* Main program */ -/*********************************************************************/ - -int main(int argc, char *argv[]) -{ - unsigned char *divx_buffer = NULL; - unsigned char *in_buffer = NULL; - unsigned char *out_buffer = NULL; - - double enctime,dectime; - double totalenctime=0.; - double totaldectime=0.; - - long totalsize=0; - int status; - - int m4v_size; - int frame_type[ABS_MAXFRAMENR]; - int Iframes=0, Pframes=0, use_assembler=0; - double framepsnr[ABS_MAXFRAMENR]; - - double Ipsnr=0.,Imaxpsnr=0.,Iminpsnr=999.,Ivarpsnr=0.; - double Ppsnr=0.,Pmaxpsnr=0.,Pminpsnr=999.,Pvarpsnr=0.; - double Bpsnr=0.,Bmaxpsnr=0.,Bminpsnr=999.,Bvarpsnr=0.; - - char filename[256]; - - FILE *filehandle; - -/* read YUV in pgm format from stdin */ - if (!pgmflag) - { - pgmflag = 1; - - if (argc==2 && !strcmp(argv[1],"-asm")) - use_assembler = 1; - if (argc>=3) - { XDIM = atoi(argv[1]); - YDIM = atoi(argv[2]); - if ( (XDIM <= 0) || (XDIM >= 2048) || (YDIM <=0) || (YDIM >= 2048) ) - { fprintf(stderr,"Wrong frames size %d %d, trying PGM \n",XDIM, YDIM); - } - else - { - YDIM = YDIM*3/2; /* for YUV */ - pgmflag = 0; - } - } - } - - if (pgmflag) - { if (read_pgmheader(stdin)) - { - printf("Wrong input format, I want YUV encapsulated in PGM\n"); - return 1; - } - } - if (argc>=4) - { ARG_QUALITY = atoi(argv[3]); - if ( (ARG_QUALITY < 0) || (ARG_QUALITY > 6) ) - { fprintf(stderr,"Wrong Quality\n"); return -1; } - else - printf("Quality %d\n",ARG_QUALITY); - } - if (argc>=5) - { ARG_BITRATE = atoi(argv[4]); - if ( (ARG_BITRATE <= 0) ) - { fprintf(stderr,"Wrong Bitrate\n"); return -1; } - if ( (ARG_BITRATE <= 32) ) - { ARG_QUANTI = ARG_BITRATE; - ARG_BITRATE=0; - printf("Quantizer %d\n",ARG_QUANTI); - } - else - printf("Bitrate %d kbps\n",ARG_BITRATE); - } - if (argc>=6) - { ARG_FRAMERATE = (float)atof(argv[5]); - if ( (ARG_FRAMERATE <= 0) ) - { fprintf(stderr,"Wrong Fraterate %s \n",argv[5]); return -1; } - printf("Framerate %6.3f fps\n",ARG_FRAMERATE); - } - - if (argc>=7) - { ARG_MAXFRAMENR = atoi(argv[6]); - if ( (ARG_MAXFRAMENR <= 0) ) - { fprintf(stderr,"Wrong number of frames\n"); return -1; } - printf("max. Framenr. %d\n",ARG_MAXFRAMENR); - } - -/* now we know the sizes, so allocate memory */ - - in_buffer = (unsigned char *) malloc(XDIM*YDIM); - if (!in_buffer) - goto free_all_memory; // goto is one of the most underestimated instructions in C !!! - - divx_buffer = (unsigned char *) malloc(XDIM*YDIM*2); // this should really be enough memory! - if (!divx_buffer) - goto free_all_memory; - - YDIM = YDIM*2/3; // PGM is YUV 4:2:0 format, so real image height is *2/3 of PGM picture - - out_buffer = (unsigned char *) malloc(XDIM*YDIM*4); - if (!out_buffer) - goto free_all_memory; - - -/*********************************************************************/ -/* XviD PART Start */ -/*********************************************************************/ - - - status = enc_init(use_assembler); - if (status) - { - printf("Encore INIT problem, return value %d\n", status); - goto release_all; - } - - status = dec_init(use_assembler); - if (status) - { - printf("Decore INIT problem, return value %d\n", status); - goto release_all; - } - - -/*********************************************************************/ -/* Main loop */ -/*********************************************************************/ - - do - { - if (pgmflag) - status = read_pgmdata(stdin, in_buffer); // read PGM data (YUV-format) - else - status = read_yuvdata(stdin, in_buffer); // read raw data (YUV-format) - - if (status) - { - // Couldn't read image, most likely end-of-file - continue; - } - - - if (save_ref_flag) - { - sprintf(filename, "%s%05d.pgm", filepath, filenr); - write_pgm(filename,in_buffer); - } - - -/*********************************************************************/ -/* analyse this frame before encoding */ -/*********************************************************************/ - -// nothing is done here at the moment, but you could e.g. create -// histograms or measure entropy or apply preprocessing filters... - -/*********************************************************************/ -/* encode and decode this frame */ -/*********************************************************************/ - - enctime = -msecond(); - status = enc_main(in_buffer, divx_buffer, &m4v_size, &frame_type[filenr]); - enctime += msecond(); - - totalenctime += enctime; - totalsize += m4v_size; - - printf("Frame %5d: intra %d, enctime =%6.1f ms length=%7d bytes ", - filenr, frame_type[filenr], enctime*1000, m4v_size); - - if (save_m4v_flag) - { - sprintf(filename, "%sframe%05d.m4v", filepath, filenr); - filehandle = fopen(filename, "wb"); - fwrite(divx_buffer, m4v_size, 1, filehandle); - fclose(filehandle); - } - - dectime = -msecond(); - status = dec_main(divx_buffer, out_buffer, m4v_size); - dectime += msecond(); - - totaldectime += dectime; - - -/*********************************************************************/ -/* analyse the decoded frame and compare to original */ -/*********************************************************************/ - - framepsnr[filenr] = PSNR(XDIM,YDIM, in_buffer, XDIM, out_buffer, XDIM ); - - printf("dectime =%6.1f ms PSNR %5.2f\n",dectime*1000, framepsnr[filenr]); - - if (save_dec_flag) - { - sprintf(filename, "%sdec%05d.pgm", filepath, filenr); - write_pgm(filename,out_buffer); - } - - if (pgmflag) - status = read_pgmheader(stdin); // because if this was the last PGM, stop now - - filenr++; - - } while ( (!status) && (filenr Pmaxpsnr) - Pmaxpsnr = framepsnr[i]; - if (framepsnr[i] < Pminpsnr) - Pminpsnr = framepsnr[i]; - Pvarpsnr += (framepsnr[i] - Ppsnr)*(framepsnr[i] - Ppsnr) /Pframes; - break; - case 1: - if (framepsnr[i] > Imaxpsnr) - Imaxpsnr = framepsnr[i]; - if (framepsnr[i] < Pminpsnr) - Iminpsnr = framepsnr[i]; - Ivarpsnr += (framepsnr[i] - Ipsnr)*(framepsnr[i] - Ipsnr) /Iframes; - default: - break; - } - } - - printf("Avg. Q%1d %2s ",ARG_QUALITY, (ARG_QUANTI ? " q" : "br")); - printf("%04d ",MAX(ARG_QUANTI,ARG_BITRATE)); - printf("( %.2f bpp) ", (double)ARG_BITRATE*1000/XDIM/YDIM/ARG_FRAMERATE); - printf("size %6d ",totalsize); - printf("( %4d kbps ",(int)(totalsize*8*ARG_FRAMERATE/1000)); - printf("/ %.2f bpp) ",(double)totalsize*8/XDIM/YDIM); - printf("enc: %6.1f fps, dec: %6.1f fps \n",1/totalenctime, 1/totaldectime); - printf("PSNR P(%d): %5.2f ( %5.2f , %5.2f ; %5.4f ) ",Pframes,Ppsnr,Pminpsnr,Pmaxpsnr,sqrt(Pvarpsnr/filenr)); - printf("I(%d): %5.2f ( %5.2f , %5.2f ; %5.4f ) ",Iframes,Ipsnr,Iminpsnr,Imaxpsnr,sqrt(Ivarpsnr/filenr)); - printf("\n"); - -/*********************************************************************/ -/* XviD PART Stop */ -/*********************************************************************/ - -release_all: - - if (enc_handle) - { - status = enc_stop(); - if (status) - printf("Encore RELEASE problem return value %d\n", status); - } - - if (dec_handle) - { - status = dec_stop(); - if (status) - printf("Decore RELEASE problem return value %d\n", status); - } - - -free_all_memory: - free(out_buffer); - free(divx_buffer); - free(in_buffer); - - return 0; -} +/* EOF */