00001
00032 #include "llmediaimplquicktime.h"
00033
00034 #if LL_QUICKTIME_ENABLED
00035
00036 #include "llmediamanager.h"
00037 #include "llmediaimplregister.h"
00038
00039 #if LL_WINDOWS
00040 #include <windows.h>
00041 #endif
00042
00043 #include <iostream>
00044 #include <sstream>
00045
00046
00047 static LLMediaImplRegister sLLMediaImplQuickTimeReg( "LLMediaImplQuickTime", new LLMediaImplQuickTimeMaker() );
00048
00050
00051 LLMediaImplQuickTimeMaker::LLMediaImplQuickTimeMaker()
00052 {
00053
00054 mSchema.push_back( "rtsp" );
00055
00056
00057 mMimeTypeCategories.push_back( "video" );
00058 mMimeTypeCategories.push_back( "audio" );
00059 mMimeTypeCategories.push_back( "image" );
00060 }
00061
00063
00064 LLMediaImplQuickTime::LLMediaImplQuickTime() :
00065 mMovieHandle( 0 ),
00066 mGWorldHandle( 0 ),
00067 mMovieController( 0 ),
00068 mMinWidth( 32 ),
00069 mMaxWidth( 2048 ),
00070 mMinHeight( 32 ),
00071 mMaxHeight( 2048 ),
00072 mCurVolume( 0 )
00073 {
00074 }
00075
00077
00078 LLMediaImplQuickTime::~LLMediaImplQuickTime()
00079 {
00080 unload();
00081 }
00082
00084
00085 bool LLMediaImplQuickTime::startup( LLMediaManagerData* init_data )
00086 {
00087 #ifdef WIN32
00088 if ( InitializeQTML( 0L ) != noErr )
00089 {
00090 return false;
00091 };
00092 #endif
00093
00094 EnterMovies();
00095
00096 return true;
00097 }
00098
00100
00101 bool LLMediaImplQuickTime::closedown()
00102 {
00103 ExitMovies();
00104
00105 #ifdef WIN32
00106 TerminateQTML();
00107 #endif
00108
00109 return true;
00110 }
00111
00113
00114 bool LLMediaImplQuickTime::load( const std::string url )
00115 {
00116 if ( url.empty() )
00117 return false;
00118
00119 Handle handle = NewHandleClear( ( Size )( url.length() + 1 ) );
00120 if ( NULL == handle )
00121 return false;
00122
00123 BlockMove( url.c_str(), *handle, ( Size )( url.length() + 1 ) );
00124
00125
00126
00127
00128 OSErr err = NewMovieFromDataRef( &mMovieHandle, newMovieActive | newMovieDontInteractWithUser | newMovieAsyncOK | newMovieIdleImportOK, nil, handle, URLDataHandlerSubType );
00129 DisposeHandle( handle );
00130 if ( noErr != err )
00131 return false;
00132
00133
00134 PrePrerollMovie( mMovieHandle, 0, GetMoviePreferredRate( mMovieHandle ), moviePrePrerollCompleteCallback, ( void * )this );
00135
00136
00137 Rect movie_rect;
00138 setMovieBoxEnhanced( &movie_rect );
00139
00140
00141 mMovieController = NewMovieController( mMovieHandle, &movie_rect, mcNotVisible | mcTopLeftMovie );
00142
00143 #if defined(__APPLE__) || defined(MACOSX)
00144 setMediaDepth( 4 );
00145 #else
00146 setMediaDepth( 3 );
00147 #endif
00148
00149
00150 setMediaSize( movie_rect.right - movie_rect.left, movie_rect.bottom - movie_rect.top);
00151
00152
00153 MCSetActionFilterWithRefCon( mMovieController, mcActionFilterCallBack, ( long )this );
00154
00155 SetMoviePlayHints( mMovieHandle, hintsAllowDynamicResize, hintsAllowDynamicResize );
00156
00157
00158 SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, movieDrawingCompleteCallback, ( long )this );
00159
00160
00161 LLMediaEvent event( this );
00162 mEventEmitter.update( &LLMediaObserver::onMediaLoaded, event );
00163
00164
00165 sizeChanged();
00166
00167 return true;
00168 }
00169
00171
00172 std::string LLMediaImplQuickTime::getVersion()
00173 {
00174 long version;
00175 Gestalt( gestaltQuickTimeVersion, &version );
00176
00177 std::ostringstream codec( "" );
00178 codec << "[";
00179 codec << sLLMediaImplQuickTimeReg.getImplName();
00180 codec << "] - ";
00181 codec << "QuickTime: " << std::hex << version;
00182
00183 return codec.str();
00184 }
00185
00187
00188 bool LLMediaImplQuickTime::navigateTo( const std::string url )
00189 {
00190
00191 setStatus( LLMediaBase::STATUS_NAVIGATING );
00192
00193
00194 unload();
00195
00196
00197 load( url );
00198
00199 return true;
00200 }
00201
00203
00204 bool LLMediaImplQuickTime::sizeChanged()
00205 {
00206 if ( ! mMovieHandle )
00207 return false;
00208
00209
00210 Rect movie_rect;
00211 setMovieBoxEnhanced( &movie_rect );
00212
00213
00214 int width = ( movie_rect.right - movie_rect.left );
00215 int height = ( movie_rect.bottom - movie_rect.top );
00216
00217 std::cout << "LLMEDIA> size changed to " << width << " x " << height << std::endl;
00218
00219 setMediaSize( width, height );
00220
00221
00222 int depth_bits = getMediaDepth() * 8;
00223
00224 GWorldPtr old_gworld_handle = mGWorldHandle;
00225
00226 if (old_gworld_handle)
00227 {
00228 GWorldFlags result = UpdateGWorld( &mGWorldHandle, depth_bits, &movie_rect, NULL, NULL, 0 );
00229 if ( gwFlagErr == result )
00230 {
00231
00232 return false;
00233 }
00234 }
00235 else
00236 {
00237 OSErr result = NewGWorld( &mGWorldHandle, depth_bits, &movie_rect, NULL, NULL, keepLocal | pixelsLocked );
00238 if ( noErr != result )
00239 {
00240
00241 return false;
00242 }
00243
00244
00245 if ( mGWorldHandle )
00246 {
00247 PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle );
00248 unsigned char* ptr = ( unsigned char* )GetPixBaseAddr( pix_map_handle );
00249 memset( ptr, 0x00, height * QTGetPixMapHandleRowBytes( pix_map_handle ) );
00250 }
00251 }
00252
00253
00254 if ( mMovieHandle && ! old_gworld_handle )
00255 {
00256 SetMovieGWorld( mMovieHandle, mGWorldHandle, GetGWorldDevice ( mGWorldHandle ) );
00257 }
00258
00259
00260 if ( mMovieController )
00261 {
00262 MCSetControllerPort( mMovieController, mGWorldHandle );
00263 MCPositionController( mMovieController, &movie_rect, &movie_rect,
00264 mcTopLeftMovie | mcPositionDontInvalidate );
00265 MCMovieChanged( mMovieController, mMovieHandle );
00266 }
00267
00268
00269 LLMediaEvent event( this );
00270 mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event );
00271
00272 return true;
00273 }
00274
00276
00277 Boolean LLMediaImplQuickTime::mcActionFilterCallBack( MovieController mc, short action, void *params, long ref )
00278 {
00279 Boolean result = false;
00280
00281 LLMediaImplQuickTime* self = ( LLMediaImplQuickTime* )ref;
00282
00283 switch( action )
00284 {
00285
00286 case mcActionControllerSizeChanged:
00287 self->sizeChanged();
00288 break;
00289
00290
00291 case mcActionLinkToURL:
00292 case mcActionGetNextURL:
00293 case mcActionLinkToURLExtended:
00294
00295 result = true;
00296 break;
00297
00298 default:
00299 break;
00300 };
00301
00302 return result;
00303 }
00304
00306
00307 bool LLMediaImplQuickTime::unload()
00308 {
00309 if ( mMovieHandle )
00310 {
00311 StopMovie( mMovieHandle );
00312 if ( mMovieController )
00313 {
00314 MCMovieChanged( mMovieController, mMovieHandle );
00315 };
00316 };
00317
00318 if ( mMovieController )
00319 {
00320 MCSetActionFilterWithRefCon( mMovieController, NULL, (long)this );
00321 DisposeMovieController( mMovieController );
00322 mMovieController = NULL;
00323 };
00324
00325 if ( mMovieHandle )
00326 {
00327 SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, nil, ( long )this );
00328 DisposeMovie ( mMovieHandle );
00329 mMovieHandle = NULL;
00330 };
00331
00332 if ( mGWorldHandle )
00333 {
00334 DisposeGWorld( mGWorldHandle );
00335 mGWorldHandle = NULL;
00336 };
00337
00338 return true;
00339 }
00340
00342
00343 OSErr LLMediaImplQuickTime::movieDrawingCompleteCallback( Movie call_back_movie, long ref )
00344 {
00345 LLMediaImplQuickTime* self = ( LLMediaImplQuickTime* )ref;
00346
00347
00348
00349
00350 LLMediaEvent event( self );
00351 self->mEventEmitter.update( &LLMediaObserver::onMediaContentsChange, event );
00352
00353 return noErr;
00354 }
00355
00357
00358 void LLMediaImplQuickTime::moviePrePrerollCompleteCallback( Movie movie, OSErr preroll_err, void *ref )
00359 {
00360 LLMediaImplQuickTime* self = ( LLMediaImplQuickTime* )ref;
00361
00362 LLMediaEvent event( self );
00363 self->mEventEmitter.update( &LLMediaObserver::onMediaPreroll, event );
00364 }
00365
00367
00368 void LLMediaImplQuickTime::rewind()
00369 {
00370 GoToBeginningOfMovie ( mMovieHandle );
00371
00372 MCMovieChanged( mMovieController, mMovieHandle );
00373 }
00374
00376
00377 bool LLMediaImplQuickTime::processState()
00378 {
00379
00380 if ( nextCommand() == LLMediaBase::COMMAND_START )
00381 {
00382
00383 if ( getStatus() == LLMediaBase::STATUS_NAVIGATING|| getStatus() == LLMediaBase::STATUS_STOPPED || getStatus() == LLMediaBase::STATUS_PAUSED )
00384 {
00385
00386 if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
00387 {
00388 MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)GetMoviePreferredRate( mMovieHandle ) );
00389
00390 MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
00391
00392 setStatus( LLMediaBase::STATUS_STARTED );
00393
00394 clearCommand();
00395 }
00396 }
00397 }
00398 else
00399 if ( nextCommand() == LLMediaBase::COMMAND_STOP )
00400 {
00401
00402 if ( getStatus() == LLMediaBase::STATUS_NAVIGATING || getStatus() == LLMediaBase::STATUS_STARTED || getStatus() == LLMediaBase::STATUS_PAUSED )
00403 {
00404
00405 if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
00406 {
00407
00408 Fixed rate = X2Fix( 0.0 );
00409 MCDoAction( mMovieController, mcActionPlay, (void*)rate );
00410
00411
00412 rewind();
00413
00414 setStatus( LLMediaBase::STATUS_STOPPED );
00415 clearCommand();
00416 };
00417 };
00418 }
00419 else
00420 if ( nextCommand() == LLMediaBase::COMMAND_PAUSE )
00421 {
00422
00423 if ( getStatus() == LLMediaBase::STATUS_NAVIGATING || getStatus() == LLMediaBase::STATUS_STARTED || getStatus() == LLMediaBase::STATUS_STOPPED )
00424 {
00425
00426 if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
00427 {
00428
00429 Fixed rate = X2Fix( 0.0 );
00430 MCDoAction( mMovieController, mcActionPlay, (void*)rate );
00431
00432 setStatus( LLMediaBase::STATUS_PAUSED );
00433 clearCommand();
00434 };
00435 };
00436 };
00437
00438 return true;
00439 }
00440
00442
00443 bool LLMediaImplQuickTime::setMovieBoxEnhanced( Rect* rect )
00444 {
00445
00446 GetMovieNaturalBoundsRect( mMovieHandle, rect );
00447
00448 int natural_width = ( rect->right - rect->left );
00449 int natural_height = ( rect->bottom - rect->top );
00450
00451 int width = natural_width;
00452 int height = natural_height;
00453
00454
00455 if ((mMediaRequestedWidth != 0) && (mMediaRequestedHeight != 0))
00456 {
00457 width = mMediaRequestedWidth;
00458 height = mMediaRequestedHeight;
00459 }
00460
00461
00462 if (mAutoScaled)
00463 {
00464 width = LLMediaManager::textureWidthFromMediaWidth( width );
00465 height = LLMediaManager::textureHeightFromMediaHeight( height );
00466 }
00467
00468
00469 if ( width < mMinWidth )
00470 width = mMinWidth;
00471
00472 if ( width > mMaxWidth )
00473 width = mMaxWidth;
00474
00475 if ( height < mMinHeight )
00476 height = mMinHeight;
00477
00478 if ( height > mMaxHeight )
00479 height = mMaxHeight;
00480
00481
00482
00483 MatrixRecord transform;
00484 SetIdentityMatrix( &transform );
00485 double scaleX = (double) width / natural_width;
00486 double scaleY = -1.0 * (double) height / natural_height;
00487 double centerX = width / 2.0;
00488 double centerY = height / 2.0;
00489 ScaleMatrix( &transform, X2Fix ( scaleX ), X2Fix ( scaleY ), X2Fix ( centerX ), X2Fix ( centerY ) );
00490 SetMovieMatrix( mMovieHandle, &transform );
00491
00492
00493 rect->right = width;
00494 rect->bottom = height;
00495 rect->left = 0;
00496 rect->top = 0;
00497
00498 return true;
00499 }
00500
00502
00503 bool LLMediaImplQuickTime::updateMedia()
00504 {
00505 if ( ! mMovieHandle )
00506 return false;
00507
00508 if ( ! mMovieController )
00509 return false;
00510
00511 if ( ! mGWorldHandle )
00512 return false;
00513
00514
00515 MoviesTask( mMovieHandle, 0 );
00516 MCIdle( mMovieController );
00517
00518
00519 processState();
00520
00521
00522
00523 if ( isLooping() )
00524 {
00525
00526 if ( IsMovieDone( mMovieHandle ) )
00527 {
00528
00529 rewind();
00530
00531
00532 MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)GetMoviePreferredRate( mMovieHandle ) );
00533
00534
00535 MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
00536 }
00537 }
00538
00539 return true;
00540 }
00541
00543
00544 unsigned char* LLMediaImplQuickTime::getMediaData()
00545 {
00546 unsigned char* ptr = NULL;
00547
00548 if ( mGWorldHandle )
00549 {
00550 PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle );
00551
00552 ptr = ( unsigned char* )GetPixBaseAddr( pix_map_handle );
00553 };
00554
00555 return ptr;
00556 }
00557
00559
00560 int LLMediaImplQuickTime::getMediaDataWidth() const
00561 {
00562 if ( mGWorldHandle )
00563 {
00564 int depth = getMediaDepth();
00565
00566 if (depth < 1)
00567 depth = 1;
00568
00569
00570
00571 PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle );
00572 return QTGetPixMapHandleRowBytes( pix_map_handle ) / depth;
00573 }
00574 else
00575 {
00576 return LLMediaImplCommon::getMediaDataWidth();
00577 }
00578 }
00579
00581
00582 int LLMediaImplQuickTime::getTextureFormatPrimary() const
00583 {
00584 #if defined(__APPLE__) || defined(MACOSX)
00585 return LL_MEDIA_BGRA;
00586 #else
00587 return LL_MEDIA_RGB;
00588 #endif
00589 }
00590
00592
00593 int LLMediaImplQuickTime::getTextureFormatType() const
00594 {
00595 #if defined(__APPLE__) || defined(MACOSX)
00596 #ifdef __BIG_ENDIAN__
00597 return LL_MEDIA_UNSIGNED_INT_8_8_8_8_REV;
00598 #else
00599 return LL_MEDIA_UNSIGNED_INT_8_8_8_8;
00600 #endif
00601 #else
00602 return LL_MEDIA_UNSIGNED_BYTE;
00603 #endif
00604 }
00605
00607
00608 bool LLMediaImplQuickTime::seek( double time )
00609 {
00610 if ( mMovieController )
00611 {
00612 TimeRecord when;
00613 when.scale = GetMovieTimeScale( mMovieHandle );
00614 when.base = 0;
00615
00616
00617
00618 SInt64 raw_time = ( SInt64 )( time * (double)( when.scale ) );
00619
00620 when.value.hi = ( SInt32 )( raw_time >> 32 );
00621 when.value.lo = ( SInt32 )( ( raw_time & 0x00000000FFFFFFFF ) );
00622
00623 MCDoAction( mMovieController, mcActionGoToTime, &when );
00624
00625 return true;
00626 }
00627
00628 return false;
00629 }
00630
00632
00633 bool LLMediaImplQuickTime::setVolume( float volume )
00634 {
00635 mCurVolume = (short)(volume * ( double ) 0x100 );
00636
00637 if ( mMovieController )
00638 {
00639 MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
00640
00641 return true;
00642 }
00643
00644 return false;
00645 }
00646
00647 #endif // _3DNOW_InstructionExtensions/ LL_QUICKTIME_ENABLED
00648