--- xvid_encraw.c 2003/08/10 13:10:09 1.11.2.35 +++ xvid_encraw.c 2005/10/07 15:02:28 1.22 @@ -21,7 +21,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_encraw.c,v 1.11.2.35 2003/08/10 13:10:09 Isibaar Exp $ + * $Id: xvid_encraw.c,v 1.22 2005/10/07 15:02:28 suxen_drol Exp $ * ****************************************************************************/ @@ -45,7 +45,10 @@ #ifndef WIN32 #include #else +#include +#include #include +#define XVID_AVI_INPUT #endif #include "xvid.h" @@ -141,6 +144,7 @@ static char *ARG_INPUTFILE = NULL; static int ARG_INPUTTYPE = 0; static int ARG_SAVEMPEGSTREAM = 0; +static int ARG_SAVEINDIVIDUAL = 0; static char *ARG_OUTPUTFILE = NULL; static int XDIM = 0; static int YDIM = 0; @@ -150,8 +154,16 @@ static int ARG_PACKED = 0; static int ARG_DEBUG = 0; static int ARG_VOPDEBUG = 0; +static int ARG_GREYSCALE = 0; +static int ARG_QTYPE = 0; +static int ARG_QMATRIX = 0; static int ARG_GMC = 0; +static int ARG_INTERLACING = 0; static int ARG_QPEL = 0; +static int ARG_TURBO = 0; +static int ARG_VHQMODE = 0; +static int ARG_BVHQ = 0; +static int ARG_CLOSED_GOP = 0; #ifndef READ_PNM #define IMAGE_SIZE(x,y) ((x)*(y)*3/2) @@ -177,6 +189,13 @@ /* Internal structures (handles) for encoding and decoding */ static void *enc_handle = NULL; +static unsigned char qmatrix_intra[64]; +static unsigned char qmatrix_inter[64]; + +#ifdef XVID_AVI_INPUT +static PAVISTREAM avi_stream = NULL; +#endif + /***************************************************************************** * Local prototypes ****************************************************************************/ @@ -235,7 +254,7 @@ int stats_type; int stats_quant; int stats_length; - int use_assembler = 0; + int use_assembler = 1; int input_num; int output_num; @@ -262,6 +281,8 @@ if (strcmp("-asm", argv[i]) == 0) { use_assembler = 1; + } else if (strcmp("-noasm", argv[i]) == 0) { + use_assembler = 0; } else if (strcmp("-w", argv[i]) == 0 && i < argc - 1) { i++; XDIM = atoi(argv[i]); @@ -308,6 +329,9 @@ } else if (strcmp("-quality", argv[i]) == 0 && i < argc - 1) { i++; ARG_QUALITY = atoi(argv[i]); + } else if (strcmp("-vhqmode", argv[i]) == 0 && i < argc - 1) { + i++; + ARG_VHQMODE = atoi(argv[i]); } else if (strcmp("-framerate", argv[i]) == 0 && i < argc - 1) { i++; ARG_FRAMERATE = (float) atof(argv[i]); @@ -326,23 +350,55 @@ } else if (strcmp("-type", argv[i]) == 0 && i < argc - 1) { i++; ARG_INPUTTYPE = atoi(argv[i]); - } else if (strcmp("-nframes", argv[i]) == 0 && i < argc - 1) { + } else if (strcmp("-frames", argv[i]) == 0 && i < argc - 1) { i++; ARG_MAXFRAMENR = atoi(argv[i]); + } else if (strcmp("-qtype", argv[i]) == 0 && i < argc - 1) { + i++; + ARG_QTYPE = atoi(argv[i]); + } else if (strcmp("-qmatrix", argv[i]) == 0 && i < argc - 1) { + FILE *fp = fopen(argv[++i], "rb"); + if (fp == NULL) { + fprintf(stderr, "Error opening input file %s\n", argv[i]); + return (-1); + } + fseek(fp, 0, SEEK_END); + if (ftell(fp) != 128) { + fprintf(stderr, "Unexpected size of input file %s\n", argv[i]); + return (-1); + } + + fseek(fp, 0, SEEK_SET); + fread(qmatrix_intra, 1, 64, fp); + fread(qmatrix_inter, 1, 64, fp); + + ARG_QMATRIX = 1; } else if (strcmp("-save", argv[i]) == 0) { ARG_SAVEMPEGSTREAM = 1; + ARG_SAVEINDIVIDUAL = 1; } else if (strcmp("-debug", argv[i]) == 0) { i++; if (sscanf(argv[i],"0x%x", &ARG_DEBUG) || sscanf(argv[i],"%d", &ARG_DEBUG)) ; } else if (strcmp("-o", argv[i]) == 0 && i < argc - 1) { + ARG_SAVEMPEGSTREAM = 1; i++; ARG_OUTPUTFILE = argv[i]; } else if (strcmp("-vop_debug", argv[i]) == 0) { ARG_VOPDEBUG = 1; + } else if (strcmp("-grey", argv[i]) == 0) { + ARG_GREYSCALE = 1; + } else if (strcmp("-bvhq", argv[i]) == 0) { + ARG_BVHQ = 1; } else if (strcmp("-qpel", argv[i]) == 0) { ARG_QPEL = 1; + } else if (strcmp("-turbo", argv[i]) == 0) { + ARG_TURBO = 1; } else if (strcmp("-gmc", argv[i]) == 0) { ARG_GMC = 1; + } else if (strcmp("-interlaced", argv[i]) == 0) { + ARG_INTERLACING = 1; + } else if (strcmp("-closed_gop", argv[i]) == 0) { + ARG_CLOSED_GOP = 1; } else if (strcmp("-help", argv[i])) { usage(); return (0); @@ -357,10 +413,11 @@ * Arguments checking ****************************************************************************/ - if (XDIM <= 0 || XDIM >= 2048 || YDIM <= 0 || YDIM >= 2048) { + if (XDIM <= 0 || XDIM >= 4096 || YDIM <= 0 || YDIM >= 4096) { fprintf(stderr, - "Trying to retreive width and height from PGM header\n"); - ARG_INPUTTYPE = 1; /* pgm */ + "Trying to retrieve width and height from input header\n"); + if (!ARG_INPUTTYPE) + ARG_INPUTTYPE = 1; /* pgm */ } if (ARG_QUALITY < 0 ) { @@ -382,15 +439,54 @@ if (ARG_INPUTFILE == NULL || strcmp(ARG_INPUTFILE, "stdin") == 0) { in_file = stdin; } else { +#ifdef XVID_AVI_INPUT + if (strcmp(ARG_INPUTFILE+(strlen(ARG_INPUTFILE)-3), "avs")==0 || + strcmp(ARG_INPUTFILE+(strlen(ARG_INPUTFILE)-3), "avi")==0 || + ARG_INPUTTYPE==2) + { + AVISTREAMINFO avi_info; + + AVIFileInit(); + if (AVIStreamOpenFromFile(&avi_stream, ARG_INPUTFILE, streamtypeVIDEO, 0, OF_READ, NULL) != AVIERR_OK) { + fprintf(stderr, "Can't open stream from file '%s'!\n", ARG_INPUTFILE); + AVIFileExit(); + return (-1); + } + + if(AVIStreamInfo(avi_stream, &avi_info, sizeof(AVISTREAMINFO)) != AVIERR_OK) { + fprintf(stderr, "Can't get stream info from file '%s'!\n", ARG_INPUTFILE); + AVIStreamRelease(avi_stream); + AVIFileExit(); + return (-1); + } + + if (avi_info.fccHandler != MAKEFOURCC('Y', 'V', '1', '2')) { + fprintf(stderr, "Unsupported input colorspace! Only YV12 is supported!\n"); + AVIStreamRelease(avi_stream); + AVIFileExit(); + return (-1); + } + + ARG_MAXFRAMENR = min(ARG_MAXFRAMENR, avi_info.dwLength); + + XDIM = avi_info.rcFrame.right - avi_info.rcFrame.left; + YDIM = avi_info.rcFrame.bottom - avi_info.rcFrame.top; + ARG_FRAMERATE = (float) avi_info.dwRate / (float) avi_info.dwScale; - in_file = fopen(ARG_INPUTFILE, "rb"); - if (in_file == NULL) { - fprintf(stderr, "Error opening input file %s\n", ARG_INPUTFILE); - return (-1); + ARG_INPUTTYPE = 2; + } + else +#endif + { + 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 (ARG_INPUTTYPE==1) { #ifndef READ_PNM if (read_pgmheader(in_file)) { #else @@ -459,7 +555,14 @@ } if (!result) { - if (ARG_INPUTTYPE) { +#ifdef XVID_AVI_INPUT + if (ARG_INPUTTYPE==2) { + /* read avs/avi data (YUV-format) */ + if(AVIStreamRead(avi_stream, input_num, 1, in_buffer, IMAGE_SIZE(XDIM, YDIM), NULL, NULL ) != AVIERR_OK) + result = 1; + } else +#endif + if (ARG_INPUTTYPE==1) { /* read PGM data (YUV-format) */ #ifndef READ_PNM result = read_pgmdata(in_file, in_buffer); @@ -541,26 +644,26 @@ ****************************************************************************/ if (m4v_size > 0 && ARG_SAVEMPEGSTREAM) { + /* Save single files */ - if (out_file == NULL) { + if (ARG_SAVEINDIVIDUAL) { + FILE *out; sprintf(filename, "%sframe%05d.m4v", filepath, output_num); - out_file = fopen(filename, "wb"); - fwrite(mp4_buffer, m4v_size, 1, out_file); - fclose(out_file); - out_file = NULL; + out = fopen(filename, "w+b"); + fwrite(mp4_buffer, m4v_size, 1, out); + fclose(out); output_num++; - } else { + } - /* Write mp4 data */ + /* Save ES stream */ + if (ARG_OUTPUTFILE && out_file) fwrite(mp4_buffer, 1, m4v_size, out_file); - - } } input_num++; /* Read the header if it's pgm stream */ - if (!result && ARG_INPUTTYPE) + if (!result && (ARG_INPUTTYPE==1)) #ifndef READ_PNM result = read_pgmheader(in_file); #else @@ -603,6 +706,13 @@ release_all: +#ifdef XVID_AVI_INPUT + if (avi_stream) { + AVIStreamRelease(avi_stream); + AVIFileExit(); + } +#endif + if (enc_handle) { result = enc_stop(); if (result) @@ -646,7 +756,7 @@ clock_t clk; clk = clock(); - return (clk * 1000 / CLOCKS_PER_SEC); + return (clk * 1000.0 / CLOCKS_PER_SEC); #endif } @@ -659,16 +769,20 @@ { fprintf(stderr, "Usage : xvid_stat [OPTIONS]\n\n"); fprintf(stderr, "Input options:\n"); - fprintf(stderr, " -i string : input filename (default=stdin)\n"); - fprintf(stderr, " -type integer: input data type (yuv=0, pgm=1)\n"); - fprintf(stderr, " -w integer: frame width ([1.2048])\n"); - fprintf(stderr, " -h integer: frame height ([1.2048])\n"); - fprintf(stderr, " -nframes integer: number of frames to encode\n"); + fprintf(stderr, " -i string : input filename (default=stdin)\n"); +#ifdef XVID_AVI_INPUT + fprintf(stderr, " -type integer: input data type (yuv=0, pgm=1, avi/avs=2)\n"); +#else + fprintf(stderr, " -type integer: input data type (yuv=0, pgm=1)\n"); +#endif + fprintf(stderr, " -w integer: frame width ([1.2048])\n"); + fprintf(stderr, " -h integer: frame height ([1.2048])\n"); + fprintf(stderr, " -frames integer: number of frames to encode\n"); fprintf(stderr, "\n"); fprintf(stderr, "Output options:\n"); fprintf(stderr, " -dump : save decoder output\n"); - fprintf(stderr, " -save : save mpeg4 raw stream\n"); - fprintf(stderr, " -o string: output filename\n"); + fprintf(stderr, " -save : save an Elementary Stream file per frame\n"); + fprintf(stderr, " -o string: save an Elementary Stream for the complete sequence\n"); fprintf(stderr, "\n"); fprintf(stderr, "BFrames options:\n"); fprintf(stderr, " -max_bframes integer: max bframes (default=0)\n"); @@ -686,16 +800,24 @@ fprintf(stderr, " -max_key_interval integer : maximum keyframe interval\n"); fprintf(stderr, "\n"); fprintf(stderr, "Other options\n"); - fprintf(stderr, " -asm : use assembly optmized code\n"); - fprintf(stderr, " -quality integer: quality ([0..%d])\n", ME_ELEMENTS - 1); - fprintf(stderr, " -qpel : use quarter pixel ME\n"); - fprintf(stderr, " -gmc : use global motion compensation\n"); - fprintf(stderr, " -packed : packed mode\n"); - fprintf(stderr, " -lumimasking : use lumimasking algorithm\n"); - fprintf(stderr, " -stats : print stats about encoded frames\n"); - fprintf(stderr, " -debug : activates xvidcore internal debugging output\n"); - fprintf(stderr, " -vop_debug : print some info directly into encoded frames\n"); - fprintf(stderr, " -help : prints this help message\n"); + fprintf(stderr, " -noasm : do not use assembly optmized code\n"); + fprintf(stderr, " -turbo : use turbo presets for higher encoding speed\n"); + fprintf(stderr, " -quality integer : quality ([0..%d])\n", ME_ELEMENTS - 1); + fprintf(stderr, " -vhqmode integer : level of Rate-Distortion optimizations ([0..4]) (default=0)\n"); + fprintf(stderr, " -bvhq : use Rate-Distortion optimizations for B-frames too\n"); + fprintf(stderr, " -qpel : use quarter pixel ME\n"); + fprintf(stderr, " -gmc : use global motion compensation\n"); + fprintf(stderr, " -qtype integer : quantization type (H263:0, MPEG4:1) (default=0)\n"); + fprintf(stderr, " -qmatrix filename: use custom MPEG4 quantization matrix\n"); + fprintf(stderr, " -interlaced : use interlaced encoding (this is NOT a deinterlacer!)\n"); + fprintf(stderr, " -packed : packed mode\n"); + fprintf(stderr, " -closed_gop : closed GOP mode\n"); + fprintf(stderr, " -grey : grey scale coding (chroma is discarded)\n"); + fprintf(stderr, " -lumimasking : use lumimasking algorithm\n"); + fprintf(stderr, " -stats : print stats about encoded frames\n"); + fprintf(stderr, " -debug : activates xvidcore internal debugging output\n"); + fprintf(stderr, " -vop_debug : print some info directly into encoded frames\n"); + fprintf(stderr, " -help : prints this help message\n"); fprintf(stderr, "\n"); fprintf(stderr, "NB: You can define %d zones repeating the -z[qw] option as many times as needed.\n", MAX_ZONES); fprintf(stderr, "\n"); @@ -722,7 +844,7 @@ return (1); fscanf(handle, "%d %d %d", &xsize, &ysize, &depth); - if ((xsize > 1440) || (ysize > 2880) || (depth != 255)) { + if ((xsize > 4096) || (ysize > 4096*3/2) || (depth != 255)) { fprintf(stderr, "%d %d %d\n", xsize, ysize, depth); return (2); } @@ -918,6 +1040,7 @@ /* Width and Height of input frames */ xvid_enc_create.width = XDIM; xvid_enc_create.height = YDIM; + xvid_enc_create.profile = XVID_PROFILE_AS_L4; /* init plugins */ xvid_enc_create.zones = ZONES; @@ -942,6 +1065,13 @@ rc2pass2.filename = ARG_PASS2; rc2pass2.bitrate = ARG_BITRATE; +/* An example of activating VBV could look like this + rc2pass2.vbv_size = 3145728; + rc2pass2.vbv_initial = 2359296; + rc2pass2.vbv_maxrate = 4000000; + rc2pass2.vbv_peakrate = 10000000; +*/ + plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass2; plugins[xvid_enc_create.num_plugins].param = &rc2pass2; xvid_enc_create.num_plugins++; @@ -1008,10 +1138,13 @@ xvid_enc_create.global = 0; if (ARG_PACKED) - xvid_enc_create.global |=XVID_GLOBAL_PACKED; + xvid_enc_create.global |= XVID_GLOBAL_PACKED; + + if (ARG_CLOSED_GOP) + xvid_enc_create.global |= XVID_GLOBAL_CLOSED_GOP; if (ARG_STATS) - xvid_enc_create.global |=XVID_GLOBAL_EXTRASTATS_ENABLE; + xvid_enc_create.global |= XVID_GLOBAL_EXTRASTATS_ENABLE; /* 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); @@ -1062,7 +1195,10 @@ if (image) { xvid_enc_frame.input.plane[0] = image; #ifndef READ_PNM - xvid_enc_frame.input.csp = XVID_CSP_I420; + if (ARG_INPUTTYPE==2) + xvid_enc_frame.input.csp = XVID_CSP_YV12; + else + xvid_enc_frame.input.csp = XVID_CSP_I420; xvid_enc_frame.input.stride[0] = XDIM; #else xvid_enc_frame.input.csp = XVID_CSP_BGR; @@ -1076,20 +1212,26 @@ xvid_enc_frame.vol_flags = 0; if (ARG_STATS) xvid_enc_frame.vol_flags |= XVID_VOL_EXTRASTATS; + if (ARG_QTYPE) + xvid_enc_frame.vol_flags |= XVID_VOL_MPEGQUANT; if (ARG_QPEL) xvid_enc_frame.vol_flags |= XVID_VOL_QUARTERPEL; if (ARG_GMC) xvid_enc_frame.vol_flags |= XVID_VOL_GMC; + if (ARG_INTERLACING) + xvid_enc_frame.vol_flags |= XVID_VOL_INTERLACING; /* Set up core's general features */ xvid_enc_frame.vop_flags = vop_presets[ARG_QUALITY]; - if (ARG_GMC) - xvid_enc_frame.vop_flags |= XVID_ME_GME_REFINE; if (ARG_VOPDEBUG) { xvid_enc_frame.vop_flags |= XVID_VOP_DEBUG; } + if (ARG_GREYSCALE) { + xvid_enc_frame.vop_flags |= XVID_VOP_GREYSCALE; + } + /* Frame type -- let core decide for us */ xvid_enc_frame.type = XVID_TYPE_AUTO; @@ -1099,14 +1241,67 @@ /* Set up motion estimation flags */ xvid_enc_frame.motion = motion_presets[ARG_QUALITY]; + if (ARG_GMC) + xvid_enc_frame.motion |= XVID_ME_GME_REFINE; + if (ARG_QPEL) xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE16; if (ARG_QPEL && (xvid_enc_frame.vop_flags & XVID_VOP_INTER4V)) xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE8; - /* We don't use special matrices */ - xvid_enc_frame.quant_intra_matrix = NULL; - xvid_enc_frame.quant_inter_matrix = NULL; + if (ARG_TURBO) + xvid_enc_frame.motion |= XVID_ME_FASTREFINE16 | XVID_ME_FASTREFINE8 | + XVID_ME_SKIP_DELTASEARCH | XVID_ME_FAST_MODEINTERPOLATE | + XVID_ME_BFRAME_EARLYSTOP; + + if (ARG_BVHQ) + xvid_enc_frame.vop_flags |= XVID_VOP_RD_BVOP; + + 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; + } + + if (ARG_QMATRIX) { + /* We don't use special matrices */ + xvid_enc_frame.quant_intra_matrix = qmatrix_intra; + xvid_enc_frame.quant_inter_matrix = qmatrix_inter; + } + else { + /* We don't use special matrices */ + xvid_enc_frame.quant_intra_matrix = NULL; + xvid_enc_frame.quant_inter_matrix = NULL; + } /* Encode the frame */ ret = xvid_encore(enc_handle, XVID_ENC_ENCODE, &xvid_enc_frame,