1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        mac/carbon/mediactrl.cpp 
   3 // Purpose:     Built-in Media Backends for Mac 
   4 // Author:      Ryan Norton <wxprojects@comcast.net> 
   8 // Copyright:   (c) 2004-2005 Ryan Norton, portions (c) 2004 Kevin Olliver 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 //=========================================================================== 
  14 //=========================================================================== 
  16 //--------------------------------------------------------------------------- 
  17 // Pre-compiled header stuff 
  18 //--------------------------------------------------------------------------- 
  20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  21 #pragma implementation "mediactrl.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  31 //--------------------------------------------------------------------------- 
  33 //--------------------------------------------------------------------------- 
  34 #include "wx/mediactrl.h" 
  36 //--------------------------------------------------------------------------- 
  38 //--------------------------------------------------------------------------- 
  41 //--------------------------------------------------------------------------- 
  42 // Whether or not to use OSX 10.2's CreateMovieControl for native QuickTime 
  43 // control - i.e. native positioning and event handling etc.. 
  44 //--------------------------------------------------------------------------- 
  45 #ifndef wxUSE_CREATEMOVIECONTROL 
  46 #       if defined( __WXMAC_OSX__ ) && ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2 ) 
  47 #               define wxUSE_CREATEMOVIECONTROL 1 
  49 #               define wxUSE_CREATEMOVIECONTROL 0 
  53 //=========================================================================== 
  54 //  BACKEND DECLARATIONS 
  55 //=========================================================================== 
  57 //--------------------------------------------------------------------------- 
  61 //--------------------------------------------------------------------------- 
  63 //--------------------------------------------------------------------------- 
  65 //--------------------------------------------------------------------------- 
  66 //uma is for wxMacFSSpec 
  67 #include "wx/mac/uma.h" 
  71 #include <QuickTimeComponents.h>    //Standard QT stuff 
  73 //Determines whether version 4 of QT is installed (Pretty much for classic only) 
  74 Boolean 
_wxIsQuickTime4Installed (void) 
  79     error 
= Gestalt (gestaltQuickTime
, &result
); 
  80     return (error 
== noErr
) && (((result 
>> 16) & 0xffff) >= 0x0400); 
  83 class WXDLLIMPEXP_MEDIA wxQTMediaBackend 
: public wxMediaBackend
 
  90     virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,  
  95                                      const wxValidator
& validator
, 
  96                                      const wxString
& name
); 
 102     virtual bool Load(const wxString
& fileName
); 
 103     virtual bool Load(const wxURI
& location
); 
 105     virtual wxMediaState 
GetState(); 
 107     virtual bool SetPosition(wxLongLong where
); 
 108     virtual wxLongLong 
GetPosition(); 
 109     virtual wxLongLong 
GetDuration(); 
 111     virtual void Move(int x
, int y
, int w
, int h
); 
 112     wxSize 
GetVideoSize() const; 
 114     virtual double GetPlaybackRate(); 
 115     virtual bool SetPlaybackRate(double dRate
); 
 120     wxSize m_bestSize
;              //Original movie size 
 122     struct MovieType
** m_movie
;     //QT Movie handle/instance 
 126     wxControl
* m_ctrl
;              //Parent control 
 127     bool m_bVideo
;                  //Whether or not we have video 
 128     class _wxQTTimer
* m_timer
;      //Timer for streaming the movie 
 130     DECLARE_DYNAMIC_CLASS(wxQTMediaBackend
); 
 134 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 138 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 140 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend
, wxMediaBackend
); 
 142 //Time between timer calls 
 143 #define MOVIE_DELAY 100 
 145 // -------------------------------------------------------------------------- 
 146 //          wxQTTimer - Handle Asyncronous Playing 
 147 // -------------------------------------------------------------------------- 
 148 class _wxQTTimer 
: public wxTimer
 
 151     _wxQTTimer(Movie movie
, wxQTMediaBackend
* parent
) : 
 152         m_movie(movie
), m_bPaused(false), m_parent(parent
) 
 160     bool GetPaused() {return m_bPaused
;} 
 161     void SetPaused(bool bPaused
) {m_bPaused 
= bPaused
;} 
 163     //----------------------------------------------------------------------- 
 164     // _wxQTTimer::Notify 
 166     // 1) Checks to see if the movie is done, and if not continues 
 167     //    streaming the movie 
 168     // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of 
 170     //----------------------------------------------------------------------- 
 175             if(!IsMovieDone(m_movie
)) 
 176                 MoviesTask(m_movie
, MOVIE_DELAY
);  
 179                 wxMediaEvent 
theEvent(wxEVT_MEDIA_STOP
,  
 180                                       m_parent
->m_ctrl
->GetId()); 
 181                 m_parent
->m_ctrl
->ProcessEvent(theEvent
); 
 183                 if(theEvent
.IsAllowed()) 
 187                     wxASSERT(::GetMoviesError() == noErr
); 
 189                     //send the event to our child 
 190                     wxMediaEvent 
theEvent(wxEVT_MEDIA_FINISHED
,  
 191                                           m_parent
->m_ctrl
->GetId()); 
 192                     m_parent
->m_ctrl
->ProcessEvent(theEvent
); 
 199     Movie m_movie
;                  //Our movie instance 
 200     bool m_bPaused
;                 //Whether we are paused or not 
 201     wxQTMediaBackend
* m_parent
;     //Backend pointer 
 204 //--------------------------------------------------------------------------- 
 205 // wxQTMediaBackend Constructor 
 207 // Sets m_timer to NULL signifying we havn't loaded anything yet 
 208 //--------------------------------------------------------------------------- 
 209 wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL
) 
 213 //--------------------------------------------------------------------------- 
 214 // wxQTMediaBackend Destructor 
 216 // 1) Cleans up the QuickTime movie instance 
 217 // 2) Decrements the QuickTime reference counter - if this reaches 
 218 //    0, QuickTime shuts down 
 219 // 3) Decrements the QuickTime Windows Media Layer reference counter - 
 220 //    if this reaches 0, QuickTime shuts down the Windows Media Layer 
 221 //--------------------------------------------------------------------------- 
 222 wxQTMediaBackend::~wxQTMediaBackend() 
 227     //Note that ExitMovies() is not neccessary... 
 231 //--------------------------------------------------------------------------- 
 232 // wxQTMediaBackend::CreateControl 
 234 // 1) Intializes QuickTime 
 235 // 2) Creates the control window 
 236 //--------------------------------------------------------------------------- 
 237 bool wxQTMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,  
 242                                      const wxValidator
& validator
, 
 243                                      const wxString
& name
) 
 245     //Don't bother in Native control mode 
 246 #if defined( __WXMAC__ ) && TARGET_API_MAC_OSX && ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_2 )     
 247     if (!_wxIsQuickTime4Installed()) 
 255     // By default wxWindow(s) is created with a border - 
 256     // so we need to get rid of those 
 258     // Since we don't have a child window like most other 
 259     // backends, we don't need wxCLIP_CHILDREN 
 263 #if wxUSE_CREATEMOVIECONTROL     
 264     ctrl
->wxWindow::Create(parent
, id
, pos
, size
, 
 265                             m_ctrl
->MacRemoveBordersFromStyle(style
), 
 268     ctrl
->wxControl::Create(parent
, id
, pos
, size
, 
 269                             m_ctrl
->MacRemoveBordersFromStyle(style
), 
 276         ctrl
->SetValidator(validator
); 
 283 //--------------------------------------------------------------------------- 
 284 // wxQTMediaBackend::Load (file version) 
 286 // 1) Get an FSSpec from the Windows path name 
 288 // 3) Obtain the movie instance from the movie resource 
 289 // 4) Close the movie resource 
 291 //--------------------------------------------------------------------------- 
 292 bool wxQTMediaBackend::Load(const wxString
& fileName
) 
 301     wxMacFilename2FSSpec( fileName 
, &sfFile 
); 
 303     if (OpenMovieFile (&sfFile
, &movieResFile
, fsRdPerm
) != noErr
) 
 306     short movieResID 
= 0; 
 309     err 
= NewMovieFromFile ( 
 317     CloseMovieFile (movieResFile
); 
 324     return ::GetMoviesError() == noErr
; 
 327 //--------------------------------------------------------------------------- 
 328 // wxQTMediaBackend::Load (URL Version) 
 330 // 1) Build an escaped URI from location 
 331 // 2) Create a handle to store the URI string 
 332 // 3) Put the URI string inside the handle 
 333 // 4) Make a QuickTime URL data ref from the handle with the URI in it 
 334 // 5) Clean up the URI string handle 
 335 // 6) Do some prerolling 
 337 //--------------------------------------------------------------------------- 
 338 bool wxQTMediaBackend::Load(const wxURI
& location
) 
 343     wxString theURI 
= location
.BuildURI(); 
 347     Handle theHandle 
= NewHandleClear(theURI
.length() + 1); 
 350     BlockMove(theURI
.mb_str(), *theHandle
, theURI
.length() + 1); 
 352     //create the movie from the handle that refers to the URI 
 353     err 
= NewMovieFromDataRef(&m_movie
, newMovieActive
,  
 355                                 URLDataHandlerSubType
); 
 357     DisposeHandle(theHandle
); 
 362     //preroll movie for streaming 
 363     //TODO:Async this using threads? 
 366     timeNow 
= GetMovieTime(m_movie
, NULL
); 
 367     playRate 
= GetMoviePreferredRate(m_movie
); 
 368     PrePrerollMovie(m_movie
, timeNow
, playRate
, NULL
, NULL
); 
 369     PrerollMovie(m_movie
, timeNow
, playRate
); 
 370     SetMovieRate(m_movie
, playRate
); 
 374     return ::GetMoviesError() == noErr
; 
 377 //--------------------------------------------------------------------------- 
 378 // wxQTMediaBackend::FinishLoad 
 380 // 1) Create the movie timer 
 381 // 2) Get real size of movie for GetBestSize/sizers 
 382 // 3) See if there is video in the movie, and if so then either 
 383 //    SetMovieGWorld if < 10.2 or use Native CreateMovieControl 
 384 // 4) Set the movie time scale to something usable so that seeking 
 385 //    etc.  will work correctly 
 386 // 5) Refresh parent window 
 387 //--------------------------------------------------------------------------- 
 388 void wxQTMediaBackend::FinishLoad() 
 390     m_timer 
= new _wxQTTimer(m_movie
, (wxQTMediaBackend
*) this); 
 393     //get the real size of the movie 
 395     ::GetMovieNaturalBoundsRect (m_movie
, &outRect
); 
 396     wxASSERT(::GetMoviesError() == noErr
); 
 398     m_bestSize
.x 
= outRect
.right 
- outRect
.left
; 
 399     m_bestSize
.y 
= outRect
.bottom 
- outRect
.top
; 
 401     //reparent movie/*AudioMediaCharacteristic*/ 
 402     if(GetMovieIndTrackType(m_movie
, 1,  
 403                             VisualMediaCharacteristic
,  
 404                             movieTrackCharacteristic 
|  
 405                                 movieTrackEnabledOnly
) != NULL
) 
 407 #if wxUSE_CREATEMOVIECONTROL     
 409     //Native CreateMovieControl QT control (Thanks to Kevin Olliver's 
 410     //wxQTMovie for some of this). 
 412     #define GetControlPeer(whatever) ctrl->m_peer 
 413     wxMediaCtrl
* ctrl 
= (wxMediaCtrl
*) m_ctrl
; 
 414         Rect bounds 
= wxMacGetBoundsForControl(m_ctrl
,  
 415                                                m_ctrl
->GetPosition(), 
 418     //Dispose of old control for new one 
 419     if (GetControlPeer(m_ctrl
) && GetControlPeer(m_ctrl
)->Ok() ) 
 420         GetControlPeer(m_ctrl
)->Dispose(); 
 423     //kMovieControlOptionXXX 
 424     //HideController - hide the movie controller 
 425     //LocateTopLeft - movie is pinned to top left rather than centered in the control 
 426     //EnableEditing - Allows programmatic editing and dragn'drop 
 427     //HandleEditingHI- Installs event stuff for edit menu - forces EnableEditing also 
 428     //SetKeysEnabled - Allows keyboard input 
 429     //ManuallyIdled - app handles movie idling rather than internal timer event loop 
 430         ::CreateMovieControl(  
 432                        ctrl
->MacGetTopLevelWindowRef(), //parent 
 433                        &bounds
,                                                         //control bounds 
 434                        m_movie
,                                                         //movie handle 
 435                        kMovieControlOptionHideController 
 
 436                        | kMovieControlOptionLocateTopLeft  
 
 437                        | kMovieControlOptionSetKeysEnabled 
 
 438 //                       | kMovieControlOptionManuallyIdled 
 440                        ctrl
->m_peer
->GetControlRefAddr() ); 
 442         ::EmbedControl(ctrl
->m_peer
->GetControlRef(), (ControlRef
)ctrl
->GetParent()->GetHandle()); 
 447         SetMovieGWorld(m_movie
,  
 451                        m_ctrl
->MacGetTopLevelWindowRef() 
 457     //we want millisecond precision 
 458     ::SetMovieTimeScale(m_movie
, 1000); 
 459     wxASSERT(::GetMoviesError() == noErr
); 
 462     //Here, if the parent of the control has a sizer - we 
 463     //tell it to recalculate the size of this control since 
 464     //the user opened a seperate media file 
 466     m_ctrl
->InvalidateBestSize(); 
 467     m_ctrl
->GetParent()->Layout(); 
 468     m_ctrl
->GetParent()->Refresh(); 
 469     m_ctrl
->GetParent()->Update(); 
 472 //--------------------------------------------------------------------------- 
 473 // wxQTMediaBackend::Play 
 475 // 1) Start the QT movie 
 476 // 2) Start the movie loading timer 
 477 //--------------------------------------------------------------------------- 
 478 bool wxQTMediaBackend::Play() 
 480     ::StartMovie(m_movie
); 
 481     m_timer
->SetPaused(false); 
 482     m_timer
->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
); 
 483     return ::GetMoviesError() == noErr
; 
 486 //--------------------------------------------------------------------------- 
 487 // wxQTMediaBackend::Pause 
 490 // 2) Stop the movie timer 
 491 //--------------------------------------------------------------------------- 
 492 bool wxQTMediaBackend::Pause() 
 494     ::StopMovie(m_movie
); 
 495     m_timer
->SetPaused(true); 
 497     return ::GetMoviesError() == noErr
; 
 500 //--------------------------------------------------------------------------- 
 501 // wxQTMediaBackend::Stop 
 504 // 2) Stop the movie timer 
 505 // 3) Seek to the beginning of the movie 
 506 //--------------------------------------------------------------------------- 
 507 bool wxQTMediaBackend::Stop() 
 509     m_timer
->SetPaused(false); 
 512     ::StopMovie(m_movie
); 
 513     if(::GetMoviesError() != noErr
) 
 516     ::GoToBeginningOfMovie(m_movie
); 
 517     return ::GetMoviesError() == noErr
; 
 520 //--------------------------------------------------------------------------- 
 521 // wxQTMediaBackend::GetPlaybackRate 
 523 // 1) Get the movie playback rate from ::GetMovieRate 
 524 //--------------------------------------------------------------------------- 
 525 double wxQTMediaBackend::GetPlaybackRate() 
 527     return ( ((double)::GetMovieRate(m_movie
)) / 0x10000); 
 530 //--------------------------------------------------------------------------- 
 531 // wxQTMediaBackend::SetPlaybackRate 
 533 // 1) Convert dRate to Fixed and Set the movie rate through SetMovieRate 
 534 //--------------------------------------------------------------------------- 
 535 bool wxQTMediaBackend::SetPlaybackRate(double dRate
) 
 537     ::SetMovieRate(m_movie
, (Fixed
) (dRate 
* 0x10000)); 
 538     return ::GetMoviesError() == noErr
; 
 541 //--------------------------------------------------------------------------- 
 542 // wxQTMediaBackend::SetPosition 
 544 // 1) Create a time record struct (TimeRecord) with appropriate values 
 545 // 2) Pass struct to SetMovieTime 
 546 //--------------------------------------------------------------------------- 
 547 bool wxQTMediaBackend::SetPosition(wxLongLong where
) 
 549     TimeRecord theTimeRecord
; 
 550     memset(&theTimeRecord
, 0, sizeof(TimeRecord
)); 
 551     theTimeRecord
.value
.lo 
= where
.GetValue(); 
 552     theTimeRecord
.scale 
= ::GetMovieTimeScale(m_movie
); 
 553     theTimeRecord
.base 
= ::GetMovieTimeBase(m_movie
); 
 554     ::SetMovieTime(m_movie
, &theTimeRecord
); 
 556     if (::GetMoviesError() != noErr
) 
 562 //--------------------------------------------------------------------------- 
 563 // wxQTMediaBackend::GetPosition 
 565 // Calls GetMovieTime 
 566 //--------------------------------------------------------------------------- 
 567 wxLongLong 
wxQTMediaBackend::GetPosition() 
 569     return ::GetMovieTime(m_movie
, NULL
); 
 572 //--------------------------------------------------------------------------- 
 573 // wxQTMediaBackend::GetDuration 
 575 // Calls GetMovieDuration 
 576 //--------------------------------------------------------------------------- 
 577 wxLongLong 
wxQTMediaBackend::GetDuration() 
 579     return ::GetMovieDuration(m_movie
); 
 582 //--------------------------------------------------------------------------- 
 583 // wxQTMediaBackend::GetState 
 585 // Determines the current state - the timer keeps track of whether or not 
 586 // we are paused or stopped (if the timer is running we are playing) 
 587 //--------------------------------------------------------------------------- 
 588 wxMediaState 
wxQTMediaBackend::GetState() 
 590     if ( !m_timer 
|| (m_timer
->IsRunning() == false &&  
 591                       m_timer
->GetPaused() == false) ) 
 592         return wxMEDIASTATE_STOPPED
; 
 594     if( m_timer
->IsRunning() == true ) 
 595         return wxMEDIASTATE_PLAYING
; 
 597         return wxMEDIASTATE_PAUSED
; 
 600 //--------------------------------------------------------------------------- 
 601 // wxQTMediaBackend::Cleanup 
 603 // Diposes of the movie timer, Control if native, and stops and disposes 
 605 //--------------------------------------------------------------------------- 
 606 void wxQTMediaBackend::Cleanup() 
 611 #if wxUSE_CREATEMOVIECONTROL     
 612     DisposeControl(((wxMediaCtrl
*)m_ctrl
)->m_peer
->GetControlRef()); 
 616     DisposeMovie(m_movie
); 
 619 //--------------------------------------------------------------------------- 
 620 // wxQTMediaBackend::GetVideoSize 
 622 // Returns the actual size of the QT movie 
 623 //--------------------------------------------------------------------------- 
 624 wxSize 
wxQTMediaBackend::GetVideoSize() const 
 629 //--------------------------------------------------------------------------- 
 630 // wxQTMediaBackend::Move 
 632 // We need to do this even when using native qt control because  
 633 // CreateMovieControl is broken in this regard... 
 634 //--------------------------------------------------------------------------- 
 635 void wxQTMediaBackend::Move(int x
, int y
, int w
, int h
) 
 637 #if !wxUSE_CREATEMOVIECONTROL     
 642             m_ctrl
->GetParent()->MacWindowToRootWindow(&x
, &y
); 
 645         Rect theRect 
= {y
, x
, y
+h
, x
+w
}; 
 647         ::SetMovieBox(m_movie
, &theRect
); 
 648         wxASSERT(::GetMoviesError() == noErr
); 
 651     if(m_timer 
&& m_ctrl
) 
 653         m_ctrl
->GetParent()->MacWindowToRootWindow(&x
, &y
); 
 655         ::MoveControl( (ControlRef
) m_ctrl
->GetHandle(), x
, y 
); 
 656         m_ctrl
->GetParent()->Refresh(); 
 657         m_ctrl
->GetParent()->Update(); 
 663 //in source file that contains stuff you don't directly use 
 664 #include "wx/html/forcelnk.h" 
 665 FORCE_LINK_ME(basewxmediabackends
); 
 667 #endif //wxUSE_MEDIACTRL