--- trunk/xvidcore/examples/xvid_decraw.c 2003/02/16 05:11:39 860 +++ trunk/xvidcore/examples/xvid_decraw.c 2004/04/15 19:44:06 1432 @@ -4,6 +4,7 @@ * - Console based decoding test application - * * Copyright(C) 2002-2003 Christoph Lampert + * 2002-2003 Edouard Gomez * * 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 @@ -19,7 +20,7 @@ * 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.7 2003-02-16 05:11:39 suxen_drol Exp $ + * $Id: xvid_decraw.c,v 1.14 2004-04-15 19:44:05 edgomez Exp $ * ****************************************************************************/ @@ -29,26 +30,11 @@ * * 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) + * The program is plain C and needs no libraries except for libxvidcore, + * and maths-lib. + * + * Use ./xvid_decraw -help for a list of options * ****************************************************************************/ @@ -71,17 +57,22 @@ /* max number of frames */ #define ABS_MAXFRAMENR 9999 +#define USE_PNM 0 +#define USE_TGA 1 + static int XDIM = 0; static int YDIM = 0; static int ARG_SAVEDECOUTPUT = 0; static int ARG_SAVEMPEGSTREAM = 0; static char *ARG_INPUTFILE = NULL; - +static int CSP = XVID_CSP_I420; +static int BPP = 1; +static int FORMAT = USE_PNM; static char filepath[256] = "./"; static void *dec_handle = NULL; -# define BUFFER_SIZE 10*XDIM*YDIM +#define BUFFER_SIZE (2*1024*1024) /***************************************************************************** * Local prototypes @@ -89,15 +80,28 @@ static double msecond(); static int write_pgm(char *filename, - unsigned char *image); -static int dec_init(int use_assembler); + unsigned char *image); +static int dec_init(int use_assembler, int debug_level); static int dec_main(unsigned char *istream, unsigned char *ostream, int istream_size, - int *ostream_size, - int *isframe); + xvid_dec_stats_t *xvid_dec_stats); static int dec_stop(); static void usage(); +int write_image(char *prefix, unsigned char *image); +int write_pnm(char *filename, unsigned char *image); +int write_tga(char *filename, unsigned char *image); + +const char * type2str(int type) +{ + if (type==XVID_TYPE_IVOP) + return "I"; + if (type==XVID_TYPE_PVOP) + return "P"; + if (type==XVID_TYPE_BVOP) + return "B"; + return "S"; +} /***************************************************************************** * Main program @@ -108,9 +112,8 @@ unsigned char *mp4_buffer = NULL; unsigned char *mp4_ptr = NULL; unsigned char *out_buffer = NULL; - int bigendian = 0; - int still_left_in_buffer; - int delayed_frames; + int useful_bytes; + xvid_dec_stats_t xvid_dec_stats; double totaldectime; @@ -118,6 +121,7 @@ int status; int use_assembler = 0; + int debug_level = 0; char filename[256]; @@ -136,47 +140,62 @@ if (strcmp("-asm", argv[i]) == 0 ) { use_assembler = 1; - } - else if (strcmp("-w", argv[i]) == 0 && i < argc - 1 ) { + } else if (strcmp("-debug", 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 ) { + if (sscanf(argv[i], "0x%x", &debug_level) != 1) { + debug_level = atoi(argv[i]); + } + } else if (strcmp("-d", argv[i]) == 0) { + ARG_SAVEDECOUTPUT = 1; + } 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 ) { + } else if (strcmp("-m", argv[i]) == 0) { + ARG_SAVEMPEGSTREAM = 1; + } else if (strcmp("-c", argv[i]) == 0 && i < argc - 1 ) { i++; - ARG_SAVEMPEGSTREAM = atoi(argv[i]); - } - else if (strcmp("-help", argv[i])) { + if (strcmp(argv[i], "rgb16") == 0) { + CSP = XVID_CSP_RGB555; + BPP = 2; + } else if (strcmp(argv[i], "rgb24") == 0) { + CSP = XVID_CSP_BGR; + BPP = 3; + } else if (strcmp(argv[i], "rgb32") == 0) { + CSP = XVID_CSP_BGRA; + BPP = 4; + } else if (strcmp(argv[i], "yv12") == 0) { + CSP = XVID_CSP_YV12; + BPP = 1; + } else { + CSP = XVID_CSP_I420; + BPP = 1; + } + } else if (strcmp("-f", argv[i]) == 0 && i < argc -1) { + i++; + if (strcmp(argv[i], "tga") == 0) { + FORMAT = USE_TGA; + } else { + FORMAT = USE_PNM; + } + } else if (strcmp("-help", argv[i]) == 0) { usage(); return(0); - } - else { + } else { usage(); exit(-1); } - } +#if defined(_MSC_VER) + if (ARG_INPUTFILE==NULL) { + fprintf(stderr, "Warning: MSVC build does not read EOF correctly from stdin. Use the -i switch.\n\n"); + } +#endif + /***************************************************************************** * Values checking ****************************************************************************/ - if(XDIM <= 0 || XDIM > 2048 || YDIM <= 0 || YDIM > 2048) { - usage(); - return -1; - } - if ( ARG_INPUTFILE == NULL || strcmp(ARG_INPUTFILE, "stdin") == 0) { in_file = stdin; } @@ -185,10 +204,15 @@ in_file = fopen(ARG_INPUTFILE, "rb"); if (in_file == NULL) { fprintf(stderr, "Error opening input file %s\n", ARG_INPUTFILE); - return -1; + return(-1); } } + /* PNM/PGM format can't handle 16/32 bit data */ + if (BPP != 1 && BPP != 3 && FORMAT == USE_PNM) { + FORMAT = USE_TGA; + } + /***************************************************************************** * Memory allocation ****************************************************************************/ @@ -199,20 +223,14 @@ 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; - - /***************************************************************************** * XviD PART Start ****************************************************************************/ - status = dec_init(use_assembler); + status = dec_init(use_assembler, debug_level); if (status) { fprintf(stderr, - "Decore INIT problem, return value %d\n", status); + "Decore INIT problem, return value %d\n", status); goto release_all; } @@ -222,89 +240,97 @@ ****************************************************************************/ /* Fill the buffer */ - still_left_in_buffer = fread(mp4_buffer, 1, BUFFER_SIZE, in_file); + useful_bytes = fread(mp4_buffer, 1, BUFFER_SIZE, in_file); totaldectime = 0; totalsize = 0; filenr = 0; - delayed_frames = 0; mp4_ptr = mp4_buffer; do { - - int mp4_size = (mp4_buffer + BUFFER_SIZE - mp4_ptr); int used_bytes = 0; double dectime; - int notification; /* * If the buffer is half empty or there are no more bytes in it * then fill it. */ - if (mp4_ptr > mp4_buffer + BUFFER_SIZE/2 || - still_left_in_buffer <= 0) { - int rest = (mp4_buffer + BUFFER_SIZE - mp4_ptr); + if (mp4_ptr > mp4_buffer + BUFFER_SIZE/2) { + int already_in_buffer = (mp4_buffer + BUFFER_SIZE - mp4_ptr); /* Move data if needed */ - if (rest) - memcpy(mp4_buffer, mp4_ptr, rest); + if (already_in_buffer > 0) + memcpy(mp4_buffer, mp4_ptr, already_in_buffer); /* Update mp4_ptr */ mp4_ptr = mp4_buffer; /* read new data */ - if(feof(in_file)) + if(feof(in_file)) break; - still_left_in_buffer = fread(mp4_buffer + rest, - 1, - BUFFER_SIZE - rest, - in_file); + useful_bytes += fread(mp4_buffer + already_in_buffer, + 1, BUFFER_SIZE - already_in_buffer, + in_file); } - /* This loop flushes N_VOPS (with vop_coded bit set to 0) */ + /* This loop is needed to handle VOL/NVOP reading */ do { /* Decode frame */ dectime = msecond(); - status = dec_main(mp4_ptr, out_buffer, mp4_size, &used_bytes, ¬ification); + used_bytes = dec_main(mp4_ptr, out_buffer, useful_bytes, &xvid_dec_stats); dectime = msecond() - dectime; - if (status) { - break; + /* Resize image buffer if needed */ + if(xvid_dec_stats.type == XVID_TYPE_VOL) { + + /* Check if old buffer is smaller */ + if(XDIM*YDIM < xvid_dec_stats.data.vol.width*xvid_dec_stats.data.vol.height) { + + /* Copy new witdh and new height from the vol structure */ + XDIM = xvid_dec_stats.data.vol.width; + YDIM = xvid_dec_stats.data.vol.height; + + /* Free old output buffer*/ + if(out_buffer) free(out_buffer); + + /* Allocate the new buffer */ + out_buffer = (unsigned char*)malloc(XDIM*YDIM*4); + if(out_buffer == NULL) + goto free_all_memory; + + fprintf(stderr, "Resized frame buffer to %dx%d\n", XDIM, YDIM); + } } /* Update buffer pointers */ - mp4_ptr += used_bytes; - still_left_in_buffer -= used_bytes; + if(used_bytes > 0) { + mp4_ptr += used_bytes; + useful_bytes -= used_bytes; - /* Total size */ - totalsize += used_bytes; + /* Total size */ + totalsize += used_bytes; + } - }while(used_bytes <= 7 && still_left_in_buffer > 0); /* <= 7 bytes is a NVOPS */ + }while(xvid_dec_stats.type <= 0 && useful_bytes > 0); - /* Negative buffer would mean we went too far */ - if(still_left_in_buffer < 0) break; + /* Check if there is a negative number of useful bytes left in buffer + * This means we went too far */ + if(useful_bytes < 0) + break; - /* Skip when decoder is buffering images or decoding VOL information */ - if(notification != XVID_DEC_VOP) { - /* It's a delay only if it notifies NOTHING */ - if(notification == XVID_DEC_NOTHING) - delayed_frames++; - continue; - } - - /* Updated data - Count only usefull decode time */ + /* Updated data - Count only usefull decode time */ totaldectime += dectime; - /* Prints some decoding stats */ - printf("Frame %5d: dectime(ms) =%6.1f, length(bytes) =%7d\n", - filenr, dectime, used_bytes); + + printf("Frame %5d: type = %s, dectime(ms) =%6.1f, length(bytes) =%7d\n", + filenr, type2str(xvid_dec_stats.type), dectime, used_bytes); /* Save individual mpeg4 stream if required */ - if (ARG_SAVEMPEGSTREAM) { + if(ARG_SAVEMPEGSTREAM) { FILE *filehandle = NULL; sprintf(filename, "%sframe%05d.m4v", filepath, filenr); @@ -315,15 +341,15 @@ filename); } else { - fwrite(mp4_buffer, 1, used_bytes, filehandle); + fwrite(mp4_ptr-used_bytes, 1, used_bytes, filehandle); fclose(filehandle); } } /* Save output frame if required */ if (ARG_SAVEDECOUTPUT) { - sprintf(filename, "%sdec%05d.pgm", filepath, filenr); - if(write_pgm(filename,out_buffer)) { + sprintf(filename, "%sdec%05d", filepath, filenr); + if(write_image(filename, out_buffer)) { fprintf(stderr, "Error writing decoded PGM frame %s\n", filename); @@ -337,51 +363,56 @@ /***************************************************************************** * Flush decoder buffers ****************************************************************************/ - while(delayed_frames--) { + + do { /* Fake vars */ - int used_bytes, isframe; + int used_bytes; double dectime; - /* Decode frame */ - dectime = msecond(); - status = dec_main(NULL, out_buffer, -1, &used_bytes, &isframe); - dectime = msecond() - dectime; - - if (status) { - break; - } + do { + dectime = msecond(); + used_bytes = dec_main(NULL, out_buffer, -1, &xvid_dec_stats); + dectime = msecond() - dectime; + }while(used_bytes>=0 && xvid_dec_stats.type <= 0); + + if (used_bytes < 0) { /* XVID_ERR_END */ + break; + } /* Updated data - Count only usefull decode time */ totaldectime += dectime; /* Prints some decoding stats */ - printf("Frame %5d: dectime(ms) =%6.1f, length(bytes) =%7d\n", - filenr, dectime, used_bytes); + printf("Frame %5d: type = %s, dectime(ms) =%6.1f, length(bytes) =%7d\n", + filenr, type2str(xvid_dec_stats.type), dectime, used_bytes); /* Save output frame if required */ if (ARG_SAVEDECOUTPUT) { - sprintf(filename, "%sdec%05d.pgm", filepath, filenr); - if(write_pgm(filename,out_buffer)) { + sprintf(filename, "%sdec%05d", filepath, filenr); + if(write_image(filename, out_buffer)) { fprintf(stderr, - "Error writing decoded PGM frame %s\n", + "Error writing decoded frame %s\n", filename); } } filenr++; - } + }while(1); /***************************************************************************** * Calculate totals and averages for output, print results ****************************************************************************/ - totalsize /= filenr; - totaldectime /= filenr; - - printf("Avg: dectime(ms) =%7.2f, fps =%7.2f, length(bytes) =%7d\n", - totaldectime, 1000/totaldectime, (int)totalsize); + if (filenr>0) { + totalsize /= filenr; + totaldectime /= filenr; + printf("Avg: dectime(ms) =%7.2f, fps =%7.2f, length(bytes) =%7d\n", + totaldectime, 1000/totaldectime, (int)totalsize); + }else{ + printf("Nothing was decoded!\n"); + } /***************************************************************************** * XviD PART Stop @@ -398,7 +429,7 @@ free(out_buffer); free(mp4_buffer); - return 0; + return(0); } /***************************************************************************** @@ -408,15 +439,15 @@ static void usage() { - fprintf(stderr, "Usage : xvid_decraw <-w width> <-h height> [OPTIONS]\n"); + fprintf(stderr, "Usage : xvid_decraw [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, " -debug : debug level (debug=0)\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, " -d : save decoder output\n"); + fprintf(stderr, " -c csp : choose colorspace output (rgb16, rgb24, rgb32, yv12, i420)\n"); + fprintf(stderr, " -f format : choose output file format (tga, pnm, pgm)\n"); + fprintf(stderr, " -m : save mpeg4 raw stream to individual files\n"); fprintf(stderr, " -help : This help message\n"); fprintf(stderr, " (* means default)\n"); @@ -433,11 +464,11 @@ #ifndef WIN32 struct timeval tv; gettimeofday(&tv, 0); - return (double)tv.tv_sec*1.0e3 + (double)tv.tv_usec*1.0e-3; + return((double)tv.tv_sec*1.0e3 + (double)tv.tv_usec*1.0e-3); #else clock_t clk; clk = clock(); - return clk * 1000 / CLOCKS_PER_SEC; + return(clk * 1000 / CLOCKS_PER_SEC); #endif } @@ -445,80 +476,207 @@ * output functions ****************************************************************************/ -static int -write_pgm(char *filename, - unsigned char *image) +int write_image(char *prefix, unsigned char *image) { - int loop; + char filename[1024]; + char *ext; + int ret; + + if (FORMAT == USE_PNM && BPP == 1) { + ext = "pgm"; + } else if (FORMAT == USE_PNM && BPP == 3) { + ext = "pnm"; + } else if (FORMAT == USE_TGA) { + ext = "tga"; + } else { + fprintf(stderr, "Bug: should not reach this path code -- please report to xvid-devel@xvid.org with command line options used"); + exit(-1); + } - unsigned char *y = image; - unsigned char *u = image + XDIM*YDIM; - unsigned char *v = image + XDIM*YDIM + XDIM/2*YDIM/2; + sprintf(filename, "%s.%s", prefix, ext); - FILE *filehandle; - filehandle=fopen(filename,"w+b"); - if (filehandle) { + if (FORMAT == USE_PNM) { + ret = write_pnm(filename, image); + } else { + ret = write_tga(filename, image); + } - /* Write header */ - fprintf(filehandle,"P5\n\n%d %d 255\n", XDIM,YDIM*3/2); + return(ret); +} - /* Write Y data */ - fwrite(y, 1, XDIM*YDIM, filehandle); +int write_tga(char *filename, unsigned char *image) +{ + FILE * f; + char hdr[18]; - for(loop=0; loop1)?2:3; /* Uncompressed true color (2) or greymap (3) */ + hdr[3] = 0; /* Color map specification (not used) */ + hdr[4] = 0; /* Color map specification (not used) */ + hdr[5] = 0; /* Color map specification (not used) */ + hdr[6] = 0; /* Color map specification (not used) */ + hdr[7] = 0; /* Color map specification (not used) */ + hdr[8] = 0; /* LSB X origin */ + hdr[9] = 0; /* MSB X origin */ + hdr[10] = 0; /* LSB Y origin */ + hdr[11] = 0; /* MSB Y origin */ + hdr[12] = (XDIM>>0)&0xff; /* LSB Width */ + hdr[13] = (XDIM>>8)&0xff; /* MSB Width */ + if (BPP > 1) { + hdr[14] = (YDIM>>0)&0xff; /* LSB Height */ + hdr[15] = (YDIM>>8)&0xff; /* MSB Height */ + } else { + hdr[14] = ((YDIM*3)>>1)&0xff; /* LSB Height */ + hdr[15] = ((YDIM*3)>>9)&0xff; /* MSB Height */ + } + hdr[16] = BPP*8; + hdr[17] = 0x00 | (1<<5) /* Up to down */ | (0<<4); /* Image descriptor */ + + /* Write header */ + fwrite(hdr, 1, sizeof(hdr), f); - /* Update pointers */ - u += XDIM/2; - v += XDIM/2; +#ifdef ARCH_IS_LITTLE_ENDIAN + /* write first plane */ + fwrite(image, 1, XDIM*YDIM*BPP, f); +#else + { + int i; + for (i=0; iversion = XVID_VERSION; - xframe.general = 0; - xframe.bitstream = istream; - xframe.length = istream_size; - xframe.image = ostream; - xframe.stride = XDIM; - xframe.colorspace = XVID_CSP_YV12; + /* No general flags to set */ + xvid_dec_frame.general = 0; - xerr = xvid_decore(dec_handle, XVID_DEC_DECODE, &xframe, &xstats); + /* Input stream */ + xvid_dec_frame.bitstream = istream; + xvid_dec_frame.length = istream_size; - *ostream_size = xframe.length; + /* Output frame structure */ + xvid_dec_frame.output.plane[0] = ostream; + xvid_dec_frame.output.stride[0] = XDIM*BPP; + xvid_dec_frame.output.csp = CSP; - *notification = xstats.notify; + ret = xvid_decore(dec_handle, XVID_DEC_DECODE, &xvid_dec_frame, xvid_dec_stats); - return xerr; + return(ret); } /* close decoder to release resources */ static int dec_stop() { - int xerr; + int ret; - xerr = xvid_decore(dec_handle, XVID_DEC_DESTROY, NULL, NULL); + ret = xvid_decore(dec_handle, XVID_DEC_DESTROY, NULL, NULL); - return xerr; + return(ret); }