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
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 // There are several known bugs with CreateMovieControl
14 // on systems > 10.2 - see main.c of QTCarbonShell sample for details
15 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
17 //===========================================================================
19 //===========================================================================
21 //---------------------------------------------------------------------------
22 // Pre-compiled header stuff
23 //---------------------------------------------------------------------------
25 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
26 #pragma implementation "mediactrl.h"
29 // For compilers that support precompilation, includes "wx.h".
30 #include "wx/wxprec.h"
36 //---------------------------------------------------------------------------
38 //---------------------------------------------------------------------------
39 #include "wx/mediactrl.h"
41 //---------------------------------------------------------------------------
43 //---------------------------------------------------------------------------
46 //---------------------------------------------------------------------------
47 // Whether or not to use OSX 10.2's CreateMovieControl for native QuickTime
48 // control - i.e. native positioning and event handling etc..
49 //---------------------------------------------------------------------------
50 #ifndef wxUSE_CREATEMOVIECONTROL
51 # if defined( __WXMAC_OSX__ ) && \
52 ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2 )
53 # define wxUSE_CREATEMOVIECONTROL 1
55 # define wxUSE_CREATEMOVIECONTROL 0
59 //---------------------------------------------------------------------------
60 // Height and Width of movie controller in the movie control
61 //---------------------------------------------------------------------------
65 //===========================================================================
66 // BACKEND DECLARATIONS
67 //===========================================================================
69 //---------------------------------------------------------------------------
73 //---------------------------------------------------------------------------
75 //---------------------------------------------------------------------------
77 //---------------------------------------------------------------------------
78 //uma is for wxMacFSSpec
79 #include "wx/mac/uma.h"
84 #include <QuickTimeComponents.h> //Standard QT stuff
86 #include <QuickTime/QuickTimeComponents.h>
89 class WXDLLIMPEXP_MEDIA wxQTMediaBackend
: public wxMediaBackendCommonBase
95 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
100 const wxValidator
& validator
,
101 const wxString
& name
);
104 virtual bool Pause();
107 virtual bool Load(const wxString
& fileName
);
108 virtual bool Load(const wxURI
& location
);
110 virtual wxMediaState
GetState();
112 virtual bool SetPosition(wxLongLong where
);
113 virtual wxLongLong
GetPosition();
114 virtual wxLongLong
GetDuration();
116 virtual void Move(int x
, int y
, int w
, int h
);
117 wxSize
GetVideoSize() const;
119 virtual double GetPlaybackRate();
120 virtual bool SetPlaybackRate(double dRate
);
122 virtual double GetVolume();
123 virtual bool SetVolume(double);
128 virtual bool ShowPlayerControls(wxMediaCtrlPlayerControls flags
);
132 // ------ Implementation from now on --------
134 void DoLoadBestSize();
135 void DoSetControllerVisible(wxMediaCtrlPlayerControls flags
);
137 //TODO: Last param actually long - does this work on 64bit machines?
138 static Boolean
MCFilterProc (MovieController theController
,
139 short action
, void *params
, long refCon
);
141 #if wxUSE_CREATEMOVIECONTROL
142 void DoCreateMovieControl();
144 Boolean
IsQuickTime4Installed();
145 void DoNewMovieController();
146 static void PPRMProc (Movie theMovie
, OSErr theErr
, void* theRefCon
);
149 wxSize m_bestSize
; // Original movie size
151 struct MovieType
** m_movie
; // QT Movie handle/instance
153 Movie m_movie
; // Movie instance
155 bool m_bPlaying
; // Whether media is playing or not
156 class wxTimer
* m_timer
; // Timer for streaming the movie
157 MovieController m_mc
; // MovieController instance
158 wxMediaCtrlPlayerControls m_interfaceflags
; // Saved interface flags
159 #if !wxUSE_CREATEMOVIECONTROL
160 EventHandlerRef m_pEventHandlerRef
; // Event handler to cleanup
162 friend class wxQTMediaEvtHandler
;
164 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend
)
167 #if !wxUSE_CREATEMOVIECONTROL
168 // helper to hijack background erasing for the QT window
169 class WXDLLIMPEXP_MEDIA wxQTMediaEvtHandler
: public wxEvtHandler
172 wxQTMediaEvtHandler(wxQTMediaBackend
*qtb
)
176 qtb
->m_ctrl
->Connect(qtb
->m_ctrl
->GetId(), wxEVT_ERASE_BACKGROUND
,
177 wxEraseEventHandler(wxQTMediaEvtHandler::OnEraseBackground
),
181 void OnEraseBackground(wxEraseEvent
& event
);
184 wxQTMediaBackend
*m_qtb
;
186 DECLARE_NO_COPY_CLASS(wxQTMediaEvtHandler
)
189 // Window event handler
190 static pascal OSStatus
wxQTMediaWindowEventHandler(
191 EventHandlerCallRef inHandlerCallRef
,
192 EventRef inEvent
, void *inUserData
);
193 DEFINE_ONE_SHOT_HANDLER_GETTER( wxQTMediaWindowEventHandler
);
197 //===========================================================================
199 //===========================================================================
202 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
206 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
208 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend
, wxMediaBackend
);
210 //Time between timer calls - this is the Apple recommondation to the TCL
212 #define MOVIE_DELAY 20
214 //---------------------------------------------------------------------------
215 // wxQTMediaLoadTimer
217 // QT, esp. QT for Windows is very picky about how you go about
218 // async loading. If you were to go through a Windows message loop
219 // or a MoviesTask or both and then check the movie load state
220 // it would still return 1000 (loading)... even (pre)prerolling doesn't
221 // help. However, making a load timer like this works
222 //---------------------------------------------------------------------------
223 class wxQTMediaLoadTimer
: public wxTimer
226 wxQTMediaLoadTimer(Movie movie
, wxQTMediaBackend
* parent
) :
227 m_movie(movie
), m_parent(parent
) {}
231 //Note that the CreateMovieControl variety performs
232 //its own custom idleing
233 #if !wxUSE_CREATEMOVIECONTROL
234 ::MCIdle(m_parent
->m_mc
);
236 //kMovieLoadStatePlayable is not enough on MAC
237 //- it plays, but IsMovieDone might return true (!)
238 //sure we need to wait until kMovieLoadStatePlaythroughOK
239 if(::GetMovieLoadState(m_movie
) >= 20000)
241 m_parent
->FinishLoad();
247 Movie m_movie
; //Our movie instance
248 wxQTMediaBackend
* m_parent
; //Backend pointer
251 // --------------------------------------------------------------------------
252 // wxQTMediaPlayTimer - Handle Asyncronous Playing
254 // 1) Checks to see if the movie is done, and if not continues
255 // streaming the movie
256 // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
258 // --------------------------------------------------------------------------
259 class wxQTMediaPlayTimer
: public wxTimer
262 wxQTMediaPlayTimer(Movie movie
, wxQTMediaBackend
* parent
) :
263 m_movie(movie
), m_parent(parent
) {}
267 //Note that CreateMovieControl performs its own idleing
268 #if !wxUSE_CREATEMOVIECONTROL
270 // OK, a little explaining - basically originally
271 // we only called MoviesTask if the movie was actually
272 // playing (not paused or stopped)... this was before
273 // we realized MoviesTask actually handles repainting
274 // of the current frame - so if you were to resize
275 // or something it would previously not redraw that
276 // portion of the movie.
278 // So now we call MoviesTask always so that it repaints
281 ::MCIdle(m_parent
->m_mc
);
285 // Handle the stop event - if the movie has reached
286 // the end, notify our handler
288 if(::IsMovieDone(m_movie
))
290 if ( m_parent
->SendStopEvent() )
293 wxASSERT(::GetMoviesError() == noErr
);
295 m_parent
->QueueFinishEvent();
301 Movie m_movie
; //Our movie instance
302 wxQTMediaBackend
* m_parent
; //Backend pointer
306 //---------------------------------------------------------------------------
307 // wxQTMediaBackend Constructor
309 // Sets m_timer to NULL signifying we havn't loaded anything yet
310 //---------------------------------------------------------------------------
311 wxQTMediaBackend::wxQTMediaBackend()
312 : m_movie(NULL
), m_bPlaying(false), m_timer(NULL
)
313 , m_mc(NULL
), m_interfaceflags(wxMEDIACTRLPLAYERCONTROLS_NONE
)
317 //---------------------------------------------------------------------------
318 // wxQTMediaBackend Destructor
320 // 1) Cleans up the QuickTime movie instance
321 // 2) Decrements the QuickTime reference counter - if this reaches
322 // 0, QuickTime shuts down
323 // 3) Decrements the QuickTime Windows Media Layer reference counter -
324 // if this reaches 0, QuickTime shuts down the Windows Media Layer
325 //---------------------------------------------------------------------------
326 wxQTMediaBackend::~wxQTMediaBackend()
331 #if !wxUSE_CREATEMOVIECONTROL
332 // Cleanup for moviecontroller
335 // destroy wxQTMediaEvtHandler we pushed on it
336 m_ctrl
->PopEventHandler(true);
337 RemoveEventHandler((EventHandlerRef
&)m_pEventHandlerRef
);
338 ::DisposeMovieController(m_mc
);
342 //Note that ExitMovies() is not necessary...
346 //---------------------------------------------------------------------------
347 // wxQTMediaBackend::CreateControl
349 // 1) Intializes QuickTime
350 // 2) Creates the control window
351 //---------------------------------------------------------------------------
352 bool wxQTMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
357 const wxValidator
& validator
,
358 const wxString
& name
)
360 //Don't bother in Native control mode
361 #if !wxUSE_CREATEMOVIECONTROL
362 if (!IsQuickTime4Installed())
370 // By default wxWindow(s) is created with a border -
371 // so we need to get rid of those
373 // Since we don't have a child window like most other
374 // backends, we don't need wxCLIP_CHILDREN
376 if ( !ctrl
->wxControl::Create(parent
, id
, pos
, size
,
377 wxWindow::MacRemoveBordersFromStyle(style
),
383 ctrl
->SetValidator(validator
);
386 m_ctrl
= (wxMediaCtrl
*)ctrl
;
390 //---------------------------------------------------------------------------
391 // wxQTMediaBackend::IsQuickTime4Installed
393 // Determines whether version 4 of QT is installed
394 // (Pretty much for classic only)
395 //---------------------------------------------------------------------------
396 #if !wxUSE_CREATEMOVIECONTROL
397 Boolean
wxQTMediaBackend::IsQuickTime4Installed()
402 error
= Gestalt (gestaltQuickTime
, &result
);
403 return (error
== noErr
) && (((result
>> 16) & 0xffff) >= 0x0400);
407 //---------------------------------------------------------------------------
408 // wxQTMediaBackend::Load (file version)
410 // 1) Get an FSSpec from the Windows path name
412 // 3) Obtain the movie instance from the movie resource
413 // 4) Close the movie resource
415 //---------------------------------------------------------------------------
416 bool wxQTMediaBackend::Load(const wxString
& fileName
)
425 //FIXME:wxMacFilename2FSSpec crashes on empty string -
426 //does it crash on other strings too and should this
427 //"fix" be put in the carbon wxSound?
428 if (fileName
.empty())
431 wxMacFilename2FSSpec( fileName
, &sfFile
);
433 if (OpenMovieFile (&sfFile
, &movieResFile
, fsRdPerm
) != noErr
)
436 short movieResID
= 0;
439 err
= NewMovieFromFile (
447 //No ::GetMoviesStickyError() here because it returns -2009
448 // a.k.a. invalid track on valid mpegs
451 ::CloseMovieFile (movieResFile
);
453 // Create movie controller/control
454 #if wxUSE_CREATEMOVIECONTROL
455 DoCreateMovieControl();
457 DoNewMovieController();
468 //---------------------------------------------------------------------------
469 // wxQTMediaBackend::PPRMProc (static)
471 // Called when done PrePrerolling the movie.
472 // Note that in 99% of the cases this does nothing...
473 // Anyway we set up the loading timer here to tell us when the movie is done
474 //---------------------------------------------------------------------------
475 #if !wxUSE_CREATEMOVIECONTROL
476 void wxQTMediaBackend::PPRMProc (Movie theMovie
,
477 OSErr
WXUNUSED_UNLESS_DEBUG(theErr
),
480 wxASSERT( theMovie
);
481 wxASSERT( theRefCon
);
482 wxASSERT( theErr
== noErr
);
484 wxQTMediaBackend
* pBE
= (wxQTMediaBackend
*) theRefCon
;
486 long lTime
= ::GetMovieTime(theMovie
,NULL
);
487 Fixed rate
= ::GetMoviePreferredRate(theMovie
);
488 ::PrerollMovie(theMovie
,lTime
,rate
);
489 pBE
->m_timer
= new wxQTMediaLoadTimer(pBE
->m_movie
, pBE
);
490 pBE
->m_timer
->Start(MOVIE_DELAY
);
494 //---------------------------------------------------------------------------
495 // wxQTMediaBackend::Load (URL Version)
497 // 1) Build an escaped URI from location
498 // 2) Create a handle to store the URI string
499 // 3) Put the URI string inside the handle
500 // 4) Make a QuickTime URL data ref from the handle with the URI in it
501 // 5) Clean up the URI string handle
502 // 6) Do some prerolling
504 //---------------------------------------------------------------------------
505 bool wxQTMediaBackend::Load(const wxURI
& location
)
510 wxString theURI
= location
.BuildURI();
514 Handle theHandle
= ::NewHandleClear(theURI
.length() + 1);
517 ::BlockMove(theURI
.mb_str(), *theHandle
, theURI
.length() + 1);
519 //create the movie from the handle that refers to the URI
520 err
= ::NewMovieFromDataRef(&m_movie
, newMovieActive
|
522 /*|newMovieIdleImportOK*/,
524 URLDataHandlerSubType
);
526 ::DisposeHandle(theHandle
);
530 #if wxUSE_CREATEMOVIECONTROL
531 // Movie control resets prerolling, so we must create first
532 DoCreateMovieControl();
534 // Setup timer to catch load event
535 m_timer
= new wxQTMediaLoadTimer(m_movie
, this);
536 m_timer
->Start(MOVIE_DELAY
);
538 // Movie controller resets prerolling, so we must create first
539 DoNewMovieController();
544 timeNow
= ::GetMovieTime(m_movie
, NULL
);
545 wxASSERT(::GetMoviesError() == noErr
);
547 playRate
= ::GetMoviePreferredRate(m_movie
);
548 wxASSERT(::GetMoviesError() == noErr
);
551 // Note that the callback here is optional,
552 // but without it PrePrerollMovie can be buggy
553 // (see Apple ml). Also, some may wonder
554 // why we need this at all - this is because
555 // Apple docs say QuickTime streamed movies
556 // require it if you don't use a Movie Controller,
557 // which we don't by default.
559 ::PrePrerollMovie(m_movie
, timeNow
, playRate
,
560 wxQTMediaBackend::PPRMProc
,
569 //---------------------------------------------------------------------------
570 // wxQTMediaBackend::DoCreateMovieControl
572 // Calls CreateMovieControl and performs setup related to it
574 // Note that we always hide the controller initially becuase when loading
575 // from a url it displays about a 40x40 box with the word loading... in it,
576 // but the box is outside the range of the control, which is bad (0,0
577 // i believe), so we need to wait until finishload to actually display
578 // the movie controller in this instance
579 //---------------------------------------------------------------------------
580 #if wxUSE_CREATEMOVIECONTROL
581 void wxQTMediaBackend::DoCreateMovieControl()
584 //Native CreateMovieControl QT control (Thanks to Kevin Olliver's
585 //wxQTMovie for some of this).
587 Rect bounds
= wxMacGetBoundsForControl(m_ctrl
,
588 m_ctrl
->GetPosition(),
591 //Dispose of old control for new one
592 if (m_ctrl
->m_peer
&& m_ctrl
->m_peer
->Ok() )
593 m_ctrl
->m_peer
->Dispose();
596 //kMovieControlOptionXXX
597 //HideController - hide the movie controller
598 //LocateTopLeft - movie is pinned to top left rather than centered in the control
599 //EnableEditing - Allows programmatic editing and dragn'drop
600 //HandleEditingHI- Installs event stuff for edit menu - forces EnableEditing also
601 //SetKeysEnabled - Allows keyboard input
602 //ManuallyIdled - app handles movie idling rather than internal timer event loop
603 ::CreateMovieControl(
605 m_ctrl
->MacGetTopLevelWindowRef(), //parent
606 &bounds
, //control bounds
607 m_movie
, //movie handle
608 kMovieControlOptionHideController
609 | kMovieControlOptionLocateTopLeft
610 | kMovieControlOptionSetKeysEnabled
611 // | kMovieControlOptionManuallyIdled
613 m_ctrl
->m_peer
->GetControlRefAddr() );
615 ::EmbedControl(m_ctrl
->m_peer
->GetControlRef(),
616 (ControlRef
)m_ctrl
->GetParent()->GetHandle());
619 // Setup MovieController for the new movie
623 //Get movie controller from our control
624 ::GetControlData( m_ctrl
->m_peer
->GetControlRef(), 0,
625 kMovieControlDataMovieController
,
626 sizeof(MovieController
), (Ptr
)&m_mc
, &dataSize
);
628 // Setup a callback so we can tell when the user presses
629 // play on the player controls
630 ::MCSetActionFilterWithRefCon(m_mc
,
631 wxQTMediaBackend::MCFilterProc
, (long)this);
635 //---------------------------------------------------------------------------
636 // wxQTMediaBackend::DoNewMovieController
638 // Attaches movie to moviecontroller or creates moviecontroller
639 // if not created yet
640 //---------------------------------------------------------------------------
641 #if !wxUSE_CREATEMOVIECONTROL
642 void wxQTMediaBackend::DoNewMovieController()
646 // Get top level window ref for some mac functions
647 WindowRef wrTLW
= (WindowRef
) m_ctrl
->MacGetTopLevelWindowRef();
649 // MovieController not setup yet -
650 // so we need to create a new one.
651 // You have to pass a valid movie to
652 // NewMovieController, evidently
653 ::SetMovieGWorld(m_movie
,
654 (CGrafPtr
) GetWindowPort(wrTLW
),
656 wxASSERT(::GetMoviesError() == noErr
);
658 Rect bounds
= wxMacGetBoundsForControl(m_ctrl
,
659 m_ctrl
->GetPosition(),
662 m_mc
= ::NewMovieController(m_movie
, &bounds
, mcTopLeftMovie
|
665 wxASSERT(::GetMoviesError() == noErr
);
666 ::MCDoAction(m_mc
, 32, (void*)true); //mcActionSetKeysEnabled
667 wxASSERT(::GetMoviesError() == noErr
);
669 // Setup a callback so we can tell when the user presses
670 // play on the player controls
671 ::MCSetActionFilterWithRefCon(m_mc
,
672 wxQTMediaBackend::MCFilterProc
, (long)this);
673 wxASSERT(::GetMoviesError() == noErr
);
675 //Part of a suggestion from Greg Hazel to repaint
677 m_ctrl
->PushEventHandler(new wxQTMediaEvtHandler(this));
679 // Event types to catch from the TLW
680 // for the moviecontroller
681 EventTypeSpec theEventTypes
[] = {
682 { kEventClassMouse
, kEventMouseDown
},
683 { kEventClassMouse
, kEventMouseUp
},
684 { kEventClassKeyboard
, kEventRawKeyDown
},
685 { kEventClassKeyboard
, kEventRawKeyRepeat
},
686 { kEventClassKeyboard
, kEventRawKeyUp
},
687 { kEventClassWindow
, kEventWindowUpdate
},
688 { kEventClassWindow
, kEventWindowActivated
},
689 { kEventClassWindow
, kEventWindowDeactivated
}
692 // Catch window messages -
693 // if we do not do this and if the user clicks the play
694 // button on the controller, for instance, nothing will happen...
695 InstallWindowEventHandler( wrTLW
,
696 GetwxQTMediaWindowEventHandlerUPP(),
697 GetEventTypeCount( theEventTypes
), theEventTypes
,
698 m_mc
, (&(EventHandlerRef
&)m_pEventHandlerRef
) );
702 // MovieController already created -
703 // Just change the movie in it and we're good to go
705 thePoint
.h
= thePoint
.v
= 0;
706 ::MCSetMovie(m_mc
, m_movie
,
707 (WindowRef
)m_ctrl
->MacGetTopLevelWindowRef(),
709 wxASSERT(::GetMoviesError() == noErr
);
714 //---------------------------------------------------------------------------
715 // wxQTMediaBackend::FinishLoad
717 // Performs operations after a movie ready to play/loaded.
718 //---------------------------------------------------------------------------
719 void wxQTMediaBackend::FinishLoad()
721 // get the real size of the movie
724 // Show the player controls if the user wants to
726 DoSetControllerVisible(m_interfaceflags
);
728 //we want millisecond precision
729 ::SetMovieTimeScale(m_movie
, 1000);
730 wxASSERT(::GetMoviesError() == noErr
);
732 // Start movie progress timer
733 m_timer
= new wxQTMediaPlayTimer(m_movie
, (wxQTMediaBackend
*) this);
735 m_timer
->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
);
737 //send loaded event & refresh size
741 //---------------------------------------------------------------------------
742 // wxQTMediaBackend::DoLoadBestSize
744 // Sets the best size of the control from the real size of the movie
745 //---------------------------------------------------------------------------
746 void wxQTMediaBackend::DoLoadBestSize()
748 //get the real size of the movie
750 ::GetMovieNaturalBoundsRect (m_movie
, &outRect
);
751 wxASSERT(::GetMoviesError() == noErr
);
753 //determine best size
754 m_bestSize
.x
= outRect
.right
- outRect
.left
;
755 m_bestSize
.y
= outRect
.bottom
- outRect
.top
;
758 //---------------------------------------------------------------------------
759 // wxQTMediaBackend::Play
761 // Start the QT movie
762 //---------------------------------------------------------------------------
763 bool wxQTMediaBackend::Play()
765 Fixed fixRate
= (Fixed
) (wxQTMediaBackend::GetPlaybackRate() * 0x10000);
767 fixRate
= ::GetMoviePreferredRate(m_movie
);
769 wxASSERT(fixRate
!= 0);
772 ::MCDoAction( m_mc
, 8, // mcActionPlay
776 return ::GetMoviesError() == noErr
;
779 //---------------------------------------------------------------------------
780 // wxQTMediaBackend::Pause
783 //---------------------------------------------------------------------------
784 bool wxQTMediaBackend::Pause()
786 //Stop the movie A.K.A. ::StopMovie(m_movie);
789 ::MCDoAction( m_mc
, 8 /*mcActionPlay*/,
792 return ::GetMoviesError() == noErr
;
794 return true; //already paused
797 //---------------------------------------------------------------------------
798 // wxQTMediaBackend::Stop
801 // 2) Seek to the beginning of the movie
802 //---------------------------------------------------------------------------
803 bool wxQTMediaBackend::Stop()
805 if(!wxQTMediaBackend::Pause())
808 ::GoToBeginningOfMovie(m_movie
);
809 return ::GetMoviesError() == noErr
;
812 //---------------------------------------------------------------------------
813 // wxQTMediaBackend::GetPlaybackRate
815 // 1) Get the movie playback rate from ::GetMovieRate
816 //---------------------------------------------------------------------------
817 double wxQTMediaBackend::GetPlaybackRate()
819 return ( ((double)::GetMovieRate(m_movie
)) / 0x10000);
822 //---------------------------------------------------------------------------
823 // wxQTMediaBackend::SetPlaybackRate
825 // 1) Convert dRate to Fixed and Set the movie rate through SetMovieRate
826 //---------------------------------------------------------------------------
827 bool wxQTMediaBackend::SetPlaybackRate(double dRate
)
829 ::SetMovieRate(m_movie
, (Fixed
) (dRate
* 0x10000));
830 return ::GetMoviesError() == noErr
;
833 //---------------------------------------------------------------------------
834 // wxQTMediaBackend::SetPosition
836 // 1) Create a time record struct (TimeRecord) with appropriate values
837 // 2) Pass struct to SetMovieTime
838 //---------------------------------------------------------------------------
839 bool wxQTMediaBackend::SetPosition(wxLongLong where
)
841 TimeRecord theTimeRecord
;
842 memset(&theTimeRecord
, 0, sizeof(TimeRecord
));
843 theTimeRecord
.value
.lo
= where
.GetValue();
844 theTimeRecord
.scale
= ::GetMovieTimeScale(m_movie
);
845 theTimeRecord
.base
= ::GetMovieTimeBase(m_movie
);
846 ::SetMovieTime(m_movie
, &theTimeRecord
);
848 if (::GetMoviesError() != noErr
)
854 //---------------------------------------------------------------------------
855 // wxQTMediaBackend::GetPosition
857 // Calls GetMovieTime
858 //---------------------------------------------------------------------------
859 wxLongLong
wxQTMediaBackend::GetPosition()
861 return ::GetMovieTime(m_movie
, NULL
);
864 //---------------------------------------------------------------------------
865 // wxQTMediaBackend::GetVolume
867 // Gets the volume through GetMovieVolume - which returns a 16 bit short -
869 // +--------+--------+
871 // +--------+--------+
873 // (1) first 8 bits are value before decimal
874 // (2) second 8 bits are value after decimal
876 // Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
877 // 1 (full gain and sound)
878 //---------------------------------------------------------------------------
879 double wxQTMediaBackend::GetVolume()
881 short sVolume
= ::GetMovieVolume(m_movie
);
883 if(sVolume
& (128 << 8)) //negative - no sound
886 return sVolume
/256.0;
889 //---------------------------------------------------------------------------
890 // wxQTMediaBackend::SetVolume
892 // Sets the volume through SetMovieVolume - which takes a 16 bit short -
894 // +--------+--------+
896 // +--------+--------+
898 // (1) first 8 bits are value before decimal
899 // (2) second 8 bits are value after decimal
901 // Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
902 // 1 (full gain and sound)
903 //---------------------------------------------------------------------------
904 bool wxQTMediaBackend::SetVolume(double dVolume
)
906 ::SetMovieVolume(m_movie
, (short) (dVolume
* 256));
910 //---------------------------------------------------------------------------
911 // wxQTMediaBackend::GetDuration
913 // Calls GetMovieDuration
914 //---------------------------------------------------------------------------
915 wxLongLong
wxQTMediaBackend::GetDuration()
917 return ::GetMovieDuration(m_movie
);
920 //---------------------------------------------------------------------------
921 // wxQTMediaBackend::GetState
923 // Determines the current state - the timer keeps track of whether or not
924 // we are paused or stopped (if the timer is running we are playing)
925 //---------------------------------------------------------------------------
926 wxMediaState
wxQTMediaBackend::GetState()
929 // GetMovieActive/IsMovieDone/SetMovieActive
930 // combo if implemented that way
931 if (m_bPlaying
== true)
932 return wxMEDIASTATE_PLAYING
;
933 else if ( !m_movie
|| wxQTMediaBackend::GetPosition() == 0)
934 return wxMEDIASTATE_STOPPED
;
936 return wxMEDIASTATE_PAUSED
;
939 //---------------------------------------------------------------------------
940 // wxQTMediaBackend::Cleanup
942 // Diposes of the movie timer, Control if native, and stops and disposes
944 //---------------------------------------------------------------------------
945 void wxQTMediaBackend::Cleanup()
955 // Apple samples with CreateMovieControl typically
956 // install a event handler and do this on the dispose
957 // event, but we do it here for simplicity
958 // (It might keep playing for several seconds after
959 // control destruction if not)
960 wxQTMediaBackend::Pause();
963 // Dispose of control or remove movie from MovieController
965 #if wxUSE_CREATEMOVIECONTROL
966 if (m_ctrl
->m_peer
&& m_ctrl
->m_peer
->Ok() )
967 m_ctrl
->m_peer
->Dispose();
970 thePoint
.h
= thePoint
.v
= 0;
971 ::MCSetVisible(m_mc
, false);
972 ::MCSetMovie(m_mc
, NULL
, NULL
, thePoint
);
975 ::DisposeMovie(m_movie
);
978 //---------------------------------------------------------------------------
979 // wxQTMediaBackend::MCFilterProc (static)
981 // Callback for when the movie controller recieves a message
982 //---------------------------------------------------------------------------
983 Boolean
wxQTMediaBackend::MCFilterProc(
984 MovieController
WXUNUSED(theController
),
986 void * WXUNUSED(params
),
989 if(action
!= 1) //don't process idle events
991 wxQTMediaBackend
* pThis
= (wxQTMediaBackend
*)refCon
;
995 case 8: //play button triggered - MC will set movie to opposite state
996 //of current - playing ? paused : playing
997 pThis
->m_bPlaying
= !(pThis
->m_bPlaying
);
1006 //---------------------------------------------------------------------------
1007 // wxQTMediaBackend::GetVideoSize
1009 // Returns the actual size of the QT movie
1010 //---------------------------------------------------------------------------
1011 wxSize
wxQTMediaBackend::GetVideoSize() const
1016 //---------------------------------------------------------------------------
1017 // wxQTMediaBackend::Move
1019 // We need to do this even when using native qt control because
1020 // CreateMovieControl is broken in this regard...
1021 //---------------------------------------------------------------------------
1022 void wxQTMediaBackend::Move(int x
, int y
, int w
, int h
)
1024 #if !wxUSE_CREATEMOVIECONTROL
1027 m_ctrl
->GetParent()->MacWindowToRootWindow(&x
, &y
);
1028 Rect theRect
= {y
, x
, y
+h
, x
+w
};
1030 ::MCSetControllerBoundsRect(m_mc
, &theRect
);
1031 wxASSERT(::GetMoviesError() == noErr
);
1034 if(m_timer
&& m_ctrl
)
1036 m_ctrl
->GetParent()->MacWindowToRootWindow(&x
, &y
);
1038 ::MoveControl( (ControlRef
) m_ctrl
->GetHandle(), x
, y
);
1039 m_ctrl
->GetParent()->Refresh();
1040 m_ctrl
->GetParent()->Update();
1045 //---------------------------------------------------------------------------
1046 // wxQTMediaBackend::DoSetControllerVisible
1048 // Utility function that takes care of showing the moviecontroller
1049 // and showing/hiding the particular controls on it
1050 //---------------------------------------------------------------------------
1051 void wxQTMediaBackend::DoSetControllerVisible(wxMediaCtrlPlayerControls flags
)
1053 ::MCSetVisible(m_mc
, TRUE
);
1056 // Take care of subcontrols
1058 if(::GetMoviesError() == noErr
)
1061 ::MCDoAction(m_mc
, 39/*mcActionGetFlags*/, (void*)&mcFlags
);
1063 if(::GetMoviesError() == noErr
)
1065 mcFlags
|= ( //(1<<0)/*mcFlagSuppressMovieFrame*/ |
1066 (1<<3)/*mcFlagsUseWindowPalette*/
1067 | ((flags
& wxMEDIACTRLPLAYERCONTROLS_STEP
)
1068 ? 0 : (1<<1)/*mcFlagSuppressStepButtons*/)
1069 | ((flags
& wxMEDIACTRLPLAYERCONTROLS_VOLUME
)
1070 ? 0 : (1<<2)/*mcFlagSuppressSpeakerButton*/)
1071 // | (1<<4) /*mcFlagDontInvalidate*/ //if we take care of repainting ourselves
1073 ::MCDoAction(m_mc
, 38/*mcActionSetFlags*/, (void*)mcFlags
);
1078 //Adjust height and width of best size for movie controller
1079 //if the user wants it shown
1081 m_bestSize
.x
= m_bestSize
.x
> wxMCWIDTH
? m_bestSize
.x
: wxMCWIDTH
;
1082 m_bestSize
.y
+= wxMCHEIGHT
;
1085 //---------------------------------------------------------------------------
1086 // wxQTMediaBackend::ShowPlayerControls
1088 // Shows/Hides subcontrols on the media control
1089 //---------------------------------------------------------------------------
1090 bool wxQTMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags
)
1093 return false; //no movie controller...
1095 bool bSizeChanged
= false;
1097 //if the controller is visible and we want to hide it do so
1098 if(m_interfaceflags
&& !flags
)
1100 bSizeChanged
= true;
1102 ::MCSetVisible(m_mc
, FALSE
);
1104 else if(!m_interfaceflags
&& flags
) //show controller if hidden
1106 bSizeChanged
= true;
1107 DoSetControllerVisible(flags
);
1110 //readjust parent sizers
1113 NotifyMovieSizeChanged();
1115 //remember state in case of loading new media
1116 m_interfaceflags
= flags
;
1119 return ::GetMoviesError() == noErr
;
1122 //---------------------------------------------------------------------------
1123 // wxQTMediaBackend::OnEraseBackground
1125 // Suggestion from Greg Hazel to repaint the movie when idle
1127 //---------------------------------------------------------------------------
1128 #if !wxUSE_CREATEMOVIECONTROL
1129 void wxQTMediaEvtHandler::OnEraseBackground(wxEraseEvent
& evt
)
1131 // Work around Nasty OSX drawing bug -
1132 // http://lists.apple.com/archives/QuickTime-API/2002/Feb/msg00311.html
1134 (WindowRef
) m_qtb
->m_ctrl
->MacGetTopLevelWindowRef();
1136 RgnHandle region
= MCGetControllerBoundsRgn(m_qtb
->m_mc
);
1137 MCInvalidate(m_qtb
->m_mc
, wrTLW
, region
);
1138 MCIdle(m_qtb
->m_mc
);
1142 //---------------------------------------------------------------------------
1143 // wxQTMediaWindowEventHandler
1145 // Event callback for the top level window of our control that passes
1146 // messages to our moviecontroller so it can recieve mouse clicks etc.
1147 //---------------------------------------------------------------------------
1148 #if !wxUSE_CREATEMOVIECONTROL
1149 OSStatus
wxQTMediaWindowEventHandler(EventHandlerCallRef inHandlerCallRef
,
1150 EventRef inEvent
, void *inUserData
)
1152 EventRecord theEvent
;
1153 ConvertEventRefToEventRecord( inEvent
, &theEvent
);
1155 err
= ::MCIsPlayerEvent( (MovieController
) inUserData
, &theEvent
);
1157 // pass on to other event handlers if not handled- i.e. wx
1161 return eventNotHandledErr
;
1165 //in source file that contains stuff you don't directly use
1166 #include "wx/html/forcelnk.h"
1167 FORCE_LINK_ME(basewxmediabackends
);
1169 #endif //wxUSE_MEDIACTRL