www.pudn.com > avi 到 mpeg 的转换程序及源代码.zip > AVI2MPG1.C
// // avi2mpg1 - windows .avi to mpeg-1 encoder // // // Copyright (C) 1997 John Schlichther // // 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. // // 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., 675 Mass Ave, Cambridge, MA 02139, USA. // // // usage: avi2mpg1 [-options] inputfile.avi [outputfile.mpg] // // where: // options can be: // -b byterate Where byterate is total system stream // rate in KB/s (default 150) // Valid range = 10 to 5000. // // -s bitrate Where bitrate is total system stream // rate in K bits/s (default 1200) // Valid range = 80 to 40000. // // YOU CAN ONLY SPECIFY -b OR -s, NOT BOTH! // // -a bitrate Where bitrate is audio bitrate in // K bits/s (default 128 K) // Valid values for layer I: // 32,64,96,128,160,192,224,256,288,320,352,384,416,448 // Valid values for layer II: // 32,48,56,64,80,96,112,128,160,192,224,256,320,384 // // -l layer Where layer specifies which layer // to use, valid values 1 or 2. // (default 2) // // -j specifies use joint stereo mode IF // input file contains stereo audio. // Has no effect if audio portion of .avi // is mono. (default non-joint stereo) // // -v specifies fixed datarates as defined for // video cd streams. If this option // is used, it overides any -a or -b // rates specified. // // -p filename.par specifies the name of a file that contains // additional parameters for the video portion // of the encoder. // // -e if avi is corrupt (ie: some frames unreadable) // fake using last frame, bad audio replaced with // zero data. // // -n no audio, generates video only (.m1v) file, also // needed if avi does not contain an audio stream. // // -y vbv_buffer size in 16K bit multiples, default = 20 // // -m motion search magnitude, range 0 - 4, default 0, // higher values MAY result in better encoding (depending // on video), but will take SIGNIFICANTLY longer to encode. // Try it on a short sample first! // // -c hor_size ver_size crop (or expand) to specified horizontal and // vertical size. // // -f frame_rate_code force specific mpeg frame rate, regardless of // input video frame rate, implies -n (video only) // // inputfile.avi A windows avi file constrained to the following // parameters: // // Horizontal size: < 4096 pixels // Vertical size: < 4096 pixels // Frame rate : 23.976, 24, 25, 29.97, or 30 FPS // 10, 12, and 15 are also supported, // but upsampled to standard rate. // Colour depth: 16, 24, or 32 bit. // (thousands, millions, millions+) // codec used in file must be installed in windows. // // Audio sample rate: 11.025, 22.05, and 44.1KHz // Audio sample size: 8 or 16 bit // Audio channels: 1 or 2 // Uncompressed PCM audio only.. // // outputfile.mpg Optional, if not specified, inputfilename with .mpg // extension will be created. // // Change log: // // 4/4/97 - Ver 1.0 - Initial Release - John Schlichther // 7/15/97 - Ver 1.1 - Added support for 8 bit audio // at 11.025, 22.05, and 44.1 KHz rates // 7/19/97 - Ver 1.2 - improved low-pass filtering for 11025 and 22050 audio // - added 8 bit palletized video // - corrected chroma subsampling // - added option to specify system stream data rate in // K bits/s. // - added option to read in video encoding parameter file // 7/30/97 - Ver 1.3 - added option to handle avi's with bad data, ie: // replace bad frames with previous good one. (-e) // - added option to generate video only file (-n) // - added suppport for 10, 12 and 15 FPS video, frames // are duplicated to generate standard MPEG frame rate. // 8/4/97 - made options case insensitive // - handles video with odd pixel sizes (pads with blanks // to even pixel size hor and vert. // - changed intermediate file names to be based on output // filename instead of input file name. // - open max size up to 704 x 480 // - increase max bit rate up to 4000K bit/sec // min bit rate down to 80K bit/sec // - added user control of vbv_buffer_size // - added motion search magnitude control (-m) // 8/14/97 - Ver 1.4 - bug fixes for VideoCD stream creation // - add size cropping option (-c x_size y_size) // - added force frame rate option (-f) // - open max size up to 720 x 480 // // 11/19/97 - Ver 1.5 - open max size limit to mpeg-1 limit, 4096x4096 // - dynamically allocated memory for U and Y buffers // in readpic routine // - open max data rate up to 40,000K bit/sec // - report audio encoding progress in % // // #include#include "avi2mpg1.h" #define GLOBAL /* used by global.h and video.h*/ #include "global.h" #include "video.h" // function prototypes void usage(void); int ValidBitrate(unsigned int, unsigned int); void StripExtension(char *, char *); void StripPath(char *, char *); int mplex(char *, char *, char *); unsigned int pixsz; // globals int main(int argc, char **argv) { int i=0, err=0; char avifilename[_MAX_PATH] = "", basefilename[_MAX_FNAME] = "", mpegfilename[_MAX_PATH] = ""; char VideoTempFile[_MAX_FNAME] = "", AudioTempFile[_MAX_FNAME] = "", basepathname[_MAX_PATH]; char testfilename[_MAX_PATH] = "", intfilename[_MAX_FNAME]; float fps; int sys_bit_specd = 0, sys_byte_specd = 0; time_t current_time, el_time; bad_frame_count = 0; bad_audio_count = 0; vbv_size = 20; m_search_size = 0; crop_size = 0; forced_frame_rate = 0; if(argc < 2) { usage(); } // set up defaults system_byterate_parm = 150; audio_bitrate_parm = 128; audio_layer_parm = 2; joint_stereo_parm = 0; vcd_parm = 0; fake_bad_frames = 0; video_only = 0; // parse for paramters here while((++i < argc)&&(err == 0)) { char c, *token, *arg, *nextArg, *nextArg2; int argUsed; token = argv[i]; if(*token++ == '-') { // must be an option if(i+1 < argc) nextArg = argv[i+1]; else nextArg = ""; argUsed = 0; while(c = *token++) { if(*token /* NumericQ(token) */) arg = token; else arg = nextArg; switch(tolower(c)) { case 'l': audio_layer_parm = atoi(arg); argUsed = 1; if((audio_layer_parm < 1)||(audio_layer_parm > 2)) { fprintf(stderr,"\n-l layer must be 1 or 2, not %s\n", arg); err = 1; } break; case 'b': argUsed = 1; system_byterate_parm = atoi(arg); sys_byte_specd = 1; if(sys_bit_specd) { fprintf(stderr, "\n can not specify both -b and -s!\n"); err = 1; } if((system_byterate_parm < 10)||(system_byterate_parm > 5000)) { fprintf(stderr, "\n-b system byterate (K bytes/s) must be from 10 to 5000, not %s\n", arg); err = 1; } break; case 's': argUsed = 1; system_byterate_parm = atoi(arg)/8; sys_bit_specd = 1; if(sys_byte_specd) { fprintf(stderr, "\n can not specify both -b and -s!\n"); err = 1; } if((system_byterate_parm < 10)||(atoi(arg) > 40000)) { fprintf(stderr, "\n-s system bitrate (K bits/s) must be from 80 to 40000, not %s\n", arg); err = 1; } break; case 'a': argUsed = 1; audio_bitrate_parm = atoi(arg); break; case 'j': joint_stereo_parm = 1; break; case 'v': vcd_parm = 1; break; case 'p': argUsed = 1; strcpy(video_param_filename, arg); use_v_param_file = 1; break; case 'e': fake_bad_frames = 1; break; case 'n': video_only = 1; break; case 'y': argUsed = 1; vbv_size = atoi(arg); if(vbv_size < 1) { fprintf(stderr, "\n vbv_buffer_size must be in range 1 <-> 1023.\n"); err = 1; } break; case 'm': argUsed = 1; m_search_size = atoi(arg); if((m_search_size < 0 )||(m_search_size > 4)) { fprintf(stderr, "\n -m search option must be from 0 to 4!\n"); err = 1; } break; case 'c': if(i+2 < argc) { nextArg2 = argv[i+2]; i++; } else nextArg2 = ""; crop_size = 1; argUsed =1; crop_horz = atoi(arg); if((crop_horz < 16)||(crop_horz>4095)) { fprintf(stderr, "\n -c horizontal size must be from 16 to 4095!\n"); err = 1; } crop_vert = atoi(nextArg2); if((crop_vert < 16)||(crop_vert>4095)) { fprintf(stderr, "\n -c vertical size must be from 16 to 4095!\n"); err=1; } break; case 'f': argUsed = 1; forced_frame_rate = atoi(arg); if((forced_frame_rate < 1)||(forced_frame_rate > 5)) { fprintf(stderr, "\n -f frame rate code must be from 1 to 5!\n"); err=1; } break; default: fprintf(stderr,"\nunrecognized option %c\n", c); err = 1; break; } if(argUsed) { if(arg == token) token = ""; /* no more from token */ else ++i; /* skip arg we used */ arg = ""; argUsed = 0; } } } else // not an option, must be a filename { if(avifilename[0] == '\0') strcpy(avifilename, argv[i]); else if(mpegfilename[0] == '\0') strcpy(mpegfilename, argv[i]); else { usage(); // too many parameters } } } if(vcd_parm) { system_byterate_parm = 1158000/8/1024; audio_bitrate_parm = 224; audio_layer_parm = 2; joint_stereo_parm = 0; } if(!ValidBitrate(audio_layer_parm, audio_bitrate_parm)) { fprintf(stderr, "\n-a bitrate %i not legal for layer %i", audio_bitrate_parm, audio_layer_parm); err = 1; } if(vcd_parm&&video_only) { fprintf(stderr, "\n can not specify both -v and -n!\n"); err = 1; } if(vcd_parm&&forced_frame_rate) { fprintf(stderr, "\n can not specify both -v and -f!\n"); err = 1; } if(forced_frame_rate) video_only = 1; if(err) { fprintf(stderr, "\n type avi2mpg1 for usage.\n"); exit(-1); } if(avifilename[0] == '\0') usage(); /* never returns */ // build the base (no extension) path filename StripExtension(basepathname, avifilename); if(strlen(avifilename) == strlen(basepathname)) strcat(avifilename, ".avi"); // input filename had no extension, add .avi // open avi file and validate file parameters // initialize AVI subsystem AVIFileInit(); hResult = AVIFileOpen(&pfile, avifilename, OF_READ, 0L); if(hResult) { fprintf(stderr, "\ncould not open filename %s!\n", avifilename); exit(-1); } // get info structure on file hResult = AVIFileInfo(pfile, &pfi, sizeof(AVIFILEINFO)); if(hResult) { fprintf(stderr, "\n%s does not appear to be an AVI file!\n", avifilename); exit(-1); } // open a stream hResult = AVIFileGetStream(pfile, &pVideoStream, streamtypeVIDEO, 0); if(hResult) { fprintf(stderr, "\ncould not retrieve video stream from %s!\n", avifilename); exit(-1); } // prepare to decompress frames pget = AVIStreamGetFrameOpen(pVideoStream, NULL); // print details on input file fps = (float)pfi.dwRate/(float)pfi.dwScale; fprintf(stderr, "%s file details:\nWidth = %u, Height = %u, FPS = %4.2f", avifilename, pfi.dwWidth, pfi.dwHeight, fps); // now retrieve a video frame so we can identify details // get pointer to bitmap lpbi = AVIStreamGetFrame(pget, 0); if(!lpbi) { fprintf(stderr, "\ncould not retrieve video details!"); fprintf(stderr, "\nyou probably do not have a codec for this compression scheme!"); fprintf(stderr, "\nor avi file may be corrupt!\n"); exit(-1); } last_good_video_frame = 0; // we only handle non-palletized video pixsz = lpbi->biBitCount; if((pixsz!=8)&&(pixsz!=16)&&(pixsz!=24)&&(pixsz!=32)) { fprintf(stderr, "\ncan only handle 8 bit palletized, 16, 24, or 32 bit RGB video!,"); fprintf(stderr, "\nthis file is %i bits!\n", pixsz); exit(-1); } fprintf(stderr, ", Bits per pixel = %u", pixsz); if(pfi.dwWidth>4095) { fprintf(stderr, "\nHorizontal width must < 4096!"); err = 1; } if(pfi.dwHeight>4095) { fprintf(stderr, "\nVerical height must be < 4096!"); err = 1; } if(err) exit(-1); fprintf(stderr, "\nTotal Video Frames = %u, ", pfi.dwLength); fprintf(stderr, "Length = %u sec.", (unsigned int)pfi.dwLength/(int)(fps+.5)); // check for compression type of retrieved DIB if (lpbi->biCompression != BI_RGB) { fprintf(stderr, "\ncan not handle compressed DIBs from codec!\n"); err = 1; } if(!video_only) { // now lets check audio stream if (AVIFileGetStream(pfile, &pAudioStream, streamtypeAUDIO, 0)) { fprintf(stderr, "\nCould not open avi audio stream!"); fprintf(stderr, "\nIf this avi has no audio, or you want to generate an"); fprintf(stderr, "\nmpeg video only stream, use the -n option."); exit(-1); } if (AVIStreamInfo(pAudioStream, &pAudioStreamInfo, sizeof(pAudioStreamInfo))) { fprintf(stderr, "\nCould not retrieve avi audio stream info!"); exit(-1); } AVIStreamReadFormat(pAudioStream, 0, 0, &length); // get length of format data if(AVIStreamReadFormat(pAudioStream, 0, &pWavFormat, &length)) { fprintf(stderr, "\nCould not retrieve avi audio format info!"); exit(-1); } fprintf(stderr, "\nAudio Channels = %i, ", pWavFormat.nChannels); fprintf(stderr, "Sample rate = %6.3f KHz, bits per sample = %u\n", (float)pWavFormat.nSamplesPerSec/1000.0, pWavFormat.wBitsPerSample); if(vcd_parm&&(pWavFormat.nChannels!=2)) { fprintf(stderr, "\n for Video CD audio must be stereo!\n"); err = 1; } if (pWavFormat.wFormatTag != WAVE_FORMAT_PCM) { fprintf(stderr, "\ninput avi audio must be uncompressed PCM!\n"); err = 1; } if ((pWavFormat.nSamplesPerSec != 11025) && (pWavFormat.nSamplesPerSec != 22050) && (pWavFormat.nSamplesPerSec != 44100)) { fprintf(stderr, "\ninput avi audio sample rate must = 11.025, 22.05, or 44.1 kHz!\n"); err = 1; } if ((pWavFormat.wBitsPerSample != 16) && (pWavFormat.wBitsPerSample != 8)) { fprintf(stderr, "\ninput avi audio must be 8 or 16 bit!, this file is %i bits\n", pWavFormat.wBitsPerSample); err = 1; } } else fprintf(stderr, "\n"); if (err == 1) exit(-1); // create base filename, strip path info from basepathname StripPath(basefilename, basepathname); // now generate intermediate and output filenames if(mpegfilename[0] != '\0') // if user supplied output filename: { StripExtension(testfilename, mpegfilename); StripPath(intfilename, testfilename); // intfilename = basic outputfile name } else // otherwise, we base it on the input filename { StripPath(intfilename, basepathname); } if(use_v_param_file) { // if parameter file used, add .par extension if none supplied StripExtension(testfilename, video_param_filename); if(strlen(video_param_filename) == strlen(testfilename)) strcat(video_param_filename, ".par"); } // call avi2m1v to encode video stream strcpy(VideoTempFile, intfilename); strcat(VideoTempFile, ".m1v"); fprintf(stderr, "encoding video stream to %s", VideoTempFile); avi2m1v(VideoTempFile); AVIStreamGetFrameClose(pget); fprintf(stderr, " \r"); // if there were errors during encoding of video, print them if(vbv_ovflow!=0) fprintf(stderr, "*** WARNING: VBV_BUFFER OVERFLOWED %u TIMES.\n", vbv_ovflow); if(vbv_unflow!=0) fprintf(stderr, "*** WARNING: VBV_BUFFER UNDERFLOWED %u TIMES.\n", vbv_unflow); if(bad_frame_count) fprintf(stderr, "*** WARNING: %u CORRUPT VIDEO FRAMES REPLACED BY PREVIOUS GOOD FRAME!\n", bad_frame_count); fprintf(stderr, "video encoding complete,"); time(¤t_time); el_time = current_time - start_time; if(el_time <= 60) fprintf(stderr, " elapsed time = %i seconds\n", el_time); else if(el_time < 3600) fprintf(stderr, " elapsed time = %i minutes\n", (el_time/60)+1); else fprintf(stderr, " elapsed time = %i hour(s) %i minute(s)\n", el_time/3600, (el_time%3600)/60); fprintf(stderr, "average seconds per frame = %5.3f\n", (float)el_time/(float)(pfi.dwLength*frame_repl)); if(!video_only) { // call avi2mp2 to encode audio stream strcpy(AudioTempFile, intfilename); strcat(AudioTempFile, ".mp2"); fprintf(stderr, "encoding audio stream to %s", AudioTempFile); fprintf(stderr, " using bitrate of %u:\n", audio_bitrate_parm*1024); avi2mp2(AudioTempFile); fprintf(stderr, "\raudio stream encoding complete.\n"); if(bad_audio_count) fprintf(stderr, "***WARNING: %u CORRUPT AUDIO SAMPLES REPLACED BY 0 DATA!\n", bad_audio_count); } AVIFileRelease(pfile); AVIFileExit(); if(!video_only) { // check if user supplied outputfile (if any) has an extension, // if not, add .mpg if(mpegfilename[0] != '\0') { StripExtension(testfilename, mpegfilename); if(strlen(mpegfilename) == strlen(testfilename)) strcat(mpegfilename, ".mpg"); } // call mplex to create .mpg file if(mpegfilename[0] == '\0') { strcpy(mpegfilename, basefilename); // no output file name supplied, strcat(mpegfilename, ".mpg"); // use input filename with .mpg } fprintf(stderr, "multiplexing video and audio streams to %s:\n", mpegfilename); mplex(VideoTempFile, AudioTempFile, mpegfilename); fprintf(stderr, "\rmultiplexing complete.\n"); if(video_end_early) fprintf(stderr, "***WARNING: video stream ended early!\n"); if(audio_end_early) fprintf(stderr, "***WARNING: audio stream ended early!\n"); if(video_time_out) fprintf(stderr, "***WARNING: video stream timed out %u times.\n", video_time_out); if(audio_time_out) fprintf(stderr, "***WARNING: audio strean timed out %u times.\n", audio_time_out); // delete temporary files. fprintf(stderr, "deleting temporary video and audio files.\n"); DeleteFile(VideoTempFile); DeleteFile(AudioTempFile); } return(0); } void usage() { fprintf(stderr, "\navi2mpg1 - avi to mpeg-1 encoder version %s,", VERSION); fprintf(stderr, "\nCopyright (C) 1997 John Schlichther"); fprintf(stderr, "\navi2mpg1 comes with ABSOLUTELY NO WARRANTY"); fprintf(stderr, "\nThis is free software, and you are welcome to redistribute it"); fprintf(stderr, "\nunder certain conditions; see file COPYING for details."); fprintf(stderr, "\n\n usage: avi2mpg1 [-options] inputfile.avi [outputfile.mpg]"); fprintf(stderr, "\n where: -b byterate (total stream - default 150 KBytes/s)"); fprintf(stderr, "\n -s bitrate (total stream - default 1200 Kbits/s)"); fprintf(stderr, "\n SPECIFY -b OR -s, NOT BOTH!"); fprintf(stderr, "\n -a bitrate (audio - default 128Kbits/s)"); fprintf(stderr, "\n -l layer (audio - default 2)"); fprintf(stderr, "\n -j (joint stereo)"); fprintf(stderr, "\n -v (use Video-cd parameters - overides -b, -s, -a, -l, -n, -c)"); fprintf(stderr, "\n -p filename.par video encoding parameter file (optional)"); fprintf(stderr, "\n -e ignore avi file errors"); fprintf(stderr, "\n -n generate video (.m1v) stream only"); fprintf(stderr, "\n -y vbv_buffer_size"); fprintf(stderr, "\n -m motion search magnitude, range 0 - 4, default 0"); fprintf(stderr, "\n -c horz_size vert_size cropping"); fprintf(stderr, "\n -f frame_rate_code 1->5, force frame rate"); fprintf(stderr, "\n inputfile.avi any valid avi file to encode"); fprintf(stderr, "\n outputfile.mpg output mpeg-1 file\n"); exit(-1); } unsigned int abitrate[2][14] = { {32,64,96,128,160,192,224,256,288,320,352,384,416,448}, {32,48,56,64,80,96,112,128,160,192,224,256,320,384}, }; int ValidBitrate(layr, bRate) /* return 1 if legal bit rate for layer, 0 otherwise */ unsigned int layr; /* 1 or 2 */ unsigned int bRate; /* legal rates from 32 to 448 */ { int index = 0; int found = 0; while(!found &&(index < 14)) { if(abitrate[layr-1][index] == bRate) found = 1; else ++index; } if(found) return(1); else return(0); } // // StripExtension - copy source filename to base and strip // extension if any. // void StripExtension(char *base, char *source) { int i, period = 0, backslash = 0; strcpy(base, source); i = strlen(base); while((i > 0) && !period && !backslash) { i--; if(base[i] == '.') period = 1; else if (base[i] == '\\') backslash = 1; } if(i == 0) return; // scanned all the way to begining, there is no extension if(backslash) return; // backslash found before period, there can't be an extension // if we're not at i=0, and we didn't find a backslash, // then we have to have found a period! base[i] = '\0'; // strip off extension } // // StripPath - copy source filename to base and strip // path if any. // void StripPath(char *base, char *source) { int i, backslash = 0; char *pSource; pSource = source; i = strlen(source); while((i > 0) && !backslash) { i--; if ((source[i] == '\\')||(source[i] == ':')) backslash = 1; } if(backslash) { pSource = pSource + i + 1; strcpy(base, pSource); } else strcpy(base, source); return; }