--- trunk/xvidcore/examples/xvid_decraw.c 2002/08/17 20:03:36 376 +++ trunk/xvidcore/examples/xvid_decraw.c 2002/09/27 18:33:13 547 @@ -1,131 +1,497 @@ -/************************************************************************** +/***************************************************************************** * - * XVID MPEG-4 VIDEO CODEC - Example for encoding and decoding + * XVID MPEG-4 VIDEO CODEC + * - Console based decoding test application - * - * 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 - * (at your option) any later version. + * Copyright(C) 2002 Christoph Lampert * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * 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 + * (at your option) any later version. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - *************************************************************************/ + * You should have received a copy of the GNU General Public License + * 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_decraw.c,v 1.2 2002-09-27 18:33:13 edgomez Exp $ + * + ****************************************************************************/ -/************************************************************************ +/***************************************************************************** * - * Test routine for XviD decoding - * (C) Christoph Lampert, 2002/08/17 + * Application notes : * - * An MPEG-4 bitstream is read from stdin and decoded, - * the speed for this is measured + * An MPEG-4 bitstream is read from an input file (or stdin) and decoded, + * the speed for this is measured. * * The program is plain C and needs no libraries except for libxvidcore, * and maths-lib, so with UN*X you simply compile by - * + * * gcc xvid_decraw.c -lxvidcore -lm -o xvid_decraw * * You have to specify the image dimensions (until the add the feature * to read this from the bitstream) + * + * Usage : xvid_decraw <-w width> <-h height> [OPTIONS] + * Options : + * -asm : use assembly optimizations (default=disabled) + * -w integer : frame width ([1.2048]) + * -h integer : frame height ([1.2048]) + * -i string : input filename (default=stdin) + * -t integer : input data type (raw=0, mp4u=1) + * -d boolean : save decoder output (0 False*, !=0 True) + * -m boolean : save mpeg4 raw stream to single files (0 False*, !=0 True) + * -help : This help message + * (* means default) * - * Parameters are: xvid_stat XDIM YDIM - * - * output and indivual m4v-files are saved, if corresponding flags are set - * - ************************************************************************/ + ****************************************************************************/ #include #include -#include // needed for log10 -#include // only needed for gettimeofday +#include +#include +#ifndef _MSC_VER +#include +#else +#include +#endif -#include "../src/xvid.h" /* comes with XviD */ +#include "xvid.h" -#define ABS_MAXFRAMENR 9999 // max number of frames +/***************************************************************************** + * Global vars in module and constants + ****************************************************************************/ + +/* max number of frames */ +#define ABS_MAXFRAMENR 9999 + +static int XDIM = 0; +static int YDIM = 0; +static int ARG_SAVEDECOUTPUT = 0; +static int ARG_SAVEMPEGSTREAM = 0; +static int ARG_STREAMTYPE = 0; +static char *ARG_INPUTFILE = NULL; + + +static char filepath[256] = "./"; +static void *dec_handle = NULL; + +# define BUFFER_SIZE 10*XDIM*YDIM + +#define LONG_PACK(a,b,c,d) ((long) (((long)(a))<<24) | (((long)(b))<<16) | \ + (((long)(c))<<8) |((long)(d))) + +#define SWAP(a) ( (((a)&0x000000ff)<<24) | (((a)&0x0000ff00)<<8) | \ + (((a)&0x00ff0000)>>8) | (((a)&0xff000000)>>24) ) + +/***************************************************************************** + * Local prototypes + ****************************************************************************/ + +static double msecond(); +static int write_pgm(char *filename, + unsigned char *image); +static int dec_init(int use_assembler); +static int dec_main(unsigned char *istream, + unsigned char *ostream, + int istream_size, + int *ostream_size); +static int dec_stop(); +static void usage(); + +/***************************************************************************** + * Main program + ****************************************************************************/ -int XDIM=720; -int YDIM=576; -int i,filenr = 0; +int main(int argc, char *argv[]) +{ + unsigned char *mp4_buffer = NULL; + unsigned char *mp4_ptr = NULL; + unsigned char *out_buffer = NULL; + int bigendian = 0; -int save_dec_flag = 1; // save decompressed bytestream? -int save_m4v_flag = 0; // save bytestream itself? + double totaldectime; + + long totalsize; + int status; + + int use_assembler = 0; + + char filename[256]; + + FILE *in_file; + int filenr; + int i; + + printf("xvid_decraw - raw mpeg4 bitstream decoder "); + 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("-d", argv[i]) == 0 && i < argc - 1 ) { + i++; + ARG_SAVEDECOUTPUT = atoi(argv[i]); + } + else if (strcmp("-i", argv[i]) == 0 && i < argc - 1 ) { + i++; + ARG_INPUTFILE = argv[i]; + } + else if (strcmp("-m", argv[i]) == 0 && i < argc - 1 ) { + i++; + ARG_SAVEMPEGSTREAM = atoi(argv[i]); + } + else if (strcmp("-t", argv[i]) == 0 && i < argc - 1 ) { + i++; + ARG_STREAMTYPE = atoi(argv[i]); + } + else if (strcmp("-help", argv[i])) { + usage(); + return(0); + } + else { + usage(); + exit(-1); + } -char filepath[256] = "./"; // the path where to save output + } + +/***************************************************************************** + * Values checking + ****************************************************************************/ + + if(XDIM <= 0 || XDIM > 2048 || YDIM <= 0 || YDIM > 2048) { + usage(); + return -1; + } -void *dec_handle = NULL; // handle for decoding + if ( ARG_INPUTFILE == NULL || strcmp(ARG_INPUTFILE, "stdin") == 0) { + in_file = stdin; + } + else { -/*********************************************************************/ -/* "statistical" functions */ -/* */ -/* these are not needed for decoding itself, but for measuring */ -/* time (and maybe later quality), there in nothing specific to */ -/* XviD in these */ -/* */ -/*********************************************************************/ + in_file = fopen(ARG_INPUTFILE, "rb"); + if (in_file == NULL) { + fprintf(stderr, "Error opening input file %s\n", ARG_INPUTFILE); + return -1; + } + } -double msecond() -/* return the current time in seconds(!) */ -{ - struct timeval tv; - gettimeofday(&tv, 0); - return tv.tv_sec + tv.tv_usec * 1.0e-6; -} +/***************************************************************************** + * Memory allocation + ****************************************************************************/ + + /* Memory for encoded mp4 stream */ + mp4_buffer = (unsigned char *) malloc(BUFFER_SIZE); + mp4_ptr = mp4_buffer; + if (!mp4_buffer) + goto free_all_memory; + + /* Memory for frame output */ + out_buffer = (unsigned char *) malloc(XDIM*YDIM*4); + if (!out_buffer) + goto free_all_memory; -/*********************************************************************/ -/* input and output functions */ -/* */ -/* the are small and simple routines for writing image */ -/* image. It's just for convenience, again nothing specific to XviD */ -/* */ -/*********************************************************************/ +/***************************************************************************** + * XviD PART Start + ****************************************************************************/ -int write_pgm(char *filename, unsigned char *image) -{ - FILE *filehandle; - filehandle=fopen(filename,"wb"); - if (filehandle) - { - fprintf(filehandle,"P5\n\n"); // - fprintf(filehandle,"%d %d 255\n",XDIM,YDIM*3/2); - fwrite(image,XDIM,YDIM*3/2,filehandle); + status = dec_init(use_assembler); + if (status) { + fprintf(stderr, + "Decore INIT problem, return value %d\n", status); + goto release_all; + } + + +/***************************************************************************** + * Main loop + ****************************************************************************/ + + if(ARG_STREAMTYPE) { + + unsigned char header[4]; + + /* MP4U format : read header */ + if(feof(in_file)) + goto release_all; + fread(header, 4, 1, in_file); + + if(header[0] != '2' || header[1] != 'M' || + header[2] != 'O' || header[3] != 'G') { + fprintf(stderr, "Error, this not a mp4u container file\n"); + goto release_all; + } - fclose(filehandle); - return 0; } + + totalsize = LONG_PACK('M','P','4','U'); + mp4_ptr = (unsigned char *)&totalsize; + if(*mp4_ptr == 'M') + bigendian = 1; else - return 1; + bigendian = 0; + + totaldectime = 0; + totalsize = 0; + filenr = 0; + mp4_ptr = mp4_buffer; + + do { + + int mp4_size = (mp4_buffer + BUFFER_SIZE - mp4_ptr); + int used_bytes = 0; + double dectime; + + /* Read data from input file */ + if(ARG_STREAMTYPE) { + + /* MP4U container */ + + /* Read stream size first */ + if(feof(in_file)) + break; + fread(&mp4_size, sizeof(long), 1, in_file); + + if(bigendian) + mp4_size = SWAP(mp4_size); + + /* Read mp4_size_bytes */ + if(feof(in_file)) + break; + fread(mp4_buffer, mp4_size, 1, in_file); + + /* + * When reading mp4u, we don't have to care about buffer + * filling as we know exactly how much bytes there are in + * next frame + */ + mp4_ptr = mp4_buffer; + + } + else { + + /* Real raw stream */ + + /* buffer more than half empty -> Fill it */ + if (mp4_ptr > mp4_buffer + BUFFER_SIZE/2) { + int rest = (mp4_buffer + BUFFER_SIZE - mp4_ptr); + + /* Move data if needed */ + if (rest) + memcpy(mp4_buffer, mp4_ptr, rest); + + /* Update mp4_ptr */ + mp4_ptr = mp4_buffer; + + /* read new data */ + if(feof(in_file)) + break; + fread(mp4_buffer + rest, BUFFER_SIZE - rest, 1, in_file); + } + + } + + /* Decode frame */ + dectime = msecond(); + status = dec_main(mp4_ptr, out_buffer, mp4_size, &used_bytes); + dectime = msecond() - dectime; + + if (status) { + break; + } + + /* + * Only needed for real raw stream, mp4u uses + * mp4_ptr = mp4_buffer for each frame + */ + mp4_ptr += used_bytes; + + /* Updated data */ + totalsize += used_bytes; + totaldectime += dectime; + + /* Prints some decoding stats */ + printf("Frame %5d: dectime =%6.1f ms length=%7d bytes \n", + filenr, dectime, used_bytes); + + /* Save individual mpeg4 strean if required */ + if (ARG_SAVEMPEGSTREAM) { + FILE *filehandle = NULL; + + sprintf(filename, "%sframe%05d.m4v", filepath, filenr); + filehandle = fopen(filename, "wb"); + if(!filehandle) { + fprintf(stderr, + "Error writing single mpeg4 stream to file %s\n", + filename); + } + else { + fwrite(mp4_buffer, used_bytes, 1, filehandle); + fclose(filehandle); + } + } + + + /* Save output frame if required */ + if (ARG_SAVEDECOUTPUT) { + sprintf(filename, "%sdec%05d.pgm", filepath, filenr); + if(write_pgm(filename,out_buffer)) { + fprintf(stderr, + "Error writing decoded PGM frame %s\n", + filename); + } + } + + filenr++; + + } while ( (status>=0) && (filenr <-h height> [OPTIONS]\n"); + fprintf(stderr, "Options :\n"); + fprintf(stderr, " -asm : use assembly optimizations (default=disabled)\n"); + fprintf(stderr, " -w integer : frame width ([1.2048])\n"); + fprintf(stderr, " -h integer : frame height ([1.2048])\n"); + fprintf(stderr, " -i string : input filename (default=stdin)\n"); + fprintf(stderr, " -t integer : input data type (raw=0, mp4u=1)\n"); + fprintf(stderr, " -d boolean : save decoder output (0 False*, !=0 True)\n"); + fprintf(stderr, " -m boolean : save mpeg4 raw stream to individual files (0 False*, !=0 True)\n"); + fprintf(stderr, " -help : This help message\n"); + fprintf(stderr, " (* means default)\n"); + +} + +/***************************************************************************** + * "helper" functions + ****************************************************************************/ + +/* return the current time in milli seconds */ +static double +msecond() +{ +#ifndef _MSC_VER + struct timeval tv; + gettimeofday(&tv, 0); + return tv.tv_sec*10e3 + tv.tv_usec * 1.0e-3; +#else + clock_t clk; + clk = clock(); + return clk * 1000 / CLOCKS_PER_SEC; +#endif +} + + +/***************************************************************************** + * output functions + ****************************************************************************/ + +static int +write_pgm(char *filename, + unsigned char *image) +{ + int loop; + + unsigned char *y = image; + unsigned char *u = image + XDIM*YDIM; + unsigned char *v = image + XDIM*YDIM + XDIM/2*YDIM/2; + FILE *filehandle; - filehandle=fopen(filename,"wb"); - if (filehandle) - { - fprintf(filehandle,"P6\n\n"); // - fprintf(filehandle,"%d %d 255\n",XDIM,YDIM); - fwrite(image,XDIM,YDIM*3,filehandle); + filehandle=fopen(filename,"w+b"); + if (filehandle) { + + /* Write header */ + fprintf(filehandle,"P5\n\n%d %d 255\n", XDIM,YDIM*3/2); + /* Write Y data */ + fwrite(y, 1, XDIM*YDIM, filehandle); + + for(loop=0; loop=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); - } - } - if (argc>=4 && !strcmp(argv[3],"noasm")) - use_assembler = 0; - - -/* allocate memory */ - - divx_buffer = (unsigned char *) malloc(10*XDIM*YDIM); - // this should really be enough memory! - if (!divx_buffer) - goto free_all_memory; - divx_ptr = divx_buffer+10*XDIM*YDIM; - - out_buffer = (unsigned char *) malloc(4*XDIM*YDIM); /* YUV needs less */ - if (!out_buffer) - goto free_all_memory; - - -/*********************************************************************/ -/* XviD PART Start */ -/*********************************************************************/ - - status = dec_init(use_assembler); - if (status) - { - printf("Decore INIT problem, return value %d\n", status); - goto release_all; - } - - -/*********************************************************************/ -/* Main loop */ -/*********************************************************************/ - - do - { - - if (divx_ptr > divx_buffer+5*XDIM*YDIM) /* buffer more than half empty */ - { int rest=(divx_buffer+10*XDIM*YDIM-divx_ptr); - if (rest) - memcpy(divx_buffer, divx_ptr, rest); - divx_ptr = divx_buffer; - fread(divx_buffer+rest, 1, 5*XDIM*YDIM, stdin); /* read new data */ - } - - dectime = -msecond(); - status = dec_main(divx_ptr, out_buffer, &m4v_size); - - if (status) - { - break; - } - dectime += msecond(); - divx_ptr += m4v_size; - - totalsize += m4v_size; - - printf("Frame %5d: dectime =%6.1f ms length=%7d bytes \n", - filenr, dectime*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); - } - totaldectime += dectime; - - -/*********************************************************************/ -/* analyse the decoded frame and compare to original */ -/*********************************************************************/ - - if (save_dec_flag) - { - sprintf(filename, "%sdec%05d.pgm", filepath, filenr); - write_pgm(filename,out_buffer); - } - - filenr++; - - } while ( (status>=0) && (filenr