// // . This program calls ImageMagick and Avifile functions to // transform a sequence of images to an avi file. // // . Derived from im2avi-0.2 (http://cpbotha.net/im2avi.html) // by ZLB, Nov 15 2002 // // . Packages required to compile this program: // XFRee86-devel, bzip2-devel, avifile (plus win32 codecs), // ImageMagick++-devel // // . Avifiles generated by the following video codecs are // known to work with MicroDVD Player under Windows: // 1. Uncompressed YUY2 // 7. DivX ;-) VKI (Low-Motion) // 8. DivX ;-) VKI (Fast-Motion) // 9. DivX ;-) Low-Motion // 10. DivX ;-) Fast-Motion // 11. Microsoft MPEG-4 // 14. Indeo(r) Video 5.04 // 15. Indeo Video 4.1 // 21. Cinepak Video // #define Image2AVI_Version "v0.2" #include // for getopt #include // for *printf #include // #include #include #include #include #include #include // avifile #include #include #include #include #include #include #include // ImageMagick++ #include #ifdef EXPAND_WILDCARDS extern "C" int expandWildCards(char *fileNamePattern, char ***retFileTable); #endif using namespace std; using namespace Magick; // Global parameters static char default_codec[] = "DivX ;-) Low-Motion"; static char avi_fn[1024] = "out.avi"; static int avi_flip_image = false; static int avi_codec_index = -1; static float avi_fps = 25; static int avi_quality = 100; // percentage static int avi_width = 0; static int avi_height = 0; static int avi_scale = 0; // 0 = scale (ignore aspect) // 1 = scale + border // 2 = scale + crop // 3 = crop + border (no scale) void init_codecs(int index) // index == -1 : use default codec // index >= 0 : use video_codecs[index], // index <= -2 : list available codecs and exit. { // this is a dummy create so that the video_codecs list is filled in BITMAPINFOHEADER bih; bih.biCompression = 0xffffffff; Creators::CreateVideoDecoder(bih, 0, 0); avm::vector::iterator it; int i=0; if ( index <= -2 ) { char s[128]; sprintf(s, "Default codec ==> %s", default_codec); cerr << "\nAvailable codecs:\n"; fprintf(stderr, "\t%3d. %s\n", -1, s); } for (it=video_codecs.begin(); it!=video_codecs.end(); it++) if (it->direction & CodecInfo::Encode) { if ( index <= -2 ) { #if 1 fprintf(stderr, "\t%3d. %s\n", i, it->GetName()); #else fprintf(stderr, "\t%3d. name: %s, kind: %d, dll: %s\n", i, it->GetName(), it->kind, it->dll.c_str()); #endif } else if (index==-1) { if ( avi_codec_index<0 || !strcmp(it->GetName(),default_codec) ) avi_codec_index = it - video_codecs.begin(); } else if (index==i) { avi_codec_index = it - video_codecs.begin(); } i++; } if ( index <= -2 ) exit(1); if ( avi_codec_index<0 ) { cerr << "No valid video codec found (use '-c help' to get a list)\n"; exit(2); } } void make_avi(int n, char *fnlist[]) { IAviWriteFile* avi_file = NULL; IAviVideoWriteStream* stream = NULL; unsigned char *image_data = new unsigned char[avi_width * avi_height * 3]; int nframes = 0; try { BitmapInfo bh(avi_width, avi_height, 24); avi_file = CreateIAviWriteFile(avi_fn); stream = avi_file->AddVideoStream(video_codecs[avi_codec_index].fourcc, &bh, int(1000000.0/avi_fps) ); stream->SetQuality(100 * avi_quality); stream->Start(); for (int i = 0; i < n; i++) { // loop on filenames char **fn; int j, m; #ifndef EXPAND_WILDCARDS m = 1; fn = fnlist + i; #else m = expandWildCards(fnlist[i], &fn); if (m<=0) { char s[1024]; sprintf(s, "%s: no such file.", fnlist[i]); throw std::runtime_error(s); } #endif for (j=0; j images; readImages( &images, fn[j] ); list::iterator image=images.begin(); int k=0; for (; image!=images.end(); image++) { // image(s) in one file fprintf(stderr, "Processing %-68s\r%s[%d]\r", "", fn[j], k++); // flip it vertically (avifile seems to like it that way) if (avi_flip_image) image->flip(); int width = image->size().width(); int height= image->size().height(); if ( width!=avi_width || height!=avi_height ) { // image size needs to be adjusted. if ( avi_scale <=2 ) { // Scale image int width1, height1; if ( avi_scale == 0 ) { // scale, ignore aspect width1 = avi_width; height1 = avi_height; } else { double r0=avi_width/(double)width, r1=avi_height/(double)height; avi_scale==1 ? r0=min(r0,r1) : r0=max(r0,r1); width1 = (int)(width*r0+0.5); height1 = (int)(height*r0+0.5); } Magick::Geometry new_geom(width1, height1); new_geom.aspect(true); image->zoom(new_geom); width = width1; height = height1; } // add borders to make image >= output size if ( avi_width>width || avi_height>height ) { Magick::Geometry new_geom( avi_width > width ? (avi_width - width + 1)/2 : 0, avi_height > height ? (avi_height - height + 1)/2 : 0 ); image->border(new_geom); width = image->size().width(); height= image->size().height(); } if ( width!=avi_width || height!=avi_height ) { // crop image to output size Magick::Geometry new_geom( avi_width, avi_height, (width-avi_width+1)/2, (height-avi_height+1)/2 ); image->crop(new_geom); } } // get image data image->write(0, 0, avi_width, avi_height, "BGR", Magick::CharPixel, image_data); // create a CImage from this, but don't copy the data CImage avi_image(&bh, image_data, false); if (stream->AddFrame(&avi_image) != 0) throw std::runtime_error("Unable to add frame."); nframes++; } // for image } // for j } // for i } // try catch (Magick::Exception &e) { cerr<Stop(); if (avi_file) delete avi_file; fprintf(stderr,"\n%d frame%s processed.\n\n", nframes, nframes>1 ? "s":""); } void Usage(char *progname) { cerr << "Usage: " << progname << " [options] image_files\n"; cerr << "Options:\n"; cerr << " -h, -? \tdisplay this help text.\n"; cerr << " -f \tflip images vertically.\n"; cerr << " -s #[x#]\toutput image size (default=first input image).\n"; cerr << " -o str \toutput avi filename (default=out.avi)\n"; cerr << " -r # \tframe rate (frames/s, default=25).\n"; cerr << " -q # \tquality (percent, default=100).\n"; cerr << " -c # \tvideo codec index ('help' shows list)\n"; cerr << " \tdefault=\""< 100) ERROR; break; case 'm': avi_scale = atoi (optarg); if (avi_scale < 0 || avi_scale > 3) ERROR; break; case 'c': if ( !strcmp(optarg, "help") ) init_codecs(-2); codec = atoi(optarg); break; case 'h': case '?': default: Usage (argv[0]); } } argc -= optind; if (argc < 1) { cerr << "Missing input image filename(s).\n"; Usage (argv[0]); } argv += optind; #if 0 { list images; readImages( &images, argv[0] ); cerr << "\nNbr of images = " << images.size() << endl; list::iterator image; for (image=images.begin(); image!=images.end(); image++) { cerr << "width=" << image->size().width() << endl; } exit(0); } #endif init_codecs(codec); if ( avi_width<=0 || avi_height<=0 ) { try { #ifndef EXPAND_WILDCARDS Magick::Image image(argv[0]); #else char **fn; ch = expandWildCards(argv[0], &fn); if (ch<=0) { char s[1024]; sprintf(s, "%s: no such file.", argv[0]); throw Magick::Exception(s); } Magick::Image image(fn[0]); #endif avi_width = image.size().width(); avi_height= image.size().height(); } catch (Magick::Exception &e) { cerr<