00001
00002
00003
00004 #include "vidl_vil1_avicodec.h"
00005 #include <vidl_vil1/vidl_vil1_frame.h>
00006 #include <vidl_vil1/vidl_vil1_movie.h>
00007
00008 #include <vcl_iostream.h>
00009 #include <vcl_cstdio.h>
00010
00011 #include <vul/vul_file.h>
00012
00013
00014 #include <windows.h>
00015 #include <vfw.h>
00016 #include <windowsx.h>
00017
00018
00019
00020
00021 #define RGB16R(rgb) ((((UINT)(rgb) >> 10) & 0x1F) * 255u / 31u)
00022 #define RGB16G(rgb) ((((UINT)(rgb) >> 5) & 0x1F) * 255u / 31u)
00023 #define RGB16B(rgb) ((((UINT)(rgb) >> 0) & 0x1F) * 255u / 31u)
00024
00025
00026 vidl_vil1_avicodec::vidl_vil1_avicodec()
00027 {
00028 avi_get_frame_ = NULL;
00029 avi_stream_ = NULL;
00030 avi_file_ = NULL;
00031 encoder_type = ASKUSER;
00032 _fmemset(&opts, 0, sizeof(AVICOMPRESSOPTIONS));
00033 encoder_options_valid=false;
00034 }
00035
00036
00037
00038 vidl_vil1_avicodec::~vidl_vil1_avicodec()
00039 {
00040 if (avi_get_frame_)
00041 AVIStreamGetFrameClose(avi_get_frame_);
00042 if (avi_stream_)
00043 AVIStreamRelease(avi_stream_);
00044 if (avi_file_)
00045 AVIFileRelease(avi_file_);
00046 AVIFileExit();
00047 }
00048
00049
00050
00051 bool vidl_vil1_avicodec::read_header()
00052 {
00053 AVIFileInfo(avi_file_, &avi_file_info_, sizeof(AVIFILEINFO));
00054 AVIStreamInfo(avi_stream_, &avi_stream_info_, sizeof(AVISTREAMINFO));
00055
00056
00057 set_width(avi_file_info_.dwWidth);
00058 if (avi_stream_info_.rcFrame.right != int(avi_file_info_.dwWidth)+avi_stream_info_.rcFrame.left)
00059 {
00060 vcl_cerr << "vidl_vil1_avicodec::read_header width size screwed up\n"
00061 << " size of avi file : " << avi_file_info_.dwWidth
00062 << "\n size of the stream : "
00063 << avi_stream_info_.rcFrame.right-avi_stream_info_.rcFrame.left
00064 << vcl_endl;
00065 }
00066
00067
00068 set_height(avi_file_info_.dwHeight);
00069 if (avi_stream_info_.rcFrame.bottom != int(avi_file_info_.dwHeight)+avi_stream_info_.rcFrame.top)
00070 {
00071 vcl_cerr << "vidl_vil1_avicodec::read_header Height size screwed up"
00072 << "\n size of avi file : " << avi_file_info_.dwHeight
00073 << "\n size of the stream : "
00074 << avi_stream_info_.rcFrame.bottom-avi_stream_info_.rcFrame.top
00075 << vcl_endl;
00076 }
00077
00078
00079 set_number_frames(avi_file_info_.dwLength);
00080
00081
00082
00083
00084
00085
00086 return true;
00087 }
00088
00089
00090 bool vidl_vil1_avicodec::write_header()
00091 {
00092 vcl_fprintf(stderr, "vidl_vil1_avicodec::write_header Not implemented.\n");
00093 return false;
00094 }
00095
00096
00097
00098 bool vidl_vil1_avicodec::get_section(
00099 int position,
00100 void* ib,
00101 int x0,
00102 int y0,
00103 int xs,
00104 int ys) const
00105 {
00106 byte* DIB = (byte*) AVIStreamGetFrame(avi_get_frame_, position);
00107
00108 WORD BitsPerPixel = ((LPBITMAPINFOHEADER)DIB)->biBitCount;
00109 #ifdef DEBUG
00110 vcl_cout << "Number of bits : " << BitsPerPixel << " Number of bytes : " << get_bytes_pixel() << vcl_endl;
00111
00112 WORD ColorsUsed = ((LPBITMAPINFOHEADER)DIB)->biClrUsed;
00113 vcl_cout << "Number of colors used : " << ColorsUsed << vcl_endl;
00114 if (ColorsUsed!=0) vcl_cout << "Not sure we can handle the stream if ColorsUsed!=0\n";
00115 #endif
00116
00117
00118 if ((BitsPerPixel!=16) && (BitsPerPixel!=24))
00119 {
00120 vcl_cerr << "vidl_vil1_avicodec : Don't know how to process a "
00121 << BitsPerPixel<< " bits per pixel AVI File.\n";
00122 return false;
00123 }
00124
00125 DIB += *(LPDWORD)DIB;
00126 byte* StartDIB = (byte*)DIB;
00127
00128
00129 int line_length = (width()*BitsPerPixel+31)/32*4;
00130
00131 if (!ib)
00132 {
00133 ib = new byte[xs*ys*get_bytes_pixel()];
00134 if (!ib) {
00135
00136 return false;
00137 }
00138 }
00139
00140 byte* db = (byte*)ib;
00141
00142
00143
00144 switch (BitsPerPixel)
00145 {
00146 case 24:
00147 for (int j=height()-y0-1; j>=height()-y0-ys; j--)
00148 {
00149 DIB = StartDIB+ (j*line_length)+x0*(BitsPerPixel/8);
00150 for (int i=0; i<xs; i++)
00151 {
00152 *db = *(DIB+2);
00153 *(db+1) = *(DIB+1);
00154 *(db+2) = *(DIB);
00155 db+=3;
00156 DIB+=3;
00157 }
00158 }
00159 break;
00160 case 16:
00161 for (int j=height()-y0-1; j>=height()-y0-ys; j--)
00162 {
00163 DIB = StartDIB + (j*line_length) + x0*(BitsPerPixel/8);
00164 for (int i=0; i<xs; i++)
00165 {
00166 WORD* Pixel16 = (WORD*) DIB;
00167 *db = (BYTE) RGB16R(*Pixel16);
00168 *(db+1) = (BYTE) RGB16G(*Pixel16);
00169 *(db+2) = (BYTE) RGB16B(*Pixel16);
00170 db+=3;
00171 DIB+=2;
00172 }
00173 }
00174 break;
00175 default:
00176 vcl_cerr << "vidl_vil1_avicodec : Don't know how to process a "
00177 << BitsPerPixel << " bits per pixel AVI File.\n";
00178 }
00179
00180 return true;
00181 }
00182
00183
00184
00185
00186
00187
00188 int vidl_vil1_avicodec::put_section(int ,
00189 void* ,
00190 int , int ,
00191 int , int )
00192 {
00193 vcl_cerr << "vidl_vil1_avicodec::put_section not implemented\n";
00194 return -1;
00195 }
00196
00197
00198
00199
00200 bool vidl_vil1_avicodec::probe(vcl_string const& fname)
00201 {
00202 int modenum = OF_READ | OF_SHARE_DENY_WRITE;
00203 AVIFileInit();
00204 if (AVIFileOpen(&avi_file_, fname.c_str(), modenum, 0L)==0)
00205 {
00206
00207
00208 AVIFileRelease(avi_file_);
00209
00210 return true;
00211 }
00212
00213 return false;
00214 }
00215
00216 vidl_vil1_codec_sptr vidl_vil1_avicodec::load(vcl_string const& fname, char mode)
00217 {
00218 int modenum = OF_READ;
00219 DWORD videostreamcode = 0x73646976;
00220
00221 switch (mode) {
00222 case 'r':
00223 modenum = OF_READ | OF_SHARE_DENY_WRITE;
00224 break;
00225 case 'w':
00226 modenum = OF_READWRITE;
00227 break;
00228 }
00229
00230 AVIFileInit();
00231 AVIFileOpen(&avi_file_, fname.c_str(), modenum, 0L);
00232
00233
00234 if (AVIFileGetStream(avi_file_, &avi_stream_, videostreamcode, 0) != AVIERR_OK) {
00235 vcl_cerr << "[vidl_vil1_avicodec: no stream 0]";
00236 }
00237
00238 if (!avi_file_ || !avi_stream_)
00239 {
00240 return NULL;
00241 }
00242
00243 avi_get_frame_ = AVIStreamGetFrameOpen(avi_stream_, NULL);
00244
00245 if (!read_header()) {
00246 vcl_fprintf(stderr, "vidl_vil1_avicodec: error reading header\n");
00247 return NULL;
00248 }
00249
00250 set_format('L');
00251 set_image_class('C');
00252 set_name(vul_file::basename(fname));
00253 set_description(fname);
00254
00255
00256 byte* DIB = (byte*) AVIStreamGetFrame(avi_get_frame_, 0);
00257
00258 if ( ! DIB )
00259 return NULL;
00260
00261
00262
00263 WORD BitsPerPixel = ((LPBITMAPINFOHEADER)DIB)->biBitCount;
00264 LONG iwidth = ((LPBITMAPINFOHEADER)DIB)->biWidth;
00265 LONG iheight = ((LPBITMAPINFOHEADER)DIB)->biHeight;
00266
00267 if (width() != iwidth)
00268 {
00269 vcl_cerr << "vidl_vil1_avicodec::load ohoh, width of the first frame is different from the one specified for the avifile\n"
00270 << " Movie width set with the first frame\n";
00271 set_width(iwidth);
00272 }
00273
00274 if (height() != iheight)
00275 {
00276 vcl_cerr << "vidl_vil1_avicodec::load ohoh, height of the first frame is different from the one specified for the avifile\n"
00277 << " Movie height set with the first frame\n";
00278 set_height(iheight);
00279 }
00280
00281
00282
00283
00284 set_bits_pixel(24);
00285
00286
00287 if ((BitsPerPixel!=16) && (BitsPerPixel!=24))
00288 {
00289 vcl_cerr << "vidl_vil1_avicodec : Don't know how to process a "
00290 << BitsPerPixel << " bits per pixel AVI File.\n";
00291 return NULL;
00292 }
00293
00294 return this;
00295 }
00296
00297
00298 bool vidl_vil1_avicodec::save(vidl_vil1_movie* movie, vcl_string const& fname)
00299 {
00300 PAVIFILE avi_file;
00301 AVISTREAMINFO avi_stream_info;
00302 PAVISTREAM avi_stream = NULL;
00303
00304 HRESULT hr;
00305
00306 AVIFileInit();
00307
00308
00309
00310
00311 hr = AVIFileOpen(&avi_file,
00312 fname.c_str(),
00313 OF_WRITE | OF_CREATE,
00314 NULL);
00315
00316 if (hr != AVIERR_OK) {
00317 vcl_cerr << "vidl_vil1_avicodec : Could not open the file " << fname << " for writing.\n";
00318 if (hr == AVIERR_BADFORMAT)
00319 vcl_cerr << "vidl_vil1_avicodec : The file couldn't be read, indicating a corrupt file or an unrecognized format.\n";
00320 if (hr== AVIERR_MEMORY)
00321 vcl_cerr << "vidl_vil1_avicodec : The file could not be opened because of insufficient memory.\n";
00322 if (hr== AVIERR_FILEREAD)
00323 vcl_cerr << "vidl_vil1_avicodec : A disk error occurred while reading the file.\n";
00324 if (hr== AVIERR_FILEOPEN)
00325 vcl_cerr << "vidl_vil1_avicodec : A disk error occurred while opening the file.\n";
00326 if (hr== REGDB_E_CLASSNOTREG)
00327 {
00328 vcl_cerr << "vidl_vil1_avicodec : According to the registry, the type of file"
00329 << " specified in AVIFileOpen does not have a handler to process it.\n"
00330 << "vidl_vil1_avicodec : This is usually the case when the file name given does not have the .avi extension\n";
00331 }
00332 return false;
00333 }
00334
00335
00336
00337
00338
00339 _fmemset(&avi_stream_info, 0, sizeof(avi_stream_info));
00340 avi_stream_info.fccType = streamtypeVIDEO;
00341 avi_stream_info.fccHandler = 0;
00342 avi_stream_info.dwScale = 1;
00343 avi_stream_info.dwRate = movie->frame_rate();
00344 avi_stream_info.dwLength = movie->length();
00345 avi_stream_info.dwSuggestedBufferSize = movie->width()*movie->height()*3;
00346 SetRect(&avi_stream_info.rcFrame, 0, 0,
00347 (int) movie->width(),
00348 (int) movie->height());
00349
00350
00351 hr = AVIFileCreateStream(avi_file,
00352 &avi_stream,
00353 &avi_stream_info);
00354 if (hr != AVIERR_OK) {
00355 vcl_cerr << "vidl_vil1_avicodec : Could not create the avi stream.\n";
00356 return false;
00357 }
00358
00359 if (encoder_type==ASKUSER)
00360 {
00361
00362 AVICOMPRESSOPTIONS FAR * aopts[1] = {&opts};
00363
00364 if (!AVISaveOptions(NULL, 0, 1, &avi_stream, (LPAVICOMPRESSOPTIONS FAR *) &aopts))
00365 {
00366 vcl_cerr << "vidl_vil1_avicodec : AVI Saving Cancelled.\n";
00367 return false;
00368 }
00369
00370 encoder_options_valid=true;
00371 }
00372
00373 char *fcc=(char *)&(opts.fccHandler);
00374
00375 vcl_cout << "Compressor options:\n"
00376 << "fccHandler = " << fcc[0] << "','" << fcc[1] << "','" << fcc[2] << "','" << fcc[3] << "'\n"
00377 << "key frame every = " << opts.dwKeyFrameEvery << vcl_endl
00378 << "quality = " << opts.dwQuality << vcl_endl
00379 << "flags = " << opts.dwFlags << vcl_endl;
00380 if (opts.dwFlags & AVICOMPRESSF_DATARATE)
00381 vcl_cout << " AVICOMPRESSF_DATARATE\n";
00382 if (opts.dwFlags & AVICOMPRESSF_INTERLEAVE)
00383 vcl_cout << " AVICOMPRESSF_INTERLEAVE\n";
00384 if (opts.dwFlags & AVICOMPRESSF_KEYFRAMES)
00385 vcl_cout << " AVICOMPRESSF_KEYFRAMES\n";
00386 if (opts.dwFlags & AVICOMPRESSF_VALID)
00387 vcl_cout << " AVICOMPRESSF_VALID\n";
00388 vcl_cout << "lpFormat = " << opts.lpFormat << vcl_endl
00389 << "cbFormat = " << opts.cbFormat << vcl_endl
00390 << "lpParms = " << opts.lpParms << vcl_endl
00391 << "cbParms = " << opts.cbParms << vcl_endl
00392 << "dwInterleaveEvery= " << opts.dwInterleaveEvery << vcl_endl;
00393
00394 PAVISTREAM avi_stream_compressed = NULL;
00395 hr = AVIMakeCompressedStream(&avi_stream_compressed, avi_stream, &opts, NULL);
00396 if (hr != AVIERR_OK)
00397 return false;
00398
00399
00400 {
00401 LPBITMAPINFOHEADER lpbi =
00402 (LPBITMAPINFOHEADER)GlobalLock(make_dib(movie->get_frame(0), 24));
00403 if (!lpbi)
00404 {
00405 vcl_cerr << "vidl_vil1_avicodec : DIB (Device Independent Bitmap) creation failed.\n";
00406 return false;
00407 }
00408 hr = AVIStreamSetFormat(avi_stream_compressed, 0,
00409 lpbi,
00410 lpbi->biSize +
00411 lpbi->biClrUsed * sizeof(RGBQUAD));
00412 if (hr != AVIERR_OK)
00413 {
00414 vcl_cerr << "vidl_vil1_avicodec : Could not set the AVI stream format.\n"
00415 << " The chosen compression mode may not be installed well.\n";
00416 return false;
00417 }
00418 }
00419
00420
00421 int i = 0;
00422 for (vidl_vil1_movie::frame_iterator pframe = movie->begin();
00423 pframe <= movie->last();
00424 ++pframe, ++i)
00425 {
00426 LPBITMAPINFOHEADER lpbi =
00427 (LPBITMAPINFOHEADER)GlobalLock(make_dib(pframe, 24));
00428 if (!lpbi)
00429 {
00430 vcl_cerr << "vidl_vil1_avicodec : DIB (Device Independent Bitmap) creation failed.\n"
00431 << "vidl_vil1_avicodec : Frame number " << i << vcl_endl;
00432 return false;
00433 }
00434
00435 int time = i;
00436 hr = AVIStreamWrite(avi_stream_compressed,
00437 time,
00438 1,
00439 (LPBYTE) lpbi +
00440 lpbi->biSize +
00441 lpbi->biClrUsed * sizeof(RGBQUAD),
00442 lpbi->biSizeImage,
00443 AVIIF_KEYFRAME,
00444 NULL,
00445 NULL);
00446 if (hr != AVIERR_OK)
00447 {
00448 vcl_cerr << "vidl_vil1_avicodec : Could not write to the AVI stream.\n";
00449 return false;
00450 }
00451 }
00452
00453 if (avi_stream)
00454 AVIStreamRelease(avi_stream);
00455 if (avi_stream_compressed)
00456 AVIStreamRelease(avi_stream_compressed);
00457 if (avi_file)
00458 AVIFileRelease(avi_file);
00459 AVIFileExit();
00460
00461
00462 return true;
00463 }
00464
00465 #if 0
00466
00467 unsigned int vidl_vil1_avicodec::fccHandlerCoder(char c0, char c1, char c2, char c3)
00468 {
00469 unsigned int code;
00470
00471 char *codeStr=(char *)(&code);
00472 codeStr[0]=c0;
00473 codeStr[1]=c1;
00474 codeStr[2]=c2;
00475 codeStr[3]=c3;
00476
00477 return code
00478 }
00479 #endif // 0
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493 void vidl_vil1_avicodec::choose_encoder(AVIEncoderType encoder)
00494 {
00495 encoder_type=encoder;
00496
00497 if (encoder_type==ASKUSER ||
00498 (encoder_type==USEPREVIOUS && encoder_options_valid))
00499 return;
00500
00501 encoder_options_valid=true;
00502
00503 switch (encoder_type)
00504 {
00505 case USEPREVIOUS:
00506 case UNCOMPRESSED:
00507 opts.fccType=streamtypeVIDEO;
00508 opts.fccHandler=mmioFOURCC('D','I','B',' ');
00509 opts.dwKeyFrameEvery=0;
00510 opts.dwQuality=0;
00511 opts.dwFlags=AVICOMPRESSF_VALID;
00512 opts.lpFormat=0;
00513 opts.cbFormat=0;
00514 opts.lpParms=0;
00515 opts.cbParms=0;
00516 opts.dwInterleaveEvery=0;
00517 break;
00518 case CINEPACK:
00519 opts.fccType=streamtypeVIDEO;
00520 opts.fccHandler=mmioFOURCC('c','v','i','d');
00521 opts.dwKeyFrameEvery=0;
00522 opts.dwQuality=10000;
00523 opts.dwFlags=AVICOMPRESSF_VALID;
00524 opts.lpFormat=0;
00525 opts.cbFormat=0;
00526
00527
00528
00529
00530
00531
00532 opts.lpParms=0;
00533 opts.cbParms=0;
00534 opts.dwInterleaveEvery=0;
00535 break;
00536 default:
00537 encoder_options_valid=false;
00538 }
00539 }
00540
00541
00542
00543 HANDLE vidl_vil1_avicodec::make_dib(vidl_vil1_frame_sptr frame, UINT bits)
00544 {
00545
00546
00547 byte* TjSection = new byte[frame->width() * frame->height() * frame->get_bytes_pixel()];
00548 if (!frame->get_section(TjSection, 0, 0, frame->width(), frame->height()) )
00549 vcl_cerr << "vidl_vil1_avicodec::make_dib--Could not read get section\n";
00550
00551
00552
00553
00554
00555
00556
00557 int line_length = (frame->width()*bits+31)/32 * 4;
00558
00559 int data_size = line_length*frame->height()*(bits/8);
00560
00561 byte* newbits = new byte[data_size];
00562 byte* db = (byte*) newbits;
00563 int i,j;
00564 for (i=0; i<data_size; i++)
00565 {
00566 *db = 0;
00567 ++db;
00568 }
00569
00570
00571 switch (frame->get_bytes_pixel())
00572 {
00573 case 3:
00574 for (j=frame->height()-1; j>=0;j--)
00575 {
00576 db = TjSection+ (j*frame->width())*frame->get_bytes_pixel();
00577 byte* DIB = newbits + (frame->height()-j-1)*line_length;
00578 for (i=0; i<frame->width(); ++i, DIB+=3, db+=3) {
00579 *DIB = *(db+2);
00580 *(DIB+1) = *(db+1);
00581 *(DIB+2) = *(db);
00582 }
00583 }
00584 break;
00585 case 1:
00586 for (j=frame->height()-1; j>=0;j--)
00587 {
00588 db = TjSection+ (j*frame->width())*frame->get_bytes_pixel();
00589 byte* DIB = newbits + (frame->height()-j-1)*line_length;
00590 for (i=0; i<frame->width(); ++i, DIB+=3, db+=1) {
00591 *DIB = *(db);
00592 *(DIB+1) = *(db);
00593 *(DIB+2) = *(db);
00594 }
00595 }
00596 break;
00597 default:
00598 vcl_cerr << "vidl_vil1_avicodec : Don't know how to deal with "
00599 << frame->get_bytes_pixel() << " bytes per pixel.\n";
00600
00601 }
00602
00603
00604 delete[] TjSection;
00605
00606
00607 HDC hdc = GetDC(NULL);
00608 HBITMAP hbitmap;
00609 if (!(hbitmap = CreateCompatibleBitmap(hdc,frame->width(),frame->height())))
00610 {
00611 vcl_cerr << "vidl_vil1_avicodec : Could not create a compatible bitmap for frame.\n";
00612 return NULL;
00613 }
00614 BITMAP bitmap;
00615 GetObject(hbitmap,sizeof(BITMAP),&bitmap);
00616 int wColSize = sizeof(RGBQUAD)*((bits <= 8) ? 1<<bits : 0);
00617 int dwSize = sizeof(BITMAPINFOHEADER) + wColSize +
00618 (DWORD)(UINT)line_length*(DWORD)(UINT)bitmap.bmHeight;
00619
00620
00621
00622
00623 HANDLE hdib = GlobalAlloc(GHND,dwSize);
00624 if (!hdib)
00625 return hdib;
00626
00627 LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);
00628
00629 lpbi->biSize = sizeof(BITMAPINFOHEADER);
00630 lpbi->biWidth = bitmap.bmWidth;
00631 lpbi->biHeight = bitmap.bmHeight;
00632 lpbi->biPlanes = 1;
00633 lpbi->biBitCount = (WORD) bits;
00634 lpbi->biCompression = BI_RGB;
00635 lpbi->biSizeImage = dwSize - sizeof(BITMAPINFOHEADER) - wColSize;
00636 lpbi->biXPelsPerMeter = 0;
00637 lpbi->biYPelsPerMeter = 0;
00638 lpbi->biClrUsed = (bits <= 8) ? 1<<bits : 0;
00639 lpbi->biClrImportant = 0;
00640
00641 hdc = CreateCompatibleDC(NULL);
00642
00643
00644 int error_code = SetDIBits(hdc,hbitmap,0,bitmap.bmHeight,newbits,(LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
00645 if (!error_code)
00646 {
00647 vcl_cerr << "vidl_vil1_avicodec : Could set the bits in the BitMap.\n";
00648 return NULL;
00649 }
00650
00651
00652
00653
00654 LPBYTE lpBits = (LPBYTE)(lpbi+1)+wColSize;
00655
00656
00657 error_code = GetDIBits(hdc,hbitmap,0,bitmap.bmHeight,lpBits,(LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
00658 if (!error_code)
00659 {
00660 vcl_cerr << "vidl_vil1_avicodec : Could set the bits in the DIB (Device Independent Bitmap).\n";
00661 return NULL;
00662 }
00663
00664
00665 lpbi->biClrUsed = (bits <= 8) ? 1<<bits : 0;
00666
00667
00668 DeleteBitmap(hbitmap);
00669 delete [] newbits;
00670 ReleaseDC(NULL,hdc);
00671 GlobalUnlock(hdib);
00672
00673 return hdib;
00674 }