00001 
00032 
00033 
00034 
00035 
00036 #include "llviewerprecompiledheaders.h"
00037 
00038 #include "moviemaker.h"
00039 #include <memory>
00040 #include "llmemtype.h"
00041 
00042 #if LL_WINDOWS
00043 
00044 #include <windowsx.h>
00045 
00046 HANDLE  MakeDib( HBITMAP hbitmap, UINT bits );
00047 HBITMAP LoadBMPFromFB( int w, int h );
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 MovieMaker::MovieMaker()
00057 {
00058     snprintf( fname, sizeof(fname), "movie.avi" );              
00059     width  = -1;
00060     height = -1;
00061 
00062     bOK = true;
00063     nFrames = 0;
00064 
00065         pfile = NULL;
00066         ps = NULL;
00067         psCompressed = NULL;
00068         psText = NULL;
00069         aopts[0] = &opts;
00070 
00071     
00072         WORD wVer = HIWORD( VideoForWindowsVersion() );
00073         if ( wVer < 0x010A )
00074         {
00075         fprintf( stderr, "VFW version is too old.\n" );
00076         exit( -1 );
00077             }
00078         else
00079             {
00080                 AVIFileInit();
00081             }
00082 }
00083 
00084 
00085 MovieMaker::~MovieMaker()
00086 {
00087         if (ps)
00088                 AVIStreamClose(ps);
00089 
00090         if (psCompressed)
00091                 AVIStreamClose(psCompressed);
00092 
00093         if (psText)
00094                 AVIStreamClose(psText);
00095 
00096         if (pfile)
00097         {
00098                 AVIFileClose(pfile);
00099         }
00100 
00101         WORD wVer = HIWORD(VideoForWindowsVersion());
00102         if (wVer >= 0x010A)
00103             {
00104                 AVIFileExit();
00105             }
00106 }
00107 
00108 void MovieMaker::StartCapture( char *name , int x, int y)
00109 {
00110     strncpy( fname, name, sizeof(fname) -1 );           
00111     fname[sizeof(fname) -1] = '\0';
00112 
00113     
00114     width = x;
00115     height = y;
00116 
00117     fprintf( stderr, "Starting %d x %d capture to file: %s\n", width, height, fname );
00118 
00119         bOK = TRUE;
00120 
00121         nFrames = 0;
00122 
00123 }
00124 
00125 void MovieMaker::EndCapture()
00126 {
00127     fprintf( stderr, "\n" );
00128         if (ps)
00129         {
00130                 AVIStreamClose(ps);
00131         ps = NULL;
00132         }
00133 
00134         if (psCompressed)
00135         {
00136                 AVIStreamClose(psCompressed);
00137         psCompressed = NULL;
00138         }
00139 
00140         if (psText)
00141         {
00142                 AVIStreamClose(psText);
00143         psText = NULL;
00144         }
00145 
00146         if (pfile)
00147         {
00148                 AVIFileClose(pfile);
00149         pfile = NULL;
00150         }
00151 
00152         WORD wVer = HIWORD(VideoForWindowsVersion());
00153         if (wVer >= 0x010A)
00154             {
00155                 AVIFileExit();
00156             }
00157 
00158 }
00159 
00160 bool MovieMaker::Snap()
00161 {
00162         HRESULT hr;
00163 
00164         if (!bOK)
00165                 return false;
00166 
00167     
00168     HBITMAP bmp;
00169     bmp = LoadBMPFromFB( width, height );
00170 
00171         LPBITMAPINFOHEADER alpbi = (LPBITMAPINFOHEADER)GlobalLock(MakeDib(bmp, 32));
00172     DeleteObject( bmp );
00173 
00174         if (alpbi == NULL)
00175         {
00176         bOK = false;
00177                 return false;
00178         }
00179         if (width>=0 && width != alpbi->biWidth)
00180         {
00181                 GlobalFreePtr(alpbi);
00182         bOK = false;
00183                 return false;
00184         }
00185         if (height>=0 && height != alpbi->biHeight)
00186         {
00187                 GlobalFreePtr(alpbi);
00188         bOK = false;
00189                 return false;
00190         }
00191         width = alpbi->biWidth;
00192         height = alpbi->biHeight;
00193         if (nFrames == 0)
00194         {
00195                 hr = AVIFileOpenA(&pfile,                   
00196                                fname,                                                   
00197                                    OF_WRITE | OF_CREATE,                    
00198                                    NULL);                                                       
00199                                                                                                         
00200                 if (hr != AVIERR_OK)
00201                 {
00202                         GlobalFreePtr(alpbi);
00203                         bOK = false;
00204                         return false;
00205                 }
00206                 _fmemset(&strhdr, 0, sizeof(strhdr));
00207                 strhdr.fccType                = streamtypeVIDEO;
00208                 strhdr.fccHandler             = 0;
00209                 strhdr.dwScale                = 1;
00210                 strhdr.dwRate                 = 15;
00211                 strhdr.dwSuggestedBufferSize  = alpbi->biSizeImage;
00212                 SetRect(&strhdr.rcFrame, 0, 0,              
00213                         (int) alpbi->biWidth,
00214                         (int) alpbi->biHeight);
00215 
00216                 
00217                 hr = AVIFileCreateStream(pfile,             
00218                                                          &ps,               
00219                                                                  &strhdr);          
00220                 if (hr != AVIERR_OK)
00221                 {
00222                         GlobalFreePtr(alpbi);
00223                         bOK = false;
00224                         return false;
00225                 }
00226 
00227                 _fmemset(&opts, 0, sizeof(opts));
00228 
00229                 if (!AVISaveOptions(NULL, ICMF_CHOOSE_KEYFRAME, 1, &ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts))
00230                 {
00231             fprintf( stderr, "AVISaveOptions failed.\n" );
00232                         GlobalFreePtr(alpbi);
00233                         bOK = false;
00234                         return false;
00235                 }
00236 
00237                 hr = AVIMakeCompressedStream(&psCompressed, ps, &opts, NULL);
00238                 if (hr != AVIERR_OK)
00239                 {
00240             fprintf( stderr, "AVIMakeCompressedStream failed.\n" );
00241                         GlobalFreePtr(alpbi);
00242                         bOK = false;
00243                         return false;
00244                 }
00245 
00246                 hr = AVIStreamSetFormat(psCompressed, 0,
00247                                            alpbi,           
00248                                        alpbi->biSize +   
00249                                        alpbi->biClrUsed * sizeof(RGBQUAD));
00250                 if (hr != AVIERR_OK)
00251                 {
00252             fprintf( stderr, "AVIStreamSetFormat failed.\n" );
00253                         GlobalFreePtr(alpbi);
00254                         bOK = false;
00255                         return false;
00256                 }
00257 
00258                 
00259 
00260                 
00261 
00262 
00263 
00264 
00265 
00266 
00267 
00268 
00269 
00270 
00271 
00272 
00273 
00274 
00275 
00276 
00277 
00278 
00279 
00280 
00281 
00282 
00283 
00284 
00285 
00286 
00287 
00288 
00289         }
00290 
00291         
00292         hr = AVIStreamWrite(psCompressed,       
00293                 nFrames * 1, 
00294                 1,                              
00295                 (LPBYTE) alpbi +                
00296                         alpbi->biSize +
00297                         alpbi->biClrUsed * sizeof(RGBQUAD),
00298                         alpbi->biSizeImage,     
00299                 AVIIF_KEYFRAME,                  
00300                 NULL,
00301                 NULL);
00302         if (hr != AVIERR_OK)
00303         {
00304         fprintf( stderr, "AVIStreamWrite failed.\n" );
00305                 GlobalFreePtr(alpbi);
00306                 bOK = false;
00307                 return false;
00308         }
00309 
00310         
00311         
00312         
00313 
00314 
00315 
00316 
00317 
00318 
00319 
00320 
00321 
00322 
00323 
00324 
00325 
00326 
00327 
00328 
00329 
00330 
00331 
00332 
00333         GlobalFreePtr(alpbi);
00334 
00335         nFrames++;
00336 
00337     fprintf( stderr, "Wrote frame %d.\r", nFrames );
00338 
00339         return true;
00340 }
00341 
00342 static HANDLE  MakeDib( HBITMAP hbitmap, UINT bits )
00343 {
00344         HANDLE              hdib ;
00345         HDC                 hdc ;
00346         BITMAP              bitmap ;
00347         UINT                wLineLen ;
00348         DWORD               dwSize ;
00349         DWORD               wColSize ;
00350         LPBITMAPINFOHEADER  lpbi ;
00351         LPBYTE              lpBits ;
00352         
00353         GetObject(hbitmap,sizeof(BITMAP),&bitmap) ;
00354 
00355         
00356         
00357         
00358         
00359         
00360         wLineLen = (bitmap.bmWidth*bits+31)/32 * 4;
00361         wColSize = sizeof(RGBQUAD)*((bits <= 8) ? 1<<bits : 0);
00362         dwSize = sizeof(BITMAPINFOHEADER) + wColSize +
00363                 (DWORD)(UINT)wLineLen*(DWORD)(UINT)bitmap.bmHeight;
00364 
00365         
00366         
00367         
00368         hdib = GlobalAlloc(GHND,dwSize);
00369         if (!hdib)
00370                 return hdib ;
00371 
00372         lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib) ;
00373 
00374         lpbi->biSize = sizeof(BITMAPINFOHEADER) ;
00375         lpbi->biWidth = bitmap.bmWidth ;
00376         lpbi->biHeight = bitmap.bmHeight ;
00377         lpbi->biPlanes = 1 ;
00378         lpbi->biBitCount = (WORD) bits ;
00379         lpbi->biCompression = BI_RGB ;
00380         lpbi->biSizeImage = dwSize - sizeof(BITMAPINFOHEADER) - wColSize ;
00381         lpbi->biXPelsPerMeter = 0 ;
00382         lpbi->biYPelsPerMeter = 0 ;
00383         lpbi->biClrUsed = (bits <= 8) ? 1<<bits : 0;
00384         lpbi->biClrImportant = 0 ;
00385 
00386         
00387         
00388         
00389         lpBits = (LPBYTE)(lpbi+1)+wColSize ;
00390 
00391         hdc = CreateCompatibleDC(NULL) ;
00392 
00393         GetDIBits(hdc,hbitmap,0,bitmap.bmHeight,lpBits,(LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
00394 
00395         
00396         lpbi->biClrUsed = (bits <= 8) ? 1<<bits : 0;
00397 
00398         DeleteDC(hdc) ;
00399         GlobalUnlock(hdib);
00400 
00401         return hdib ;
00402 }
00403 
00404 
00405 static HBITMAP LoadBMPFromFB( int w, int h )
00406 {
00407     
00408     
00409     
00410     
00411  
00412     HDC hdcScreen = wglGetCurrentDC();
00413     HDC hdcCompatible = CreateCompatibleDC(hdcScreen); 
00414  
00415     
00416 
00417     HBITMAP hbmScreen = CreateCompatibleBitmap(hdcScreen, 
00418                            
00419                            
00420                              w, 
00421                              h ); 
00422 
00423     if (hbmScreen == 0)
00424         {
00425         fprintf( stderr, "hbmScreen == NULL\nExiting.\n" );
00426         exit( -1 );
00427         
00428         }
00429  
00430     
00431  
00432     if (!SelectObject(hdcCompatible, hbmScreen)) 
00433         {
00434         fprintf( stderr, "Couldn't SelectObject()\nExiting.\n" );
00435         exit( -1 );
00436         
00437         }
00438  
00439     
00440  
00441      
00442  
00443     
00444     
00445  
00446     if (!BitBlt(hdcCompatible, 
00447                  0,0, 
00448                  w, h, 
00449                  hdcScreen, 
00450                 
00451                  0, 0,
00452                  SRCCOPY)) 
00453         {
00454         fprintf( stderr, "Screen to Compat Blt Failed\nExiting.\n" );
00455         exit( -1 );
00456         
00457         }
00458  
00459    
00460    
00461 
00462     DeleteDC( hdcCompatible );
00463 
00464     return( hbmScreen );
00465 }
00466 
00467 #elif LL_DARWIN
00468 
00469  #include <AGL/agl.h>
00470  #include <AGL/gl.h>
00471  #include <AGL/glu.h>
00472 
00473 
00474 #ifdef verify
00475         #undef verify
00476 #endif
00477 
00478 #include "llviewerwindow.h"
00479 #include "llworld.h"
00480 
00481 MovieMaker::MovieMaker()
00482 {
00483         movie = NULL;
00484         movieResRef = 0;
00485         track = NULL;
00486         media = NULL;
00487         width = 0;
00488         height = 0;
00489         bufferSize = 0;
00490         rowBytes = 0;
00491         buffer = NULL;
00492         invertedBuffer = NULL;
00493         ci = NULL;
00494         gworld = NULL;
00495         idh = NULL;
00496 }
00497 
00498 MovieMaker::~MovieMaker()
00499 {
00500         EndCapture();
00501 }
00502 
00503 void MovieMaker::StartCapture( char *name , int x, int y)
00504 {
00505     strncpy( fname, name, sizeof(fname));               
00506         width = x;
00507         height = y;
00508         
00509         setupMovie();
00510 }
00511 
00512 OSStatus MovieMaker::setupMovie()
00513 {
00514         OSStatus        error = noErr;
00515         FSRef           fileRef;
00516         FSSpec          fileSpec;
00517         
00518         rowBytes = width * 4;
00519         bufferSize = height * rowBytes;
00520         LLMemType mt(LLMemType::MTYPE_SCRIPT);
00521         buffer = (char*) new char(bufferSize);
00522         invertedBuffer = (char*) new char(bufferSize);
00523 
00524         rect.left = 0;
00525         rect.top = 0;
00526         rect.right = width;
00527         rect.bottom = height;
00528         
00529         error = NewGWorldFromPtr(&gworld, k32ARGBPixelFormat, &rect, 0, 0, 0, buffer, rowBytes);
00530 
00531         if (error == noErr)
00532         {
00533                 LockPixels(GetGWorldPixMap(gworld));
00534         }
00535 
00536 
00537 
00538 
00539 
00540 
00541 
00542 
00543         if (error == noErr)
00544         {
00545                 error = EnterMovies();
00546         }
00547         
00548         if (error == noErr)
00549         {
00550                 ci = OpenDefaultComponent(StandardCompressionType,StandardCompressionSubType);
00551                 if(ci == NULL)
00552                         error = paramErr;
00553         }
00554                 
00555         if (error == noErr)
00556         {
00557                 long flags;
00558                 
00559                 SCGetInfo(ci,scPreferenceFlagsType,&flags);
00560                 flags &= ~scShowBestDepth;
00561                 flags |= scAllowZeroFrameRate;
00562                 SCSetInfo(ci,scPreferenceFlagsType,&flags);
00563         }
00564 
00565         if (error == noErr)
00566         {
00567                 send_agent_pause();
00568                 gViewerWindow->mWindow->beforeDialog();
00569 
00570                 error = SCRequestSequenceSettings(ci);
00571 
00572                 gViewerWindow->mWindow->afterDialog();
00573                 send_agent_resume();
00574 
00575                 if (error == scUserCancelled) 
00576                 {
00577                         
00578                         EndCapture();
00579                 }
00580         }
00581         
00582         if (error == noErr)
00583         {
00584                 
00585                 FILE* file = LLFile::fopen(fname, "w");         
00586                 if (file)
00587                 {
00588                         fclose(file);
00589                         
00590                         error = FSPathMakeRef((UInt8*)fname, &fileRef, NULL);
00591                         if (error == noErr)
00592                                 error = FSGetCatalogInfo(&fileRef, 0, NULL, NULL, &fileSpec, NULL);
00593                 }
00594                 else
00595                 {
00596                         error = paramErr;
00597                 }
00598         }
00599         
00600         if (error == noErr)
00601         {
00602                 error = CreateMovieFile(&fileSpec, 'TVOD', smCurrentScript, createMovieFileDeleteCurFile | createMovieFileDontCreateResFile, &movieResRef, &movie);
00603         }
00604         
00605         if (error == noErr)
00606         {
00607                 track = NewMovieTrack(movie, FixRatio(width, 1), FixRatio(height, 1), kNoVolume);
00608                 error = GetMoviesError();
00609         }
00610         
00611         if (error == noErr)
00612         {
00613                 media = NewTrackMedia(track, VideoMediaType, 600, NULL, 0);
00614                 error = GetMoviesError();
00615         }
00616         
00617         if (error == noErr)
00618         {
00619                 Microseconds(&lastFrameTime);
00620                 error = grabFrame();
00621         }
00622 
00623         if (error == noErr)
00624         {
00625                 error = SCCompressSequenceBegin(ci,GetPortPixMap(gworld),nil,&idh);
00626         }
00627 
00628         if (error == noErr)
00629         {
00630                 error = BeginMediaEdits(media);
00631         }
00632         
00633         if (error != noErr)
00634         {
00635                 media = NULL;
00636         }
00637         
00638         return error;
00639 }
00640 
00641 void MovieMaker::EndCapture()
00642 {
00643         OSStatus        error = noErr;
00644 
00645         if (movie && movieResRef)
00646         {
00647                 if (media && track)
00648                 {
00649                         
00650                         (void)addFrame();
00651                         
00652                         error = EndMediaEdits(media);
00653                         if (error == noErr)
00654                         {
00655                                 error = SCCompressSequenceEnd(ci);
00656                         }
00657 
00658                         if (error == noErr)
00659                         {
00660                                 error = InsertMediaIntoTrack(track, 0, 0, GetMediaDuration(media), fixed1);
00661                         }
00662                         media = NULL;
00663                         track = NULL;
00664                 }
00665                 
00666                 short resId = movieInDataForkResID;
00667                 error = AddMovieResource(movie, movieResRef, &resId, "\pSecond Life");
00668                 CloseMovieFile(movieResRef);
00669                 movieResRef = 0;
00670                 movie = NULL;
00671         }
00672         
00673         
00674         idh = NULL;
00675         
00676         if(ci)
00677         {
00678                 CloseComponent(ci);
00679                 ci = NULL;
00680         }
00681         
00682         if(gworld)
00683         {
00684                 DisposeGWorld(gworld);
00685                 gworld = NULL;
00686         }
00687 
00688         if(buffer)
00689         {
00690                 delete(buffer);
00691                 buffer = NULL;
00692         }
00693 
00694         if(invertedBuffer)
00695         {
00696                 delete(invertedBuffer);
00697                 invertedBuffer = NULL;
00698         }
00699 }
00700 
00701 OSStatus MovieMaker::grabFrame()
00702 {
00703         OSStatus        error = noErr;
00704         GLenum          glerr;
00705         
00706         
00707         glReadBuffer(GL_BACK);
00708         glReadPixels(0 ,0, width, height,  
00709 #ifdef LL_BIG_ENDIAN    
00710         
00711         GL_BGRA,
00712         GL_UNSIGNED_INT_8_8_8_8_REV,
00713 #else                           
00714         
00715         GL_BGRA,
00716         GL_UNSIGNED_INT_8_8_8_8,
00717 #endif  
00718         invertedBuffer);
00719         glerr = glGetError();
00720         
00721         
00722         if (glerr == GL_NO_ERROR)
00723         {
00724                 long i, j;
00725                 
00726                 i = j = 0;
00727                         
00728                 
00729                 for (i = 0, j = bufferSize - rowBytes; i < bufferSize; i += rowBytes, j -= rowBytes)
00730                         BlockMoveData(&invertedBuffer[i], &buffer[j], rowBytes);
00731         }
00732         else
00733         {
00734                 error = paramErr;
00735         }
00736         
00737         return error;
00738 }
00739 
00740 OSStatus MovieMaker::addFrame()
00741 {
00742         OSStatus        error = noErr;
00743         Handle  compressedData;
00744         short   syncFlag;
00745         long    dataSize;
00746         UnsignedWide now;
00747 
00748         CGrafPtr oldPort;
00749         GDHandle oldGDeviceH;
00750 
00751         GetGWorld(&oldPort, &oldGDeviceH);
00752         SetGWorld(gworld, nil);
00753         
00754         
00755 
00756         error = SCCompressSequenceFrame(ci,GetPortPixMap(gworld),&rect,&compressedData,&dataSize,&syncFlag);
00757         
00758         Microseconds(&now);
00759 
00760         if (error == noErr)
00761         {
00762                 double duration = (now.lo - lastFrameTime.lo);  
00763                 duration *= GetMovieTimeScale(movie);   
00764                 duration *= 1.0 / 1000000.0;                            
00765 
00766                 error = AddMediaSample(
00767                                 media,
00768                                 compressedData,
00769                                 0,
00770                                 dataSize,
00771                                 (TimeValue)duration,
00772                                 (SampleDescriptionHandle)idh,
00773                                 1,
00774                                 syncFlag,
00775                                 nil);
00776                 
00777         }
00778 
00779         lastFrameTime = now;
00780 
00781         SetGWorld(oldPort, oldGDeviceH);
00782         
00783         return error;
00784 }
00785 
00786 bool MovieMaker::Snap()
00787 {
00788         bool    result = false;
00789         
00790         if (movie && movieResRef && media && track)
00791         {
00792                 OSStatus error = noErr;
00793                 
00794                 error = addFrame();
00795                 
00796                 if (error == noErr)
00797                 {
00798                         error = grabFrame();
00799                 }
00800 
00801                 if (error == noErr)
00802                 {
00803                         result = true;
00804                 }
00805         }
00806         
00807         return result;
00808 }
00809 
00810 #endif
00811