llmediaimplquicktime.cpp

Go to the documentation of this file.
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"        // For gl texture modes
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 // These should probably be in the initializer list above, but that seemed uglier...
00060 #if LL_DARWIN
00061         // Mac OS -- gworld will be xRGB (4 byte pixels, like ARGB, but QuickDraw doesn't actually do alpha...)
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         // Windows -- GWorld will be RGB (3 byte pixels)
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         // If we're waiting for a size change, we just got one.
00099         sizeChangeInProgress = FALSE;
00100                 
00101         // Since we've pointed QuickTime at the old media data buffer directly, we need to be somewhat careful deleting it...
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                 // Passing NULL to this function requests that the object allocate its own buffer.
00111                 mediaData = new unsigned char [ mMediaHeight * mMediaRowbytes ];
00112                 ownBuffer = TRUE;
00113         }
00114         else
00115         {
00116                 // Use the supplied buffer.
00117                 mediaData = bufferIn;
00118                 ownBuffer = FALSE;
00119         }
00120         
00121         if(mediaData == NULL)
00122         {
00123                 // This is bad.
00124                 llerrs << "LLMediaImplQuickTime::setBuffer: mediaData is NULL" << llendl;
00125                 // NOTE: This case doesn't clean up properly.  This assert is fatal, so this isn't a huge problem,
00126                 // but if this assert is ever removed the code should be fixed to clean up correctly.
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                         // tell the movie about it
00136                         SetMovieGWorld ( theMovie, theGWorld, GetGWorldDevice ( theGWorld ) );
00137                 }
00138                 
00139                 if(theController)
00140                 {
00141                         // and tell the movie controller about it.
00142                         MCSetControllerPort(theController, theGWorld);
00143                 }
00144 
00145 #if LL_DARWIN
00146 // NOTE: (CP) This call ultimately leads to a crash in NewGWorldFromPtr on Windows (only) 
00147 //                        Not calling DisposeGWorld doesn't appear to leak anything significant and stops the crash occuring.
00148 //                        This will eventually be fixed but for now, leaking slightly is better than crashing.
00149                 if ( oldGWorld != NULL )
00150                 {
00151                         // Delete the old GWorld
00152                         DisposeGWorld ( oldGWorld );
00153                         oldGWorld = NULL;
00154                 }
00155 #endif
00156         }
00157         else
00158         {
00159                 // Hmm... this may be bad.  Assert here?
00160                 llerrs << "LLMediaImplQuickTime::setBuffer: NewGWorldFromPtr failed" << llendl;
00161                 theGWorld = NULL;
00162                 return FALSE;
00163         }
00164         
00165         // Delete the old media data buffer iff we owned it.
00166         if ( ownedMediaData )
00167         {
00168                 if ( oldMediaData )
00169                 {
00170                         delete [] oldMediaData;
00171                 }
00172         }
00173 
00174         // build event and emit it
00175         
00176         return TRUE;
00177 }
00178 
00180 //
00181 BOOL
00182 LLMediaImplQuickTime::
00183 init ()
00184 {
00185         // movied to main application initialization for now because it's non-trivial and only needs to be done once
00186         // (even though it goes against the media framework design)
00187         //if ( InitializeQTML ( 0L ) != 0 )
00188         //{
00189         //      return FALSE;
00190         //};
00191 
00192         //if ( EnterMovies () != 0 )
00193         //{
00194         //      return FALSE;
00195         //};
00196 
00197         return LLMediaMovieBase::init();
00198 }
00199 
00201 //
00202 void 
00203 LLMediaImplQuickTime::
00204 updateMediaSize()
00205 {
00206         if((theController == NULL) && (!isQTLoaded()))
00207         {
00208                 // The movie's not loaded enough to get info about it yet.
00209                 // Set up a dummy buffer.
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         // pick up the size of the movie
00222         GetMovieBox ( theMovie, &movieRect );
00223         
00224         // save the size of the media so consumer of media class can use it
00225         mMediaWidth = movieRect.right - movieRect.left;
00226         mMediaHeight = movieRect.bottom - movieRect.top;
00227         
00228         // Giant media could make us try to use textures bigger than the opengl implementation can handle.
00229         // Pin the maximum X or Y dimension to 1024.
00230         // NOTE: 1024x1024 may still hurt a lot, but it shouldn't cause opengl to flame out.
00231         if(mMediaWidth > 1024)
00232         {
00233                 mMediaWidth = 1024;
00234         }
00235         if(mMediaHeight > 1024)
00236         {
00237                 mMediaHeight = 1024;
00238         }
00239         
00240         // calculate the texture size required to hold media of this size (next power of 2 bigger)
00241         for ( mTextureWidth = 1; mTextureWidth < mMediaWidth; mTextureWidth <<= 1 )
00242         {
00243         };
00244 
00245         for ( mTextureHeight = 1; mTextureHeight < mMediaHeight; mTextureHeight <<= 1 )
00246         {
00247         };
00248 
00249 //      llinfos << "Media texture size will be " << mTextureWidth << " x " << mTextureHeight << llendl;
00250         
00251         // if autoscale is on we simply make the media & texture sizes the same and quicktime does all the hard work
00252         if ( autoScaled )
00253         {
00254                 // Stretch the movie to fill the texture.
00255                 mMediaWidth = mTextureWidth;
00256                 mMediaHeight = mTextureHeight;
00257 
00258                 // scale movie using high quality but slow algorithm.
00259                 // NOTE: this results in close to same quality as texture scaling option but with (perhaps) significant
00260                 //       loss of performance (e.g. my machine, release build, frame rate goes from 92 -> 82 fps
00261                 //       To revert to original behaviour, just remove the line below.
00262                 
00263                 // MBW -- There seems to be serious drop in performance above a particular size, on both low and high end machines.
00264                 // 512x256 is fine, while 512x512 is unusable.  I theorize that this is due to CPU cache getting broken around that size.
00265                 if((mTextureWidth * mTextureHeight) <= (512 * 256))
00266                 {
00267 //                      llinfos << "Setting high-quality hint." << llendl;
00268                         SetMoviePlayHints ( theMovie, hintsHighQuality, hintsHighQuality );
00269                 }
00270         };
00271         
00272         // always flip movie using quicktime (little performance impact and no loss in quality)
00273         if ( TRUE )
00274         {
00275                 // Invert the movie in the Y directon to match the expected orientation of GL textures.
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         // Calculate the rowbytes of the texture
00292         mMediaRowbytes = mMediaWidth * mMediaDepthBytes;
00293         
00294         SetMovieBox(theMovie, &movieRect);
00295 
00296         if(theController == NULL)
00297         {
00298                 SetGWorld(theGWorld, NULL);
00299                 
00300                 // Create a movie controller for the movie
00301                 theController = NewMovieController(theMovie, &movieRect, mcNotVisible|mcTopLeftMovie);
00302                 
00303                 MCSetActionFilterWithRefCon(theController, myMCActionFilterProc, (long)this);
00304                         
00305                 // Allow the movie to dynamically resize (may be necessary for streaming movies to work right...)
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         // Used when the movie can't be drawn for some reason.  This sets up a buffer that keeps callers from getting annoyed.
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         // The movie may do things to the current port when it's created.  Make sure we have a valid port set.
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         // Might be able to make this asynchronous with (newMovieActive|newMovieAsyncOK|newMovieIdleImportOK)? 
00355         OSErr err = NewMovieFromDataRef ( &theMovie, newMovieActive|newMovieDontInteractWithUser|newMovieAsyncOK|newMovieIdleImportOK, NULL, myHandle, URLDataHandlerSubType );
00356         
00357         if ( err != noErr )
00358                 return false;
00359 
00360         // function that gets called when a frame is drawn
00361         SetMovieDrawingCompleteProc ( theMovie, movieDrawingCallWhenChanged, myFrameDrawnCallback, ( long ) this );
00362         
00363         if(isQTLoaded())
00364         {
00365                 updateMediaSize();
00366                 setBuffer(NULL);
00367         }
00368         
00369         // Tell the controller to play the movie.  This also deals with the movie still loading.
00370         //play();
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         // The gworld quicktime is playing back into is now wrapped around myQtRenderer->mediaData,
00384         // so there's no need to copy any data here.
00385 #if 0
00386         Ptr pixels = GetPixBaseAddr ( myQtRenderer->pixmapHandle );
00387 
00388         LockPixels ( myQtRenderer->pixmapHandle );
00389 
00390         memcpy ( ( U8* ) myQtRenderer->mediaData, pixels, myQtRenderer->getMediaBufferSize () );        /* Flawfinder: ignore */
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                 // handle window resizing
00410                 case mcActionControllerSizeChanged:
00411                         self->sizeChanged();
00412                         break;
00413 
00414                 // Block any movie controller actions that open URLs.
00415                 case mcActionLinkToURL:
00416                 case mcActionGetNextURL:
00417                 case mcActionLinkToURLExtended:
00418                         // Prevent the movie controller from handling the message
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         // MBW -- XXX -- I don't see an easy way to do this via the movie controller.  
00435         GoToBeginningOfMovie ( theMovie );
00436         
00437         // Call this afterwards so the movie controller can sync itself with the movie.
00438         MCMovieChanged(theController, theMovie);
00439         
00440 #if 0
00441         // Maybe something like this?
00442         TimeRecord when;
00443         when.value.hi = 0;
00444         when.value.lo = 0;
00445         when.scale = GetMovieTimeScale(theMovie);
00446         
00447         // This seems like the obvious thing, but a tech note (http://developer.apple.com/technotes/qt/qt_510.html) says otherwise...
00448 //      when.base = GetMovieTimeBase(theMovie);
00449         when.base = 0;
00450         
00451         MCDoAction(theController, mcActionGoToTime, &when);
00452 #endif
00453 }
00454 
00456 //
00457 void 
00458 LLMediaImplQuickTime::sizeChanged()
00459 {
00460         // Set the movie to render (well, actually NOT render) to an internal buffer until the size change can be handled.
00461         setupDummyBuffer();
00462         
00463         // Make the next call to updateMedia request a size change.
00464         sizeChangeInProgress = true;
00465 
00466         // Recalculate the values that depend on the movie rect.
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                 // Slight paranoia...
00518                 MCSetActionFilterWithRefCon(theController, NULL, (long)this);
00519 
00520                 DisposeMovieController( theController );
00521                 theController = NULL;
00522         };
00523         
00524         if ( theMovie )
00525         {
00526                 // Slight paranoia...
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                         // Movie has finished loading.  Request a size change to update buffers, etc.
00562                         // We MUST update the media size here, so it will be correct before the size change request.
00563                         updateMediaSize();
00564                         return updateMediaNeedsSizeChange;
00565                 }
00566                 else
00567                 {
00568                         // Movie is still loading.
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                                         // The movie is loaded enough to start playing.  Start it now.
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 //              // This function may copy decompressed movie frames into our media data pointer. JC
00595 //              if (!mediaData)
00596 //              {
00597 //                      llwarns << "LLMediaImplQuickTime::updateMedia() about to update with null media pointer" << llendl;
00598 //              }
00599 //              else
00600 //              {
00601 //                      // try writing to the pointer to see if it's valid
00602 //                      *mediaData = 0;
00603 //              }
00604 
00605                 MCIdle(theController);
00606         }
00607 
00608         // If we need a size change, that takes precedence.
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         // don't use movie controller for looping - appears to be broken on PCs (volume issue)
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         // MBW -- XXX -- This may be harder to do with a movie controller...
00689 //      loopsLeft = howMany;
00690 
00691         if ( theController )
00692         {
00693                 // Movie is loaded and set up.
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                 // Movie is loaded and set up.
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         // Fixed point signed short, 8.8
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         // Only tell the caller the movie is loaded if we've had a chance to set up the movie controller.
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         // MBW -- XXX -- This should stash the time if theController is NULL, and seek to there when the movie's loaded.
00841         // Do this later.
00842         if(theController != NULL)
00843         {
00844                 TimeRecord when;
00845                 when.scale = GetMovieTimeScale(theMovie);
00846                 when.base = 0;
00847 
00848                 // 'time' is in (floating point) seconds.  The timebase time will be in 'units', where
00849                 // there are 'scale' units per second.
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                 // Hmph.
00897                 // Return 0 in this case.
00898         }
00899         else if(duration == kQTSInfiniteDuration)
00900         {
00901                 // This is the magic number for "indefinite duration", i.e. a live stream.
00902                 // Note that the docs claim this value is 0x7FFFFFF, while the symbolic constant is 0x7FFFFFFF.  Go figure.
00903                 // Return 0 in this case.
00904         }
00905         else if(scale != 0)
00906         {
00907                 // Timescale is a useful number.  Convert to seconds.
00908                 result = (F64)duration;
00909                 result /= (F64)scale;
00910         }
00911         
00912         return result;
00913 }
00914 
00915 #endif

Generated on Thu Jul 1 06:08:51 2010 for Second Life Viewer by  doxygen 1.4.7