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 // For compilers that support precompilation, includes "wx.h".
26 #include "wx/wxprec.h"
32 //---------------------------------------------------------------------------
34 //---------------------------------------------------------------------------
35 #include "wx/mediactrl.h"
37 //---------------------------------------------------------------------------
39 //---------------------------------------------------------------------------
42 //---------------------------------------------------------------------------
43 // Whether or not to use OSX 10.2's CreateMovieControl for native QuickTime
44 // control - i.e. native positioning and event handling etc..
45 //---------------------------------------------------------------------------
46 #ifndef wxUSE_CREATEMOVIECONTROL
47 # if defined( __WXMAC_OSX__ ) && \
48 ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2 )
49 # define wxUSE_CREATEMOVIECONTROL 1
51 # define wxUSE_CREATEMOVIECONTROL 0
55 //---------------------------------------------------------------------------
56 // Height and Width of movie controller in the movie control
57 //---------------------------------------------------------------------------
61 //===========================================================================
62 // BACKEND DECLARATIONS
63 //===========================================================================
65 //---------------------------------------------------------------------------
69 //---------------------------------------------------------------------------
71 //---------------------------------------------------------------------------
73 //---------------------------------------------------------------------------
74 //uma is for wxMacFSSpec
75 #include "wx/mac/uma.h"
80 #include <QuickTimeComponents.h> //Standard QT stuff
82 #include <QuickTime/QuickTimeComponents.h>
85 class WXDLLIMPEXP_MEDIA wxQTMediaBackend
: public wxMediaBackendCommonBase
91 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
96 const wxValidator
& validator
,
97 const wxString
& name
);
100 virtual bool Pause();
103 virtual bool Load(const wxString
& fileName
);
104 virtual bool Load(const wxURI
& location
);
106 virtual wxMediaState
GetState();
108 virtual bool SetPosition(wxLongLong where
);
109 virtual wxLongLong
GetPosition();
110 virtual wxLongLong
GetDuration();
112 virtual void Move(int x
, int y
, int w
, int h
);
113 wxSize
GetVideoSize() const;
115 virtual double GetPlaybackRate();
116 virtual bool SetPlaybackRate(double dRate
);
118 virtual double GetVolume();
119 virtual bool SetVolume(double);
124 virtual bool ShowPlayerControls(wxMediaCtrlPlayerControls flags
);
128 // ------ Implementation from now on --------
130 void DoLoadBestSize();
131 void DoSetControllerVisible(wxMediaCtrlPlayerControls flags
);
133 //TODO: Last param actually long - does this work on 64bit machines?
134 static Boolean
MCFilterProc (MovieController theController
,
135 short action
, void *params
, long refCon
);
137 #if wxUSE_CREATEMOVIECONTROL
138 void DoCreateMovieControl();
140 Boolean
IsQuickTime4Installed();
141 void DoNewMovieController();
142 static void PPRMProc (Movie theMovie
, OSErr theErr
, void* theRefCon
);
145 wxSize m_bestSize
; // Original movie size
147 struct MovieType
** m_movie
; // QT Movie handle/instance
149 Movie m_movie
; // Movie instance
151 bool m_bPlaying
; // Whether media is playing or not
152 class wxTimer
* m_timer
; // Timer for streaming the movie
153 MovieController m_mc
; // MovieController instance
154 wxMediaCtrlPlayerControls m_interfaceflags
; // Saved interface flags
155 #if !wxUSE_CREATEMOVIECONTROL
156 EventHandlerRef m_pEventHandlerRef
; // Event handler to cleanup
158 friend class wxQTMediaEvtHandler
;
160 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend
)
163 #if !wxUSE_CREATEMOVIECONTROL
164 // helper to hijack background erasing for the QT window
165 class WXDLLIMPEXP_MEDIA wxQTMediaEvtHandler
: public wxEvtHandler
168 wxQTMediaEvtHandler(wxQTMediaBackend
*qtb
)
172 qtb
->m_ctrl
->Connect(qtb
->m_ctrl
->GetId(), wxEVT_ERASE_BACKGROUND
,
173 wxEraseEventHandler(wxQTMediaEvtHandler::OnEraseBackground
),
177 void OnEraseBackground(wxEraseEvent
& event
);
180 wxQTMediaBackend
*m_qtb
;
182 DECLARE_NO_COPY_CLASS(wxQTMediaEvtHandler
)
185 // Window event handler
186 static pascal OSStatus
wxQTMediaWindowEventHandler(
187 EventHandlerCallRef inHandlerCallRef
,
188 EventRef inEvent
, void *inUserData
);
189 DEFINE_ONE_SHOT_HANDLER_GETTER( wxQTMediaWindowEventHandler
);
193 //===========================================================================
195 //===========================================================================
198 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
202 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
204 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend
, wxMediaBackend
);
206 //Time between timer calls - this is the Apple recommondation to the TCL
208 #define MOVIE_DELAY 20
210 //---------------------------------------------------------------------------
211 // wxQTMediaLoadTimer
213 // QT, esp. QT for Windows is very picky about how you go about
214 // async loading. If you were to go through a Windows message loop
215 // or a MoviesTask or both and then check the movie load state
216 // it would still return 1000 (loading)... even (pre)prerolling doesn't
217 // help. However, making a load timer like this works
218 //---------------------------------------------------------------------------
219 class wxQTMediaLoadTimer
: public wxTimer
222 wxQTMediaLoadTimer(Movie movie
, wxQTMediaBackend
* parent
) :
223 m_movie(movie
), m_parent(parent
) {}
227 //Note that the CreateMovieControl variety performs
228 //its own custom idleing
229 #if !wxUSE_CREATEMOVIECONTROL
230 ::MCIdle(m_parent
->m_mc
);
232 //kMovieLoadStatePlayable is not enough on MAC
233 //- it plays, but IsMovieDone might return true (!)
234 //sure we need to wait until kMovieLoadStatePlaythroughOK
235 if(::GetMovieLoadState(m_movie
) >= 20000)
237 m_parent
->FinishLoad();
243 Movie m_movie
; //Our movie instance
244 wxQTMediaBackend
* m_parent
; //Backend pointer
247 // --------------------------------------------------------------------------
248 // wxQTMediaPlayTimer - Handle Asyncronous Playing
250 // 1) Checks to see if the movie is done, and if not continues
251 // streaming the movie
252 // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
254 // --------------------------------------------------------------------------
255 class wxQTMediaPlayTimer
: public wxTimer
258 wxQTMediaPlayTimer(Movie movie
, wxQTMediaBackend
* parent
) :
259 m_movie(movie
), m_parent(parent
) {}
263 //Note that CreateMovieControl performs its own idleing
264 #if !wxUSE_CREATEMOVIECONTROL
266 // OK, a little explaining - basically originally
267 // we only called MoviesTask if the movie was actually
268 // playing (not paused or stopped)... this was before
269 // we realized MoviesTask actually handles repainting
270 // of the current frame - so if you were to resize
271 // or something it would previously not redraw that
272 // portion of the movie.
274 // So now we call MoviesTask always so that it repaints
277 ::MCIdle(m_parent
->m_mc
);
281 // Handle the stop event - if the movie has reached
282 // the end, notify our handler
284 if(::IsMovieDone(m_movie
))
286 if ( m_parent
->SendStopEvent() )
289 wxASSERT(::GetMoviesError() == noErr
);
291 m_parent
->QueueFinishEvent();
297 Movie m_movie
; //Our movie instance
298 wxQTMediaBackend
* m_parent
; //Backend pointer
302 //---------------------------------------------------------------------------
303 // wxQTMediaBackend Constructor
305 // Sets m_timer to NULL signifying we havn't loaded anything yet
306 //---------------------------------------------------------------------------
307 wxQTMediaBackend::wxQTMediaBackend()
308 : m_movie(NULL
), m_bPlaying(false), m_timer(NULL
)
309 , m_mc(NULL
), m_interfaceflags(wxMEDIACTRLPLAYERCONTROLS_NONE
)
313 //---------------------------------------------------------------------------
314 // wxQTMediaBackend Destructor
316 // 1) Cleans up the QuickTime movie instance
317 // 2) Decrements the QuickTime reference counter - if this reaches
318 // 0, QuickTime shuts down
319 // 3) Decrements the QuickTime Windows Media Layer reference counter -
320 // if this reaches 0, QuickTime shuts down the Windows Media Layer
321 //---------------------------------------------------------------------------
322 wxQTMediaBackend::~wxQTMediaBackend()
327 #if !wxUSE_CREATEMOVIECONTROL
328 // Cleanup for moviecontroller
331 // destroy wxQTMediaEvtHandler we pushed on it
332 m_ctrl
->PopEventHandler(true);
333 RemoveEventHandler((EventHandlerRef
&)m_pEventHandlerRef
);
334 ::DisposeMovieController(m_mc
);
338 //Note that ExitMovies() is not necessary...
342 //---------------------------------------------------------------------------
343 // wxQTMediaBackend::CreateControl
345 // 1) Intializes QuickTime
346 // 2) Creates the control window
347 //---------------------------------------------------------------------------
348 bool wxQTMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
353 const wxValidator
& validator
,
354 const wxString
& name
)
356 //Don't bother in Native control mode
357 #if !wxUSE_CREATEMOVIECONTROL
358 if (!IsQuickTime4Installed())
366 // By default wxWindow(s) is created with a border -
367 // so we need to get rid of those
369 // Since we don't have a child window like most other
370 // backends, we don't need wxCLIP_CHILDREN
372 if ( !ctrl
->wxControl::Create(parent
, id
, pos
, size
,
373 wxWindow::MacRemoveBordersFromStyle(style
),
379 ctrl
->SetValidator(validator
);
382 m_ctrl
= (wxMediaCtrl
*)ctrl
;
386 //---------------------------------------------------------------------------
387 // wxQTMediaBackend::IsQuickTime4Installed
389 // Determines whether version 4 of QT is installed
390 // (Pretty much for classic only)
391 //---------------------------------------------------------------------------
392 #if !wxUSE_CREATEMOVIECONTROL
393 Boolean
wxQTMediaBackend::IsQuickTime4Installed()
398 error
= Gestalt (gestaltQuickTime
, &result
);
399 return (error
== noErr
) && (((result
>> 16) & 0xffff) >= 0x0400);
403 //---------------------------------------------------------------------------
404 // wxQTMediaBackend::Load (file version)
406 // 1) Get an FSSpec from the Windows path name
408 // 3) Obtain the movie instance from the movie resource
409 // 4) Close the movie resource
411 //---------------------------------------------------------------------------
412 bool wxQTMediaBackend::Load(const wxString
& fileName
)
421 //FIXME:wxMacFilename2FSSpec crashes on empty string -
422 //does it crash on other strings too and should this
423 //"fix" be put in the carbon wxSound?
424 if (fileName
.empty())
427 wxMacFilename2FSSpec( fileName
, &sfFile
);
429 if (OpenMovieFile (&sfFile
, &movieResFile
, fsRdPerm
) != noErr
)
432 short movieResID
= 0;
435 err
= NewMovieFromFile (
443 //No ::GetMoviesStickyError() here because it returns -2009
444 // a.k.a. invalid track on valid mpegs
447 ::CloseMovieFile (movieResFile
);
449 // Create movie controller/control
450 #if wxUSE_CREATEMOVIECONTROL
451 DoCreateMovieControl();
453 DoNewMovieController();
464 //---------------------------------------------------------------------------
465 // wxQTMediaBackend::PPRMProc (static)
467 // Called when done PrePrerolling the movie.
468 // Note that in 99% of the cases this does nothing...
469 // Anyway we set up the loading timer here to tell us when the movie is done
470 //---------------------------------------------------------------------------
471 #if !wxUSE_CREATEMOVIECONTROL
472 void wxQTMediaBackend::PPRMProc (Movie theMovie
,
473 OSErr
WXUNUSED_UNLESS_DEBUG(theErr
),
476 wxASSERT( theMovie
);
477 wxASSERT( theRefCon
);
478 wxASSERT( theErr
== noErr
);
480 wxQTMediaBackend
* pBE
= (wxQTMediaBackend
*) theRefCon
;
482 long lTime
= ::GetMovieTime(theMovie
,NULL
);
483 Fixed rate
= ::GetMoviePreferredRate(theMovie
);
484 ::PrerollMovie(theMovie
,lTime
,rate
);
485 pBE
->m_timer
= new wxQTMediaLoadTimer(pBE
->m_movie
, pBE
);
486 pBE
->m_timer
->Start(MOVIE_DELAY
);
490 //---------------------------------------------------------------------------
491 // wxQTMediaBackend::Load (URL Version)
493 // 1) Build an escaped URI from location
494 // 2) Create a handle to store the URI string
495 // 3) Put the URI string inside the handle
496 // 4) Make a QuickTime URL data ref from the handle with the URI in it
497 // 5) Clean up the URI string handle
498 // 6) Do some prerolling
500 //---------------------------------------------------------------------------
501 bool wxQTMediaBackend::Load(const wxURI
& location
)
506 wxString theURI
= location
.BuildURI();
510 Handle theHandle
= ::NewHandleClear(theURI
.length() + 1);
513 ::BlockMove(theURI
.mb_str(), *theHandle
, theURI
.length() + 1);
515 //create the movie from the handle that refers to the URI
516 err
= ::NewMovieFromDataRef(&m_movie
, newMovieActive
|
518 /*|newMovieIdleImportOK*/,
520 URLDataHandlerSubType
);
522 ::DisposeHandle(theHandle
);
526 #if wxUSE_CREATEMOVIECONTROL
527 // Movie control resets prerolling, so we must create first
528 DoCreateMovieControl();
530 // Setup timer to catch load event
531 m_timer
= new wxQTMediaLoadTimer(m_movie
, this);
532 m_timer
->Start(MOVIE_DELAY
);
534 // Movie controller resets prerolling, so we must create first
535 DoNewMovieController();
540 timeNow
= ::GetMovieTime(m_movie
, NULL
);
541 wxASSERT(::GetMoviesError() == noErr
);
543 playRate
= ::GetMoviePreferredRate(m_movie
);
544 wxASSERT(::GetMoviesError() == noErr
);
547 // Note that the callback here is optional,
548 // but without it PrePrerollMovie can be buggy
549 // (see Apple ml). Also, some may wonder
550 // why we need this at all - this is because
551 // Apple docs say QuickTime streamed movies
552 // require it if you don't use a Movie Controller,
553 // which we don't by default.
555 ::PrePrerollMovie(m_movie
, timeNow
, playRate
,
556 wxQTMediaBackend::PPRMProc
,
565 //---------------------------------------------------------------------------
566 // wxQTMediaBackend::DoCreateMovieControl
568 // Calls CreateMovieControl and performs setup related to it
570 // Note that we always hide the controller initially becuase when loading
571 // from a url it displays about a 40x40 box with the word loading... in it,
572 // but the box is outside the range of the control, which is bad (0,0
573 // i believe), so we need to wait until finishload to actually display
574 // the movie controller in this instance
575 //---------------------------------------------------------------------------
576 #if wxUSE_CREATEMOVIECONTROL
577 void wxQTMediaBackend::DoCreateMovieControl()
580 //Native CreateMovieControl QT control (Thanks to Kevin Olliver's
581 //wxQTMovie for some of this).
583 Rect bounds
= wxMacGetBoundsForControl(m_ctrl
,
584 m_ctrl
->GetPosition(),
587 //Dispose of old control for new one
588 if (m_ctrl
->m_peer
&& m_ctrl
->m_peer
->Ok() )
589 m_ctrl
->m_peer
->Dispose();
592 //kMovieControlOptionXXX
593 //HideController - hide the movie controller
594 //LocateTopLeft - movie is pinned to top left rather than centered in the control
595 //EnableEditing - Allows programmatic editing and dragn'drop
596 //HandleEditingHI- Installs event stuff for edit menu - forces EnableEditing also
597 //SetKeysEnabled - Allows keyboard input
598 //ManuallyIdled - app handles movie idling rather than internal timer event loop
599 ::CreateMovieControl(
601 m_ctrl
->MacGetTopLevelWindowRef(), //parent
602 &bounds
, //control bounds
603 m_movie
, //movie handle
604 kMovieControlOptionHideController
605 | kMovieControlOptionLocateTopLeft
606 | kMovieControlOptionSetKeysEnabled
607 // | kMovieControlOptionManuallyIdled
609 m_ctrl
->m_peer
->GetControlRefAddr() );
611 ::EmbedControl(m_ctrl
->m_peer
->GetControlRef(),
612 (ControlRef
)m_ctrl
->GetParent()->GetHandle());
615 // Setup MovieController for the new movie
619 //Get movie controller from our control
620 ::GetControlData( m_ctrl
->m_peer
->GetControlRef(), 0,
621 kMovieControlDataMovieController
,
622 sizeof(MovieController
), (Ptr
)&m_mc
, &dataSize
);
624 // Setup a callback so we can tell when the user presses
625 // play on the player controls
626 ::MCSetActionFilterWithRefCon(m_mc
,
627 wxQTMediaBackend::MCFilterProc
, (long)this);
631 //---------------------------------------------------------------------------
632 // wxQTMediaBackend::DoNewMovieController
634 // Attaches movie to moviecontroller or creates moviecontroller
635 // if not created yet
636 //---------------------------------------------------------------------------
637 #if !wxUSE_CREATEMOVIECONTROL
638 void wxQTMediaBackend::DoNewMovieController()
642 // Get top level window ref for some mac functions
643 WindowRef wrTLW
= (WindowRef
) m_ctrl
->MacGetTopLevelWindowRef();
645 // MovieController not setup yet -
646 // so we need to create a new one.
647 // You have to pass a valid movie to
648 // NewMovieController, evidently
649 ::SetMovieGWorld(m_movie
,
650 (CGrafPtr
) GetWindowPort(wrTLW
),
652 wxASSERT(::GetMoviesError() == noErr
);
654 Rect bounds
= wxMacGetBoundsForControl(m_ctrl
,
655 m_ctrl
->GetPosition(),
658 m_mc
= ::NewMovieController(m_movie
, &bounds
, mcTopLeftMovie
|
661 wxASSERT(::GetMoviesError() == noErr
);
662 ::MCDoAction(m_mc
, 32, (void*)true); //mcActionSetKeysEnabled
663 wxASSERT(::GetMoviesError() == noErr
);
665 // Setup a callback so we can tell when the user presses
666 // play on the player controls
667 ::MCSetActionFilterWithRefCon(m_mc
,
668 wxQTMediaBackend::MCFilterProc
, (long)this);
669 wxASSERT(::GetMoviesError() == noErr
);
671 //Part of a suggestion from Greg Hazel to repaint
673 m_ctrl
->PushEventHandler(new wxQTMediaEvtHandler(this));
675 // Event types to catch from the TLW
676 // for the moviecontroller
677 EventTypeSpec theEventTypes
[] = {
678 { kEventClassMouse
, kEventMouseDown
},
679 { kEventClassMouse
, kEventMouseUp
},
680 { kEventClassKeyboard
, kEventRawKeyDown
},
681 { kEventClassKeyboard
, kEventRawKeyRepeat
},
682 { kEventClassKeyboard
, kEventRawKeyUp
},
683 { kEventClassWindow
, kEventWindowUpdate
},
684 { kEventClassWindow
, kEventWindowActivated
},
685 { kEventClassWindow
, kEventWindowDeactivated
}
688 // Catch window messages -
689 // if we do not do this and if the user clicks the play
690 // button on the controller, for instance, nothing will happen...
691 InstallWindowEventHandler( wrTLW
,
692 GetwxQTMediaWindowEventHandlerUPP(),
693 GetEventTypeCount( theEventTypes
), theEventTypes
,
694 m_mc
, (&(EventHandlerRef
&)m_pEventHandlerRef
) );
698 // MovieController already created -
699 // Just change the movie in it and we're good to go
701 thePoint
.h
= thePoint
.v
= 0;
702 ::MCSetMovie(m_mc
, m_movie
,
703 (WindowRef
)m_ctrl
->MacGetTopLevelWindowRef(),
705 wxASSERT(::GetMoviesError() == noErr
);
710 //---------------------------------------------------------------------------
711 // wxQTMediaBackend::FinishLoad
713 // Performs operations after a movie ready to play/loaded.
714 //---------------------------------------------------------------------------
715 void wxQTMediaBackend::FinishLoad()
717 // get the real size of the movie
720 // Show the player controls if the user wants to
722 DoSetControllerVisible(m_interfaceflags
);
724 //we want millisecond precision
725 ::SetMovieTimeScale(m_movie
, 1000);
726 wxASSERT(::GetMoviesError() == noErr
);
728 // Start movie progress timer
729 m_timer
= new wxQTMediaPlayTimer(m_movie
, (wxQTMediaBackend
*) this);
731 m_timer
->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
);
733 //send loaded event & refresh size
737 //---------------------------------------------------------------------------
738 // wxQTMediaBackend::DoLoadBestSize
740 // Sets the best size of the control from the real size of the movie
741 //---------------------------------------------------------------------------
742 void wxQTMediaBackend::DoLoadBestSize()
744 //get the real size of the movie
746 ::GetMovieNaturalBoundsRect (m_movie
, &outRect
);
747 wxASSERT(::GetMoviesError() == noErr
);
749 //determine best size
750 m_bestSize
.x
= outRect
.right
- outRect
.left
;
751 m_bestSize
.y
= outRect
.bottom
- outRect
.top
;
754 //---------------------------------------------------------------------------
755 // wxQTMediaBackend::Play
757 // Start the QT movie
758 //---------------------------------------------------------------------------
759 bool wxQTMediaBackend::Play()
761 Fixed fixRate
= (Fixed
) (wxQTMediaBackend::GetPlaybackRate() * 0x10000);
763 fixRate
= ::GetMoviePreferredRate(m_movie
);
765 wxASSERT(fixRate
!= 0);
768 ::MCDoAction( m_mc
, 8, // mcActionPlay
772 return ::GetMoviesError() == noErr
;
775 //---------------------------------------------------------------------------
776 // wxQTMediaBackend::Pause
779 //---------------------------------------------------------------------------
780 bool wxQTMediaBackend::Pause()
782 //Stop the movie A.K.A. ::StopMovie(m_movie);
785 ::MCDoAction( m_mc
, 8 /*mcActionPlay*/,
788 return ::GetMoviesError() == noErr
;
790 return true; //already paused
793 //---------------------------------------------------------------------------
794 // wxQTMediaBackend::Stop
797 // 2) Seek to the beginning of the movie
798 //---------------------------------------------------------------------------
799 bool wxQTMediaBackend::Stop()
801 if(!wxQTMediaBackend::Pause())
804 ::GoToBeginningOfMovie(m_movie
);
805 return ::GetMoviesError() == noErr
;
808 //---------------------------------------------------------------------------
809 // wxQTMediaBackend::GetPlaybackRate
811 // 1) Get the movie playback rate from ::GetMovieRate
812 //---------------------------------------------------------------------------
813 double wxQTMediaBackend::GetPlaybackRate()
815 return ( ((double)::GetMovieRate(m_movie
)) / 0x10000);
818 //---------------------------------------------------------------------------
819 // wxQTMediaBackend::SetPlaybackRate
821 // 1) Convert dRate to Fixed and Set the movie rate through SetMovieRate
822 //---------------------------------------------------------------------------
823 bool wxQTMediaBackend::SetPlaybackRate(double dRate
)
825 ::SetMovieRate(m_movie
, (Fixed
) (dRate
* 0x10000));
826 return ::GetMoviesError() == noErr
;
829 //---------------------------------------------------------------------------
830 // wxQTMediaBackend::SetPosition
832 // 1) Create a time record struct (TimeRecord) with appropriate values
833 // 2) Pass struct to SetMovieTime
834 //---------------------------------------------------------------------------
835 bool wxQTMediaBackend::SetPosition(wxLongLong where
)
837 TimeRecord theTimeRecord
;
838 memset(&theTimeRecord
, 0, sizeof(TimeRecord
));
839 theTimeRecord
.value
.lo
= where
.GetValue();
840 theTimeRecord
.scale
= ::GetMovieTimeScale(m_movie
);
841 theTimeRecord
.base
= ::GetMovieTimeBase(m_movie
);
842 ::SetMovieTime(m_movie
, &theTimeRecord
);
844 if (::GetMoviesError() != noErr
)
850 //---------------------------------------------------------------------------
851 // wxQTMediaBackend::GetPosition
853 // Calls GetMovieTime
854 //---------------------------------------------------------------------------
855 wxLongLong
wxQTMediaBackend::GetPosition()
857 return ::GetMovieTime(m_movie
, NULL
);
860 //---------------------------------------------------------------------------
861 // wxQTMediaBackend::GetVolume
863 // Gets the volume through GetMovieVolume - which returns a 16 bit short -
865 // +--------+--------+
867 // +--------+--------+
869 // (1) first 8 bits are value before decimal
870 // (2) second 8 bits are value after decimal
872 // Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
873 // 1 (full gain and sound)
874 //---------------------------------------------------------------------------
875 double wxQTMediaBackend::GetVolume()
877 short sVolume
= ::GetMovieVolume(m_movie
);
879 if(sVolume
& (128 << 8)) //negative - no sound
882 return sVolume
/256.0;
885 //---------------------------------------------------------------------------
886 // wxQTMediaBackend::SetVolume
888 // Sets the volume through SetMovieVolume - which takes a 16 bit short -
890 // +--------+--------+
892 // +--------+--------+
894 // (1) first 8 bits are value before decimal
895 // (2) second 8 bits are value after decimal
897 // Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
898 // 1 (full gain and sound)
899 //---------------------------------------------------------------------------
900 bool wxQTMediaBackend::SetVolume(double dVolume
)
902 ::SetMovieVolume(m_movie
, (short) (dVolume
* 256));
906 //---------------------------------------------------------------------------
907 // wxQTMediaBackend::GetDuration
909 // Calls GetMovieDuration
910 //---------------------------------------------------------------------------
911 wxLongLong
wxQTMediaBackend::GetDuration()
913 return ::GetMovieDuration(m_movie
);
916 //---------------------------------------------------------------------------
917 // wxQTMediaBackend::GetState
919 // Determines the current state - the timer keeps track of whether or not
920 // we are paused or stopped (if the timer is running we are playing)
921 //---------------------------------------------------------------------------
922 wxMediaState
wxQTMediaBackend::GetState()
925 // GetMovieActive/IsMovieDone/SetMovieActive
926 // combo if implemented that way
927 if (m_bPlaying
== true)
928 return wxMEDIASTATE_PLAYING
;
929 else if ( !m_movie
|| wxQTMediaBackend::GetPosition() == 0)
930 return wxMEDIASTATE_STOPPED
;
932 return wxMEDIASTATE_PAUSED
;
935 //---------------------------------------------------------------------------
936 // wxQTMediaBackend::Cleanup
938 // Diposes of the movie timer, Control if native, and stops and disposes
940 //---------------------------------------------------------------------------
941 void wxQTMediaBackend::Cleanup()
951 // Apple samples with CreateMovieControl typically
952 // install a event handler and do this on the dispose
953 // event, but we do it here for simplicity
954 // (It might keep playing for several seconds after
955 // control destruction if not)
956 wxQTMediaBackend::Pause();
959 // Dispose of control or remove movie from MovieController
961 #if wxUSE_CREATEMOVIECONTROL
962 if (m_ctrl
->m_peer
&& m_ctrl
->m_peer
->Ok() )
963 m_ctrl
->m_peer
->Dispose();
966 thePoint
.h
= thePoint
.v
= 0;
967 ::MCSetVisible(m_mc
, false);
968 ::MCSetMovie(m_mc
, NULL
, NULL
, thePoint
);
971 ::DisposeMovie(m_movie
);
974 //---------------------------------------------------------------------------
975 // wxQTMediaBackend::MCFilterProc (static)
977 // Callback for when the movie controller recieves a message
978 //---------------------------------------------------------------------------
979 Boolean
wxQTMediaBackend::MCFilterProc(
980 MovieController
WXUNUSED(theController
),
982 void * WXUNUSED(params
),
985 if(action
!= 1) //don't process idle events
987 wxQTMediaBackend
* pThis
= (wxQTMediaBackend
*)refCon
;
991 case 8: //play button triggered - MC will set movie to opposite state
992 //of current - playing ? paused : playing
993 pThis
->m_bPlaying
= !(pThis
->m_bPlaying
);
1002 //---------------------------------------------------------------------------
1003 // wxQTMediaBackend::GetVideoSize
1005 // Returns the actual size of the QT movie
1006 //---------------------------------------------------------------------------
1007 wxSize
wxQTMediaBackend::GetVideoSize() const
1012 //---------------------------------------------------------------------------
1013 // wxQTMediaBackend::Move
1015 // We need to do this even when using native qt control because
1016 // CreateMovieControl is broken in this regard...
1017 //---------------------------------------------------------------------------
1018 void wxQTMediaBackend::Move(int x
, int y
, int w
, int h
)
1020 #if !wxUSE_CREATEMOVIECONTROL
1023 m_ctrl
->GetParent()->MacWindowToRootWindow(&x
, &y
);
1024 Rect theRect
= {y
, x
, y
+h
, x
+w
};
1026 ::MCSetControllerBoundsRect(m_mc
, &theRect
);
1027 wxASSERT(::GetMoviesError() == noErr
);
1030 if(m_timer
&& m_ctrl
)
1032 m_ctrl
->GetParent()->MacWindowToRootWindow(&x
, &y
);
1034 ::MoveControl( (ControlRef
) m_ctrl
->GetHandle(), x
, y
);
1035 m_ctrl
->GetParent()->Refresh();
1036 m_ctrl
->GetParent()->Update();
1041 //---------------------------------------------------------------------------
1042 // wxQTMediaBackend::DoSetControllerVisible
1044 // Utility function that takes care of showing the moviecontroller
1045 // and showing/hiding the particular controls on it
1046 //---------------------------------------------------------------------------
1047 void wxQTMediaBackend::DoSetControllerVisible(wxMediaCtrlPlayerControls flags
)
1049 ::MCSetVisible(m_mc
, TRUE
);
1052 // Take care of subcontrols
1054 if(::GetMoviesError() == noErr
)
1057 ::MCDoAction(m_mc
, 39/*mcActionGetFlags*/, (void*)&mcFlags
);
1059 if(::GetMoviesError() == noErr
)
1061 mcFlags
|= ( //(1<<0)/*mcFlagSuppressMovieFrame*/ |
1062 (1<<3)/*mcFlagsUseWindowPalette*/
1063 | ((flags
& wxMEDIACTRLPLAYERCONTROLS_STEP
)
1064 ? 0 : (1<<1)/*mcFlagSuppressStepButtons*/)
1065 | ((flags
& wxMEDIACTRLPLAYERCONTROLS_VOLUME
)
1066 ? 0 : (1<<2)/*mcFlagSuppressSpeakerButton*/)
1067 // | (1<<4) /*mcFlagDontInvalidate*/ //if we take care of repainting ourselves
1069 ::MCDoAction(m_mc
, 38/*mcActionSetFlags*/, (void*)mcFlags
);
1074 //Adjust height and width of best size for movie controller
1075 //if the user wants it shown
1077 m_bestSize
.x
= m_bestSize
.x
> wxMCWIDTH
? m_bestSize
.x
: wxMCWIDTH
;
1078 m_bestSize
.y
+= wxMCHEIGHT
;
1081 //---------------------------------------------------------------------------
1082 // wxQTMediaBackend::ShowPlayerControls
1084 // Shows/Hides subcontrols on the media control
1085 //---------------------------------------------------------------------------
1086 bool wxQTMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags
)
1089 return false; //no movie controller...
1091 bool bSizeChanged
= false;
1093 //if the controller is visible and we want to hide it do so
1094 if(m_interfaceflags
&& !flags
)
1096 bSizeChanged
= true;
1098 ::MCSetVisible(m_mc
, FALSE
);
1100 else if(!m_interfaceflags
&& flags
) //show controller if hidden
1102 bSizeChanged
= true;
1103 DoSetControllerVisible(flags
);
1106 //readjust parent sizers
1109 NotifyMovieSizeChanged();
1111 //remember state in case of loading new media
1112 m_interfaceflags
= flags
;
1115 return ::GetMoviesError() == noErr
;
1118 //---------------------------------------------------------------------------
1119 // wxQTMediaBackend::OnEraseBackground
1121 // Suggestion from Greg Hazel to repaint the movie when idle
1123 //---------------------------------------------------------------------------
1124 #if !wxUSE_CREATEMOVIECONTROL
1125 void wxQTMediaEvtHandler::OnEraseBackground(wxEraseEvent
& evt
)
1127 // Work around Nasty OSX drawing bug -
1128 // http://lists.apple.com/archives/QuickTime-API/2002/Feb/msg00311.html
1130 (WindowRef
) m_qtb
->m_ctrl
->MacGetTopLevelWindowRef();
1132 RgnHandle region
= MCGetControllerBoundsRgn(m_qtb
->m_mc
);
1133 MCInvalidate(m_qtb
->m_mc
, wrTLW
, region
);
1134 MCIdle(m_qtb
->m_mc
);
1138 //---------------------------------------------------------------------------
1139 // wxQTMediaWindowEventHandler
1141 // Event callback for the top level window of our control that passes
1142 // messages to our moviecontroller so it can recieve mouse clicks etc.
1143 //---------------------------------------------------------------------------
1144 #if !wxUSE_CREATEMOVIECONTROL
1145 OSStatus
wxQTMediaWindowEventHandler(EventHandlerCallRef inHandlerCallRef
,
1146 EventRef inEvent
, void *inUserData
)
1148 EventRecord theEvent
;
1149 ConvertEventRefToEventRecord( inEvent
, &theEvent
);
1151 err
= ::MCIsPlayerEvent( (MovieController
) inUserData
, &theEvent
);
1153 // pass on to other event handlers if not handled- i.e. wx
1157 return eventNotHandledErr
;
1161 //in source file that contains stuff you don't directly use
1162 #include "wx/html/forcelnk.h"
1163 FORCE_LINK_ME(basewxmediabackends
);
1165 #endif //wxUSE_MEDIACTRL