00001
00032 #include "linden_common.h"
00033
00034 #if LL_QUICKTIME_ENABLED
00035
00036 #include <iostream>
00037
00038 #include "llmediaimplquicktime.h"
00039
00040 #include "llgl.h"
00041 #include "llglheaders.h"
00042
00044
00045 LLMediaImplQuickTime::
00046 LLMediaImplQuickTime () :
00047 theController ( NULL ),
00048 currentMode ( ModeIdle ),
00049 theGWorld ( 0 ),
00050 theMovie ( 0 ),
00051 mediaData ( 0 ),
00052 loopsLeft ( 0 ),
00053 ownBuffer ( TRUE ),
00054 curVolume ( 0 ),
00055 sizeChangeInProgress ( FALSE ),
00056 initialStartDone ( FALSE ),
00057 autoScaled ( FALSE )
00058 {
00059
00060 #if LL_DARWIN
00061
00062 mMediaDepthBytes = 4;
00063 mTextureDepth = 4;
00064 mTextureFormatInternal = GL_RGB8;
00065 mTextureFormatPrimary = GL_BGRA;
00066 #ifdef LL_BIG_ENDIAN
00067 mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV;
00068 #else
00069 mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8;
00070 #endif
00071
00072 #else
00073
00074 mMediaDepthBytes = 3;
00075 mTextureDepth = 3;
00076 mTextureFormatInternal = GL_RGB8;
00077 mTextureFormatPrimary = GL_RGB;
00078 mTextureFormatType = GL_UNSIGNED_BYTE;
00079 #endif
00080 };
00081
00083
00084 LLMediaImplQuickTime::
00085 ~LLMediaImplQuickTime ()
00086 {
00087 unload();
00088 }
00089
00091
00092 BOOL
00093 LLMediaImplQuickTime::
00094 setBuffer ( U8* bufferIn )
00095 {
00096 OSErr err = noErr;
00097
00098
00099 sizeChangeInProgress = FALSE;
00100
00101
00102 U8* oldMediaData = mediaData;
00103 BOOL ownedMediaData = ownBuffer;
00104 #if LL_DARWIN
00105 GWorldPtr oldGWorld = theGWorld;
00106 #endif
00107
00108 if(bufferIn == NULL)
00109 {
00110
00111 mediaData = new unsigned char [ mMediaHeight * mMediaRowbytes ];
00112 ownBuffer = TRUE;
00113 }
00114 else
00115 {
00116
00117 mediaData = bufferIn;
00118 ownBuffer = FALSE;
00119 }
00120
00121 if(mediaData == NULL)
00122 {
00123
00124 llerrs << "LLMediaImplQuickTime::setBuffer: mediaData is NULL" << llendl;
00125
00126
00127 return FALSE;
00128 }
00129
00130 err = NewGWorldFromPtr ( &theGWorld, mMediaDepthBytes * 8, &movieRect, NULL, NULL, 0, (Ptr)mediaData, mMediaRowbytes);
00131 if(err == noErr)
00132 {
00133 if(theMovie)
00134 {
00135
00136 SetMovieGWorld ( theMovie, theGWorld, GetGWorldDevice ( theGWorld ) );
00137 }
00138
00139 if(theController)
00140 {
00141
00142 MCSetControllerPort(theController, theGWorld);
00143 }
00144
00145 #if LL_DARWIN
00146
00147
00148
00149 if ( oldGWorld != NULL )
00150 {
00151
00152 DisposeGWorld ( oldGWorld );
00153 oldGWorld = NULL;
00154 }
00155 #endif
00156 }
00157 else
00158 {
00159
00160 llerrs << "LLMediaImplQuickTime::setBuffer: NewGWorldFromPtr failed" << llendl;
00161 theGWorld = NULL;
00162 return FALSE;
00163 }
00164
00165
00166 if ( ownedMediaData )
00167 {
00168 if ( oldMediaData )
00169 {
00170 delete [] oldMediaData;
00171 }
00172 }
00173
00174
00175
00176 return TRUE;
00177 }
00178
00180
00181 BOOL
00182 LLMediaImplQuickTime::
00183 init ()
00184 {
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 return LLMediaMovieBase::init();
00198 }
00199
00201
00202 void
00203 LLMediaImplQuickTime::
00204 updateMediaSize()
00205 {
00206 if((theController == NULL) && (!isQTLoaded()))
00207 {
00208
00209
00210 movieRect.left = movieRect.top = 0;
00211 movieRect.right = movieRect.bottom = 64;
00212 mMediaRowbytes = mMediaDepthBytes * 64;
00213 mMediaWidth = 64;
00214 mMediaHeight = 64;
00215 mTextureWidth = 64;
00216 mTextureHeight = 64;
00217
00218 return;
00219 }
00220
00221
00222 GetMovieBox ( theMovie, &movieRect );
00223
00224
00225 mMediaWidth = movieRect.right - movieRect.left;
00226 mMediaHeight = movieRect.bottom - movieRect.top;
00227
00228
00229
00230
00231 if(mMediaWidth > 1024)
00232 {
00233 mMediaWidth = 1024;
00234 }
00235 if(mMediaHeight > 1024)
00236 {
00237 mMediaHeight = 1024;
00238 }
00239
00240
00241 for ( mTextureWidth = 1; mTextureWidth < mMediaWidth; mTextureWidth <<= 1 )
00242 {
00243 };
00244
00245 for ( mTextureHeight = 1; mTextureHeight < mMediaHeight; mTextureHeight <<= 1 )
00246 {
00247 };
00248
00249
00250
00251
00252 if ( autoScaled )
00253 {
00254
00255 mMediaWidth = mTextureWidth;
00256 mMediaHeight = mTextureHeight;
00257
00258
00259
00260
00261
00262
00263
00264
00265 if((mTextureWidth * mTextureHeight) <= (512 * 256))
00266 {
00267
00268 SetMoviePlayHints ( theMovie, hintsHighQuality, hintsHighQuality );
00269 }
00270 };
00271
00272
00273 if ( TRUE )
00274 {
00275
00276 MatrixRecord transform;
00277 GetMovieMatrix ( theMovie, &transform );
00278
00279 double centerX = mMediaWidth / 2.0;
00280 double centerY = mMediaHeight / 2.0;
00281 ScaleMatrix ( &transform, X2Fix ( 1.0 ), X2Fix ( -1.0 ), X2Fix ( centerX ), X2Fix ( centerY ) );
00282
00283 SetMovieMatrix ( theMovie, &transform );
00284 };
00285
00286 movieRect.left = 0;
00287 movieRect.top = 0;
00288 movieRect.right = mMediaWidth;
00289 movieRect.bottom = mMediaHeight;
00290
00291
00292 mMediaRowbytes = mMediaWidth * mMediaDepthBytes;
00293
00294 SetMovieBox(theMovie, &movieRect);
00295
00296 if(theController == NULL)
00297 {
00298 SetGWorld(theGWorld, NULL);
00299
00300
00301 theController = NewMovieController(theMovie, &movieRect, mcNotVisible|mcTopLeftMovie);
00302
00303 MCSetActionFilterWithRefCon(theController, myMCActionFilterProc, (long)this);
00304
00305
00306 SetMoviePlayHints(theMovie, hintsAllowDynamicResize, hintsAllowDynamicResize);
00307 }
00308 else
00309 {
00310 MCPositionController(theController, &movieRect, &movieRect, mcTopLeftMovie|mcPositionDontInvalidate);
00311 }
00312 }
00313
00315
00316 void
00317 LLMediaImplQuickTime::
00318 setupDummyBuffer()
00319 {
00320
00321 movieRect.left = movieRect.top = 0;
00322 movieRect.right = movieRect.bottom = 64;
00323 mMediaRowbytes = mMediaDepthBytes * 64;
00324 mMediaWidth = 64;
00325 mMediaHeight = 64;
00326 mTextureWidth = 64;
00327 mTextureHeight = 64;
00328
00329 setBuffer ( NULL );
00330
00331 memset(mediaData, 0, mMediaRowbytes * mMediaHeight );
00332 }
00333
00335
00336 BOOL
00337 LLMediaImplQuickTime::
00338 load ( const LLString& urlIn )
00339 {
00340
00341 setupDummyBuffer();
00342 SetGWorld(theGWorld, NULL);
00343
00344 Size mySize = ( Size ) urlIn.length () + 1;
00345 if ( mySize == 0 )
00346 return FALSE;
00347
00348 Handle myHandle = NewHandleClear ( mySize );
00349 if ( myHandle == NULL )
00350 return FALSE;
00351
00352 BlockMove ( urlIn.c_str (), *myHandle, mySize );
00353
00354
00355 OSErr err = NewMovieFromDataRef ( &theMovie, newMovieActive|newMovieDontInteractWithUser|newMovieAsyncOK|newMovieIdleImportOK, NULL, myHandle, URLDataHandlerSubType );
00356
00357 if ( err != noErr )
00358 return false;
00359
00360
00361 SetMovieDrawingCompleteProc ( theMovie, movieDrawingCallWhenChanged, myFrameDrawnCallback, ( long ) this );
00362
00363 if(isQTLoaded())
00364 {
00365 updateMediaSize();
00366 setBuffer(NULL);
00367 }
00368
00369
00370
00371
00372 return LLMediaMovieBase::load(urlIn);
00373 }
00374
00376
00377 OSErr
00378 LLMediaImplQuickTime::
00379 myFrameDrawnCallback ( Movie callbackMovie, long refCon )
00380 {
00381 LLMediaImplQuickTime* myQtRenderer = ( LLMediaImplQuickTime* ) refCon;
00382
00383
00384
00385 #if 0
00386 Ptr pixels = GetPixBaseAddr ( myQtRenderer->pixmapHandle );
00387
00388 LockPixels ( myQtRenderer->pixmapHandle );
00389
00390 memcpy ( ( U8* ) myQtRenderer->mediaData, pixels, myQtRenderer->getMediaBufferSize () );
00391
00392 UnlockPixels ( myQtRenderer->pixmapHandle );
00393 #endif
00394
00395 myQtRenderer->bufferChanged();
00396
00397 return 0;
00398 }
00399
00401 Boolean
00402 LLMediaImplQuickTime::myMCActionFilterProc (MovieController theMC, short theAction, void *theParams, long theRefCon)
00403 {
00404 Boolean result = false;
00405 LLMediaImplQuickTime *self = (LLMediaImplQuickTime*)theRefCon;
00406
00407 switch ( theAction )
00408 {
00409
00410 case mcActionControllerSizeChanged:
00411 self->sizeChanged();
00412 break;
00413
00414
00415 case mcActionLinkToURL:
00416 case mcActionGetNextURL:
00417 case mcActionLinkToURLExtended:
00418
00419 result = true;
00420 break;
00421
00422 default:
00423 break;
00424 };
00425
00426 return ( result );
00427 }
00428
00430
00431 void
00432 LLMediaImplQuickTime::rewind()
00433 {
00434
00435 GoToBeginningOfMovie ( theMovie );
00436
00437
00438 MCMovieChanged(theController, theMovie);
00439
00440 #if 0
00441
00442 TimeRecord when;
00443 when.value.hi = 0;
00444 when.value.lo = 0;
00445 when.scale = GetMovieTimeScale(theMovie);
00446
00447
00448
00449 when.base = 0;
00450
00451 MCDoAction(theController, mcActionGoToTime, &when);
00452 #endif
00453 }
00454
00456
00457 void
00458 LLMediaImplQuickTime::sizeChanged()
00459 {
00460
00461 setupDummyBuffer();
00462
00463
00464 sizeChangeInProgress = true;
00465
00466
00467 updateMediaSize();
00468 }
00469
00471
00472 BOOL
00473 LLMediaImplQuickTime::
00474 isQTLoaded()
00475 {
00476 BOOL result = false;
00477
00478 if(theMovie)
00479 {
00480 if(GetMovieLoadState(theMovie) >= kMovieLoadStateLoaded)
00481 {
00482 result = true;
00483 }
00484 }
00485
00486 return result;
00487 }
00488
00490
00491 BOOL
00492 LLMediaImplQuickTime::
00493 isQTPlaythroughOK()
00494 {
00495 BOOL result = false;
00496
00497 if(theMovie)
00498 {
00499 if(GetMovieLoadState(theMovie) >= kMovieLoadStatePlaythroughOK)
00500 {
00501 result = true;
00502 }
00503 }
00504
00505 return result;
00506 }
00507
00509
00510 BOOL
00511 LLMediaImplQuickTime::
00512 unload ()
00513 {
00514
00515 if( theController )
00516 {
00517
00518 MCSetActionFilterWithRefCon(theController, NULL, (long)this);
00519
00520 DisposeMovieController( theController );
00521 theController = NULL;
00522 };
00523
00524 if ( theMovie )
00525 {
00526
00527 SetMovieDrawingCompleteProc ( theMovie, movieDrawingCallWhenChanged, nil, ( long ) this );
00528
00529 DisposeMovie ( theMovie );
00530 theMovie = NULL;
00531 };
00532
00533 if ( theGWorld )
00534 {
00535 DisposeGWorld ( theGWorld );
00536 theGWorld = NULL;
00537 };
00538
00539 if ( mediaData )
00540 {
00541 if ( ownBuffer )
00542 {
00543 delete mediaData;
00544 mediaData = NULL;
00545 };
00546 };
00547
00548 return TRUE;
00549 }
00550
00552
00553 S32
00554 LLMediaImplQuickTime::
00555 updateMedia ()
00556 {
00557 if(!theController)
00558 {
00559 if(isQTLoaded())
00560 {
00561
00562
00563 updateMediaSize();
00564 return updateMediaNeedsSizeChange;
00565 }
00566 else
00567 {
00568
00569 MoviesTask ( theMovie, 0 );
00570 }
00571 }
00572
00573 if(theController)
00574 {
00575 switch(currentMode)
00576 {
00577 case ModePlaying:
00578 case ModeLooping:
00579 if(!initialStartDone)
00580 {
00581 if(isQTPlaythroughOK())
00582 {
00583
00584 MCDoAction(theController, mcActionPrerollAndPlay, (void*)GetMoviePreferredRate(theMovie));
00585
00586 MCDoAction(theController, mcActionSetVolume, (void*)curVolume );
00587
00588 initialStartDone = TRUE;
00589 }
00590 }
00591 break;
00592 }
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605 MCIdle(theController);
00606 }
00607
00608
00609 if(sizeChangeInProgress)
00610 {
00611 return updateMediaNeedsSizeChange;
00612 }
00613
00614 BOOL updated = getBufferChanged();
00615
00616 resetBufferChanged();
00617
00618 if(updated)
00619 return updateMediaNeedsUpdate;
00620
00621
00622 if ( currentMode == ModeLooping )
00623 if ( IsMovieDone ( theMovie ) )
00624 loop ( 0 );
00625
00626 return updateMediaNoChanges;
00627 }
00628
00630
00631 void
00632 LLMediaImplQuickTime::
00633 setAutoScaled ( BOOL autoScaledIn )
00634 {
00635 autoScaled = autoScaledIn;
00636 }
00637
00639
00640 BOOL
00641 LLMediaImplQuickTime::
00642 stop ()
00643 {
00644 currentMode = ModeStopped;
00645
00646 if(theController)
00647 {
00648 Fixed rate = X2Fix(0.0);
00649 MCDoAction(theController, mcActionPlay, (void*)rate);
00650
00651 rewind();
00652 }
00653
00654 return LLMediaMovieBase::stop();
00655 };
00656
00658
00659 BOOL
00660 LLMediaImplQuickTime::
00661 play ()
00662 {
00663 currentMode = ModePlaying;
00664
00665 if(theController)
00666 {
00667 if ( IsMovieDone ( theMovie ) )
00668 {
00669 rewind();
00670 };
00671
00672 MCDoAction(theController, mcActionPrerollAndPlay, (void*)GetMoviePreferredRate(theMovie));
00673
00674 MCDoAction(theController, mcActionSetVolume, (void*)curVolume );
00675 }
00676
00677 return LLMediaMovieBase::play();
00678 };
00679
00681
00682 BOOL
00683 LLMediaImplQuickTime::
00684 loop ( S32 howMany )
00685 {
00686 currentMode = ModeLooping;
00687
00688
00689
00690
00691 if ( theController )
00692 {
00693
00694 if ( IsMovieDone ( theMovie ) )
00695 {
00696 rewind();
00697 };
00698
00699 MCDoAction(theController, mcActionPrerollAndPlay, (void*)GetMoviePreferredRate(theMovie));
00700
00701 MCDoAction(theController, mcActionSetVolume, (void*)curVolume );
00702 }
00703
00704 return LLMediaMovieBase::loop(howMany);
00705 };
00706
00708
00709 BOOL
00710 LLMediaImplQuickTime::
00711 pause ()
00712 {
00713 currentMode = ModePaused;
00714
00715 if(theController)
00716 {
00717
00718 Fixed rate = X2Fix(0.0);
00719 MCDoAction(theController, mcActionPlay, (void*)rate);
00720 }
00721
00722 return LLMediaMovieBase::pause();
00723 };
00724
00726
00727 BOOL
00728 LLMediaImplQuickTime::
00729 setVolume ( F32 volumeIn )
00730 {
00731
00732 curVolume = (short)(volumeIn * ( F32 ) 0x100);
00733
00734 if(theController != NULL)
00735 {
00736 MCDoAction(theController, mcActionSetVolume, (void*)curVolume);
00737 }
00738
00739 return TRUE;
00740 }
00741
00743
00744 F32
00745 LLMediaImplQuickTime::
00746 getVolume ()
00747 {
00748 return ( ( F32 ) curVolume ) / ( F32 ) 0x100;
00749 }
00750
00752
00753 BOOL
00754 LLMediaImplQuickTime::
00755 isIdle () const
00756 {
00757 return ( currentMode == ModeIdle );
00758 };
00759
00761
00762 BOOL
00763 LLMediaImplQuickTime::
00764 isError () const
00765 {
00766 return ( currentMode == ModeError );
00767 };
00768
00770
00771 BOOL
00772 LLMediaImplQuickTime::
00773 isBuffering () const
00774 {
00775 return ( currentMode == ModeBuffering );
00776 };
00777
00779
00780 BOOL
00781 LLMediaImplQuickTime::
00782 isLoaded () const
00783 {
00784
00785
00786 return (theController != NULL);
00787 };
00788
00790
00791 BOOL
00792 LLMediaImplQuickTime::
00793 isPlaying () const
00794 {
00795 return ( currentMode == ModePlaying );
00796 };
00797
00799
00800 BOOL
00801 LLMediaImplQuickTime::
00802 isLooping () const
00803 {
00804 return ( currentMode == ModeLooping );
00805 };
00806
00808
00809 BOOL
00810 LLMediaImplQuickTime::
00811 isPaused () const
00812 {
00813 return ( currentMode == ModePaused );
00814 };
00815
00817
00818 BOOL
00819 LLMediaImplQuickTime::
00820 isStopped () const
00821 {
00822 return ( currentMode == ModeStopped );
00823 };
00824
00826
00827 U8*
00828 LLMediaImplQuickTime::
00829 getMediaData ()
00830 {
00831 return mediaData;
00832 }
00833
00835
00836 BOOL
00837 LLMediaImplQuickTime::
00838 seek ( F64 time )
00839 {
00840
00841
00842 if(theController != NULL)
00843 {
00844 TimeRecord when;
00845 when.scale = GetMovieTimeScale(theMovie);
00846 when.base = 0;
00847
00848
00849
00850 S64 rawTime = (S64)(time * (F64)(when.scale));
00851
00852 when.value.hi = ( SInt32 ) ( rawTime >> 32 );
00853 when.value.lo = ( SInt32 ) ( ( rawTime & 0x00000000FFFFFFFF ) );
00854
00855 MCDoAction(theController, mcActionGoToTime, &when);
00856 }
00857
00858 return TRUE;
00859 }
00860
00862
00863 F64
00864 LLMediaImplQuickTime::
00865 getTime () const
00866 {
00867 F64 result = 0;
00868
00869 if(theController != NULL)
00870 {
00871 TimeValue time;
00872 TimeScale scale = 0;
00873
00874 time = MCGetCurrentTime(theController, &scale);
00875 if(scale != 0)
00876 {
00877 result = ((F64)time) / ((F64)scale);
00878 }
00879 }
00880
00881 return result;
00882 }
00883
00885
00886 F64
00887 LLMediaImplQuickTime::
00888 getMediaDuration () const
00889 {
00890 F64 result = 0;
00891 TimeScale scale = GetMovieTimeScale(theMovie);
00892 TimeValue duration = GetMovieDuration(theMovie);
00893
00894 if(duration == kQTSUnknownDuration)
00895 {
00896
00897
00898 }
00899 else if(duration == kQTSInfiniteDuration)
00900 {
00901
00902
00903
00904 }
00905 else if(scale != 0)
00906 {
00907
00908 result = (F64)duration;
00909 result /= (F64)scale;
00910 }
00911
00912 return result;
00913 }
00914
00915 #endif