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 // For compilers that support precompilation, includes "wx.h".
18 #include "wx/wxprec.h"
24 #include "wx/mediactrl.h"
26 // uma is for wxMacFSSpec
27 #include "wx/mac/uma.h"
33 #include <QuickTimeComponents.h> // standard QT stuff
35 #include <QuickTime/QuickTimeComponents.h>
40 //---------------------------------------------------------------------------
41 // Whether or not to use OSX 10.2's CreateMovieControl for native QuickTime
42 // control - i.e. native positioning and event handling etc..
43 //---------------------------------------------------------------------------
44 #ifndef wxUSE_CREATEMOVIECONTROL
45 # if defined( __WXMAC_OSX__ ) && \
46 ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2 )
47 # define wxUSE_CREATEMOVIECONTROL 1
49 # define wxUSE_CREATEMOVIECONTROL 0
53 //---------------------------------------------------------------------------
54 // Height and Width of movie controller in the movie control
55 //---------------------------------------------------------------------------
59 //===========================================================================
60 // BACKEND DECLARATIONS
61 //===========================================================================
63 //---------------------------------------------------------------------------
65 //---------------------------------------------------------------------------
68 class WXDLLIMPEXP_MEDIA wxQTMediaBackend
: public wxMediaBackendCommonBase
74 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
79 const wxValidator
& validator
,
80 const wxString
& name
);
86 virtual bool Load(const wxString
& fileName
);
87 virtual bool Load(const wxURI
& location
);
89 virtual wxMediaState
GetState();
91 virtual bool SetPosition(wxLongLong where
);
92 virtual wxLongLong
GetPosition();
93 virtual wxLongLong
GetDuration();
95 virtual void Move(int x
, int y
, int w
, int h
);
96 wxSize
GetVideoSize() const;
98 virtual double GetPlaybackRate();
99 virtual bool SetPlaybackRate(double dRate
);
101 virtual double GetVolume();
102 virtual bool SetVolume(double);
107 virtual bool ShowPlayerControls(wxMediaCtrlPlayerControls flags
);
109 // ------ Implementation from now on --------
111 void DoLoadBestSize();
112 void DoSetControllerVisible(wxMediaCtrlPlayerControls flags
);
114 //TODO: Last param actually long - does this work on 64bit machines?
115 static Boolean
MCFilterProc (MovieController theController
,
116 short action
, void *params
, long refCon
);
118 #if wxUSE_CREATEMOVIECONTROL
119 void DoCreateMovieControl();
121 Boolean
IsQuickTime4Installed();
122 void DoNewMovieController();
123 static void PPRMProc (Movie theMovie
, OSErr theErr
, void* theRefCon
);
126 wxSize m_bestSize
; // Original movie size
129 struct MovieType
** m_movie
; // QT Movie handle/instance
131 Movie m_movie
; // Movie instance
134 bool m_bPlaying
; // Whether media is playing or not
135 class wxTimer
* m_timer
; // Timer for streaming the movie
136 MovieController m_mc
; // MovieController instance
137 wxMediaCtrlPlayerControls m_interfaceflags
; // Saved interface flags
139 #if !wxUSE_CREATEMOVIECONTROL
140 EventHandlerRef m_pEventHandlerRef
; // Event handler to cleanup
142 friend class wxQTMediaEvtHandler
;
145 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend
)
148 #if !wxUSE_CREATEMOVIECONTROL
149 // helper to hijack background erasing for the QT window
150 class WXDLLIMPEXP_MEDIA wxQTMediaEvtHandler
: public wxEvtHandler
153 wxQTMediaEvtHandler(wxQTMediaBackend
*qtb
)
157 qtb
->m_ctrl
->Connect(
158 qtb
->m_ctrl
->GetId(), wxEVT_ERASE_BACKGROUND
,
159 wxEraseEventHandler(wxQTMediaEvtHandler::OnEraseBackground
),
163 void OnEraseBackground(wxEraseEvent
& event
);
166 wxQTMediaBackend
*m_qtb
;
168 DECLARE_NO_COPY_CLASS(wxQTMediaEvtHandler
)
171 // Window event handler
172 static pascal OSStatus
wxQTMediaWindowEventHandler(
173 EventHandlerCallRef inHandlerCallRef
,
174 EventRef inEvent
, void *inUserData
);
175 DEFINE_ONE_SHOT_HANDLER_GETTER( wxQTMediaWindowEventHandler
);
179 //===========================================================================
181 //===========================================================================
184 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
186 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
188 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend
, wxMediaBackend
)
190 //Time between timer calls - this is the Apple recommondation to the TCL
192 #define MOVIE_DELAY 20
194 //---------------------------------------------------------------------------
195 // wxQTMediaLoadTimer
197 // QT, esp. QT for Windows is very picky about how you go about
198 // async loading. If you were to go through a Windows message loop
199 // or a MoviesTask or both and then check the movie load state
200 // it would still return 1000 (loading)... even (pre)prerolling doesn't
201 // help. However, making a load timer like this works
202 //---------------------------------------------------------------------------
203 class wxQTMediaLoadTimer
: public wxTimer
206 wxQTMediaLoadTimer(Movie movie
, wxQTMediaBackend
* parent
) :
207 m_movie(movie
), m_parent(parent
) {}
211 // Note that the CreateMovieControl variety performs
212 // its own custom idleing
213 #if !wxUSE_CREATEMOVIECONTROL
214 ::MCIdle(m_parent
->m_mc
);
217 // kMovieLoadStatePlayable is not enough on MAC:
218 // it plays, but IsMovieDone might return true (!)
219 // sure we need to wait until kMovieLoadStatePlaythroughOK
220 if (::GetMovieLoadState(m_movie
) >= 20000)
222 m_parent
->FinishLoad();
228 Movie m_movie
; // Our movie instance
229 wxQTMediaBackend
*m_parent
; // Backend pointer
232 // --------------------------------------------------------------------------
233 // wxQTMediaPlayTimer - Handle Asyncronous Playing
235 // 1) Checks to see if the movie is done, and if not continues
236 // streaming the movie
237 // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
239 // --------------------------------------------------------------------------
240 class wxQTMediaPlayTimer
: public wxTimer
243 wxQTMediaPlayTimer(Movie movie
, wxQTMediaBackend
* parent
) :
244 m_movie(movie
), m_parent(parent
) {}
248 //Note that CreateMovieControl performs its own idleing
249 #if !wxUSE_CREATEMOVIECONTROL
251 // OK, a little explaining - basically originally
252 // we only called MoviesTask if the movie was actually
253 // playing (not paused or stopped)... this was before
254 // we realized MoviesTask actually handles repainting
255 // of the current frame - so if you were to resize
256 // or something it would previously not redraw that
257 // portion of the movie.
259 // So now we call MoviesTask always so that it repaints
262 ::MCIdle(m_parent
->m_mc
);
265 // Handle the stop event - if the movie has reached
266 // the end, notify our handler
267 if (::IsMovieDone(m_movie
))
269 if ( m_parent
->SendStopEvent() )
272 wxASSERT(::GetMoviesError() == noErr
);
274 m_parent
->QueueFinishEvent();
280 Movie m_movie
; // Our movie instance
281 wxQTMediaBackend
* m_parent
; // Backend pointer
285 //---------------------------------------------------------------------------
286 // wxQTMediaBackend Constructor
288 // Sets m_timer to NULL signifying we havn't loaded anything yet
289 //---------------------------------------------------------------------------
290 wxQTMediaBackend::wxQTMediaBackend()
291 : m_movie(NULL
), m_bPlaying(false), m_timer(NULL
)
292 , m_mc(NULL
), m_interfaceflags(wxMEDIACTRLPLAYERCONTROLS_NONE
)
296 //---------------------------------------------------------------------------
297 // wxQTMediaBackend Destructor
299 // 1) Cleans up the QuickTime movie instance
300 // 2) Decrements the QuickTime reference counter - if this reaches
301 // 0, QuickTime shuts down
302 // 3) Decrements the QuickTime Windows Media Layer reference counter -
303 // if this reaches 0, QuickTime shuts down the Windows Media Layer
304 //---------------------------------------------------------------------------
305 wxQTMediaBackend::~wxQTMediaBackend()
310 #if !wxUSE_CREATEMOVIECONTROL
311 // Cleanup for moviecontroller
314 // destroy wxQTMediaEvtHandler we pushed on it
315 m_ctrl
->PopEventHandler(true);
316 RemoveEventHandler((EventHandlerRef
&)m_pEventHandlerRef
);
317 ::DisposeMovieController(m_mc
);
321 // Note that ExitMovies() is not necessary...
325 //---------------------------------------------------------------------------
326 // wxQTMediaBackend::CreateControl
328 // 1) Intializes QuickTime
329 // 2) Creates the control window
330 //---------------------------------------------------------------------------
331 bool wxQTMediaBackend::CreateControl(
338 const wxValidator
& validator
,
339 const wxString
& name
)
341 // Don't bother in Native control mode
342 #if !wxUSE_CREATEMOVIECONTROL
343 if (!IsQuickTime4Installed())
350 // By default wxWindow(s) is created with a border -
351 // so we need to get rid of those
353 // Since we don't have a child window like most other
354 // backends, we don't need wxCLIP_CHILDREN
355 if ( !ctrl
->wxControl::Create(parent
, id
, pos
, size
,
356 wxWindow::MacRemoveBordersFromStyle(style
),
363 ctrl
->SetValidator(validator
);
366 m_ctrl
= (wxMediaCtrl
*)ctrl
;
370 //---------------------------------------------------------------------------
371 // wxQTMediaBackend::IsQuickTime4Installed
373 // Determines whether version 4 of QT is installed
374 // (Pretty much for classic only)
375 //---------------------------------------------------------------------------
376 #if !wxUSE_CREATEMOVIECONTROL
377 Boolean
wxQTMediaBackend::IsQuickTime4Installed()
382 error
= Gestalt(gestaltQuickTime
, &result
);
383 return (error
== noErr
) && (((result
>> 16) & 0xffff) >= 0x0400);
387 //---------------------------------------------------------------------------
388 // wxQTMediaBackend::Load (file version)
390 // 1) Get an FSSpec from the Windows path name
392 // 3) Obtain the movie instance from the movie resource
393 // 4) Close the movie resource
395 //---------------------------------------------------------------------------
396 bool wxQTMediaBackend::Load(const wxString
& fileName
)
405 // FIXME:wxMacFilename2FSSpec crashes on empty string -
406 // does it crash on other strings too and should this
407 // "fix" be put in the carbon wxSound?
408 if (fileName
.empty())
411 wxMacFilename2FSSpec( fileName
, &sfFile
);
413 if (OpenMovieFile( &sfFile
, &movieResFile
, fsRdPerm
) != noErr
)
416 short movieResID
= 0;
420 err
= NewMovieFromFile(
427 result
= (err
== noErr
);
429 // No ::GetMoviesStickyError() here because it returns -2009
430 // a.k.a. invalid track on valid mpegs
433 ::CloseMovieFile(movieResFile
);
435 // Create movie controller/control
436 #if wxUSE_CREATEMOVIECONTROL
437 DoCreateMovieControl();
439 DoNewMovieController();
448 //---------------------------------------------------------------------------
449 // wxQTMediaBackend::PPRMProc (static)
451 // Called when done PrePrerolling the movie.
452 // Note that in 99% of the cases this does nothing...
453 // Anyway we set up the loading timer here to tell us when the movie is done
454 //---------------------------------------------------------------------------
455 #if !wxUSE_CREATEMOVIECONTROL
456 void wxQTMediaBackend::PPRMProc (Movie theMovie
,
457 OSErr
WXUNUSED_UNLESS_DEBUG(theErr
),
460 wxASSERT( theMovie
);
461 wxASSERT( theRefCon
);
462 wxASSERT( theErr
== noErr
);
464 wxQTMediaBackend
* pBE
= (wxQTMediaBackend
*) theRefCon
;
466 long lTime
= ::GetMovieTime(theMovie
,NULL
);
467 Fixed rate
= ::GetMoviePreferredRate(theMovie
);
468 ::PrerollMovie(theMovie
,lTime
,rate
);
469 pBE
->m_timer
= new wxQTMediaLoadTimer(pBE
->m_movie
, pBE
);
470 pBE
->m_timer
->Start(MOVIE_DELAY
);
474 //---------------------------------------------------------------------------
475 // wxQTMediaBackend::Load (URL Version)
477 // 1) Build an escaped URI from location
478 // 2) Create a handle to store the URI string
479 // 3) Put the URI string inside the handle
480 // 4) Make a QuickTime URL data ref from the handle with the URI in it
481 // 5) Clean up the URI string handle
482 // 6) Do some prerolling
484 //---------------------------------------------------------------------------
485 bool wxQTMediaBackend::Load(const wxURI
& location
)
490 wxString theURI
= location
.BuildURI();
495 // FIXME: lurking Unicode problem here
496 Handle theHandle
= ::NewHandleClear(theURI
.length() + 1);
499 ::BlockMoveData(theURI
.mb_str(), *theHandle
, theURI
.length() + 1);
501 // create the movie from the handle that refers to the URI
502 err
= ::NewMovieFromDataRef(&m_movie
, newMovieActive
|
504 /* | newMovieIdleImportOK*/,
506 URLDataHandlerSubType
);
508 ::DisposeHandle(theHandle
);
510 result
= (err
== noErr
);
513 #if wxUSE_CREATEMOVIECONTROL
514 // Movie control resets prerolling, so we must create first
515 DoCreateMovieControl();
517 // Setup timer to catch load event
518 m_timer
= new wxQTMediaLoadTimer(m_movie
, this);
519 m_timer
->Start(MOVIE_DELAY
);
521 // Movie controller resets prerolling, so we must create first
522 DoNewMovieController();
527 timeNow
= ::GetMovieTime(m_movie
, NULL
);
528 wxASSERT(::GetMoviesError() == noErr
);
530 playRate
= ::GetMoviePreferredRate(m_movie
);
531 wxASSERT(::GetMoviesError() == noErr
);
533 // Note that the callback here is optional,
534 // but without it PrePrerollMovie can be buggy
535 // (see Apple ml). Also, some may wonder
536 // why we need this at all - this is because
537 // Apple docs say QuickTime streamed movies
538 // require it if you don't use a Movie Controller,
539 // which we don't by default.
542 m_movie
, timeNow
, playRate
,
543 wxQTMediaBackend::PPRMProc
,
551 //---------------------------------------------------------------------------
552 // wxQTMediaBackend::DoCreateMovieControl
554 // Calls CreateMovieControl and performs setup related to it
556 // Note that we always hide the controller initially becuase when loading
557 // from a url it displays about a 40x40 box with the word loading... in it,
558 // but the box is outside the range of the control, which is bad (0,0
559 // i believe), so we need to wait until finishload to actually display
560 // the movie controller in this instance
561 //---------------------------------------------------------------------------
562 #if wxUSE_CREATEMOVIECONTROL
563 void wxQTMediaBackend::DoCreateMovieControl()
565 // Native CreateMovieControl QT control (Thanks to Kevin Olliver's
566 // wxQTMovie for some of this).
567 Rect bounds
= wxMacGetBoundsForControl(
569 m_ctrl
->GetPosition(),
572 // Dispose of old control for new one
573 if (m_ctrl
->m_peer
&& m_ctrl
->m_peer
->Ok() )
574 m_ctrl
->m_peer
->Dispose();
577 // kMovieControlOptionXXX
578 // HideController - hide the movie controller
579 // LocateTopLeft - movie is pinned to top left rather than centered in the control
580 // EnableEditing - Allows programmatic editing and dragn'drop
581 // HandleEditingHI- Installs event stuff for edit menu - forces EnableEditing also
582 // SetKeysEnabled - Allows keyboard input
583 // ManuallyIdled - app handles movie idling rather than internal timer event loop
584 ::CreateMovieControl(
586 m_ctrl
->MacGetTopLevelWindowRef(), //parent
587 &bounds
, //control bounds
588 m_movie
, //movie handle
589 kMovieControlOptionHideController
590 | kMovieControlOptionLocateTopLeft
591 | kMovieControlOptionSetKeysEnabled
592 // | kMovieControlOptionManuallyIdled
594 m_ctrl
->m_peer
->GetControlRefAddr() );
597 m_ctrl
->m_peer
->GetControlRef(),
598 (ControlRef
)m_ctrl
->GetParent()->GetHandle());
600 // set up MovieController for the new movie
603 // Get movie controller from our control
605 m_ctrl
->m_peer
->GetControlRef(), 0,
606 kMovieControlDataMovieController
,
607 sizeof(MovieController
), (Ptr
)&m_mc
, &dataSize
);
609 // Setup a callback so we can tell when the user presses
610 // play on the player controls
611 ::MCSetActionFilterWithRefCon(m_mc
,
612 wxQTMediaBackend::MCFilterProc
, (long)this);
616 //---------------------------------------------------------------------------
617 // wxQTMediaBackend::DoNewMovieController
619 // Attaches movie to moviecontroller or creates moviecontroller
620 // if not created yet
621 //---------------------------------------------------------------------------
622 #if !wxUSE_CREATEMOVIECONTROL
623 void wxQTMediaBackend::DoNewMovieController()
627 // Get top level window ref for some mac functions
628 WindowRef wrTLW
= (WindowRef
) m_ctrl
->MacGetTopLevelWindowRef();
630 // MovieController not setup yet:
631 // so we need to create a new one.
632 // You have to pass a valid movie to
633 // NewMovieController, evidently
634 ::SetMovieGWorld(m_movie
,
635 (CGrafPtr
) GetWindowPort(wrTLW
),
637 wxASSERT(::GetMoviesError() == noErr
);
639 Rect bounds
= wxMacGetBoundsForControl(
641 m_ctrl
->GetPosition(),
644 m_mc
= ::NewMovieController(
646 mcTopLeftMovie
| mcNotVisible
/* | mcWithFrame */ );
647 wxASSERT(::GetMoviesError() == noErr
);
649 ::MCDoAction(m_mc
, 32, (void*)true); //mcActionSetKeysEnabled
650 wxASSERT(::GetMoviesError() == noErr
);
652 // Setup a callback so we can tell when the user presses
653 // play on the player controls
654 ::MCSetActionFilterWithRefCon(m_mc
,
655 wxQTMediaBackend::MCFilterProc
, (long)this);
656 wxASSERT(::GetMoviesError() == noErr
);
658 // Part of a suggestion from Greg Hazel to repaint
660 m_ctrl
->PushEventHandler(new wxQTMediaEvtHandler(this));
662 // Event types to catch from the TLW
663 // for the moviecontroller
664 EventTypeSpec theEventTypes
[] =
666 { kEventClassMouse
, kEventMouseDown
},
667 { kEventClassMouse
, kEventMouseUp
},
668 { kEventClassKeyboard
, kEventRawKeyDown
},
669 { kEventClassKeyboard
, kEventRawKeyRepeat
},
670 { kEventClassKeyboard
, kEventRawKeyUp
},
671 { kEventClassWindow
, kEventWindowUpdate
},
672 { kEventClassWindow
, kEventWindowActivated
},
673 { kEventClassWindow
, kEventWindowDeactivated
}
676 // Catch window messages:
677 // if we do not do this and if the user clicks the play
678 // button on the controller, for instance, nothing will happen...
679 InstallWindowEventHandler( wrTLW
,
680 GetwxQTMediaWindowEventHandlerUPP(),
681 GetEventTypeCount( theEventTypes
), theEventTypes
,
682 m_mc
, (&(EventHandlerRef
&)m_pEventHandlerRef
) );
686 // MovieController already created:
687 // Just change the movie in it and we're good to go
689 thePoint
.h
= thePoint
.v
= 0;
690 ::MCSetMovie(m_mc
, m_movie
,
691 (WindowRef
)m_ctrl
->MacGetTopLevelWindowRef(),
694 wxASSERT(::GetMoviesError() == noErr
);
699 //---------------------------------------------------------------------------
700 // wxQTMediaBackend::FinishLoad
702 // Performs operations after a movie ready to play/loaded.
703 //---------------------------------------------------------------------------
704 void wxQTMediaBackend::FinishLoad()
706 // get the real size of the movie
709 // show the player controls if the user wants to
710 if (m_interfaceflags
)
711 DoSetControllerVisible(m_interfaceflags
);
713 // we want millisecond precision
714 ::SetMovieTimeScale(m_movie
, 1000);
715 wxASSERT(::GetMoviesError() == noErr
);
717 // start movie progress timer
718 m_timer
= new wxQTMediaPlayTimer(m_movie
, (wxQTMediaBackend
*) this);
720 m_timer
->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
);
722 // send loaded event & refresh size
726 //---------------------------------------------------------------------------
727 // wxQTMediaBackend::DoLoadBestSize
729 // Sets the best size of the control from the real size of the movie
730 //---------------------------------------------------------------------------
731 void wxQTMediaBackend::DoLoadBestSize()
733 // get the real size of the movie
735 ::GetMovieNaturalBoundsRect (m_movie
, &outRect
);
736 wxASSERT(::GetMoviesError() == noErr
);
738 // determine best size
739 m_bestSize
.x
= outRect
.right
- outRect
.left
;
740 m_bestSize
.y
= outRect
.bottom
- outRect
.top
;
743 //---------------------------------------------------------------------------
744 // wxQTMediaBackend::Play
746 // Start the QT movie
747 //---------------------------------------------------------------------------
748 bool wxQTMediaBackend::Play()
750 Fixed fixRate
= (Fixed
) (wxQTMediaBackend::GetPlaybackRate() * 0x10000);
752 fixRate
= ::GetMoviePreferredRate(m_movie
);
754 wxASSERT(fixRate
!= 0);
757 ::MCDoAction( m_mc
, 8 /* mcActionPlay */, (void*) fixRate
);
760 return ::GetMoviesError() == noErr
;
763 //---------------------------------------------------------------------------
764 // wxQTMediaBackend::Pause
767 //---------------------------------------------------------------------------
768 bool wxQTMediaBackend::Pause()
770 // Stop the movie A.K.A. ::StopMovie(m_movie);
773 ::MCDoAction( m_mc
, 8 /*mcActionPlay*/, (void*) 0);
775 return ::GetMoviesError() == noErr
;
782 //---------------------------------------------------------------------------
783 // wxQTMediaBackend::Stop
786 // 2) Seek to the beginning of the movie
787 //---------------------------------------------------------------------------
788 bool wxQTMediaBackend::Stop()
790 if (!wxQTMediaBackend::Pause())
793 ::GoToBeginningOfMovie(m_movie
);
794 return ::GetMoviesError() == noErr
;
797 //---------------------------------------------------------------------------
798 // wxQTMediaBackend::GetPlaybackRate
800 // 1) Get the movie playback rate from ::GetMovieRate
801 //---------------------------------------------------------------------------
802 double wxQTMediaBackend::GetPlaybackRate()
804 return ( ((double)::GetMovieRate(m_movie
)) / 0x10000);
807 //---------------------------------------------------------------------------
808 // wxQTMediaBackend::SetPlaybackRate
810 // 1) Convert dRate to Fixed and Set the movie rate through SetMovieRate
811 //---------------------------------------------------------------------------
812 bool wxQTMediaBackend::SetPlaybackRate(double dRate
)
814 ::SetMovieRate(m_movie
, (Fixed
) (dRate
* 0x10000));
815 return ::GetMoviesError() == noErr
;
818 //---------------------------------------------------------------------------
819 // wxQTMediaBackend::SetPosition
821 // 1) Create a time record struct (TimeRecord) with appropriate values
822 // 2) Pass struct to SetMovieTime
823 //---------------------------------------------------------------------------
824 bool wxQTMediaBackend::SetPosition(wxLongLong where
)
826 TimeRecord theTimeRecord
;
827 memset(&theTimeRecord
, 0, sizeof(TimeRecord
));
828 theTimeRecord
.value
.lo
= where
.GetValue();
829 theTimeRecord
.scale
= ::GetMovieTimeScale(m_movie
);
830 theTimeRecord
.base
= ::GetMovieTimeBase(m_movie
);
831 ::SetMovieTime(m_movie
, &theTimeRecord
);
833 if (::GetMoviesError() != noErr
)
839 //---------------------------------------------------------------------------
840 // wxQTMediaBackend::GetPosition
842 // Calls GetMovieTime
843 //---------------------------------------------------------------------------
844 wxLongLong
wxQTMediaBackend::GetPosition()
846 return ::GetMovieTime(m_movie
, NULL
);
849 //---------------------------------------------------------------------------
850 // wxQTMediaBackend::GetVolume
852 // Gets the volume through GetMovieVolume - which returns a 16 bit short -
854 // +--------+--------+
856 // +--------+--------+
858 // (1) first 8 bits are value before decimal
859 // (2) second 8 bits are value after decimal
861 // Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
862 // 1 (full gain and sound)
863 //---------------------------------------------------------------------------
864 double wxQTMediaBackend::GetVolume()
866 short sVolume
= ::GetMovieVolume(m_movie
);
868 if (sVolume
& (128 << 8)) //negative - no sound
871 return sVolume
/ 256.0;
874 //---------------------------------------------------------------------------
875 // wxQTMediaBackend::SetVolume
877 // Sets the volume through SetMovieVolume - which takes a 16 bit short -
879 // +--------+--------+
881 // +--------+--------+
883 // (1) first 8 bits are value before decimal
884 // (2) second 8 bits are value after decimal
886 // Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
887 // 1 (full gain and sound)
888 //---------------------------------------------------------------------------
889 bool wxQTMediaBackend::SetVolume(double dVolume
)
891 ::SetMovieVolume(m_movie
, (short) (dVolume
* 256));
895 //---------------------------------------------------------------------------
896 // wxQTMediaBackend::GetDuration
898 // Calls GetMovieDuration
899 //---------------------------------------------------------------------------
900 wxLongLong
wxQTMediaBackend::GetDuration()
902 return ::GetMovieDuration(m_movie
);
905 //---------------------------------------------------------------------------
906 // wxQTMediaBackend::GetState
908 // Determines the current state - the timer keeps track of whether or not
909 // we are paused or stopped (if the timer is running we are playing)
910 //---------------------------------------------------------------------------
911 wxMediaState
wxQTMediaBackend::GetState()
914 // GetMovieActive/IsMovieDone/SetMovieActive
915 // combo if implemented that way
917 return wxMEDIASTATE_PLAYING
;
918 else if ( !m_movie
|| wxQTMediaBackend::GetPosition() == 0)
919 return wxMEDIASTATE_STOPPED
;
921 return wxMEDIASTATE_PAUSED
;
924 //---------------------------------------------------------------------------
925 // wxQTMediaBackend::Cleanup
927 // Diposes of the movie timer, Control if native, and stops and disposes
929 //---------------------------------------------------------------------------
930 void wxQTMediaBackend::Cleanup()
940 // Apple samples with CreateMovieControl typically
941 // install a event handler and do this on the dispose
942 // event, but we do it here for simplicity
943 // (It might keep playing for several seconds after
944 // control destruction if not)
945 wxQTMediaBackend::Pause();
947 // Dispose of control or remove movie from MovieController
948 #if wxUSE_CREATEMOVIECONTROL
949 if (m_ctrl
->m_peer
&& m_ctrl
->m_peer
->Ok() )
950 m_ctrl
->m_peer
->Dispose();
953 thePoint
.h
= thePoint
.v
= 0;
954 ::MCSetVisible(m_mc
, false);
955 ::MCSetMovie(m_mc
, NULL
, NULL
, thePoint
);
958 ::DisposeMovie(m_movie
);
962 //---------------------------------------------------------------------------
963 // wxQTMediaBackend::MCFilterProc (static)
965 // Callback for when the movie controller recieves a message
966 //---------------------------------------------------------------------------
967 Boolean
wxQTMediaBackend::MCFilterProc(
968 MovieController
WXUNUSED(theController
),
970 void * WXUNUSED(params
),
973 wxQTMediaBackend
* pThis
= (wxQTMediaBackend
*)refCon
;
978 // don't process idle events
982 // play button triggered - MC will set movie to opposite state
983 // of current - playing ? paused : playing
984 pThis
->m_bPlaying
= !(pThis
->m_bPlaying
);
994 //---------------------------------------------------------------------------
995 // wxQTMediaBackend::GetVideoSize
997 // Returns the actual size of the QT movie
998 //---------------------------------------------------------------------------
999 wxSize
wxQTMediaBackend::GetVideoSize() const
1004 //---------------------------------------------------------------------------
1005 // wxQTMediaBackend::Move
1007 // We need to do this even when using native qt control because
1008 // CreateMovieControl is broken in this regard...
1009 //---------------------------------------------------------------------------
1010 void wxQTMediaBackend::Move(int x
, int y
, int w
, int h
)
1012 #if !wxUSE_CREATEMOVIECONTROL
1015 m_ctrl
->GetParent()->MacWindowToRootWindow(&x
, &y
);
1016 Rect theRect
= {y
, x
, y
+h
, x
+w
};
1018 ::MCSetControllerBoundsRect(m_mc
, &theRect
);
1019 wxASSERT(::GetMoviesError() == noErr
);
1022 if (m_timer
&& m_ctrl
)
1024 m_ctrl
->GetParent()->MacWindowToRootWindow(&x
, &y
);
1026 ::MoveControl( (ControlRef
) m_ctrl
->GetHandle(), x
, y
);
1027 m_ctrl
->GetParent()->Refresh();
1028 m_ctrl
->GetParent()->Update();
1033 //---------------------------------------------------------------------------
1034 // wxQTMediaBackend::DoSetControllerVisible
1036 // Utility function that takes care of showing the moviecontroller
1037 // and showing/hiding the particular controls on it
1038 //---------------------------------------------------------------------------
1039 void wxQTMediaBackend::DoSetControllerVisible(wxMediaCtrlPlayerControls flags
)
1041 ::MCSetVisible(m_mc
, true);
1043 // Take care of subcontrols
1044 if (::GetMoviesError() == noErr
)
1047 ::MCDoAction(m_mc
, 39/*mcActionGetFlags*/, (void*)&mcFlags
);
1049 if (::GetMoviesError() == noErr
)
1051 mcFlags
|= ( //(1<<0)/*mcFlagSuppressMovieFrame*/ |
1052 (1 << 3)/*mcFlagsUseWindowPalette*/
1053 | ((flags
& wxMEDIACTRLPLAYERCONTROLS_STEP
)
1054 ? 0 : (1 << 1)/*mcFlagSuppressStepButtons*/)
1055 | ((flags
& wxMEDIACTRLPLAYERCONTROLS_VOLUME
)
1056 ? 0 : (1 << 2)/*mcFlagSuppressSpeakerButton*/)
1057 // | (1 << 4) /*mcFlagDontInvalidate*/ //if we take care of repainting ourselves
1060 ::MCDoAction(m_mc
, 38/*mcActionSetFlags*/, (void*)mcFlags
);
1064 // Adjust height and width of best size for movie controller
1065 // if the user wants it shown
1066 m_bestSize
.x
= m_bestSize
.x
> wxMCWIDTH
? m_bestSize
.x
: wxMCWIDTH
;
1067 m_bestSize
.y
+= wxMCHEIGHT
;
1070 //---------------------------------------------------------------------------
1071 // wxQTMediaBackend::ShowPlayerControls
1073 // Shows/Hides subcontrols on the media control
1074 //---------------------------------------------------------------------------
1075 bool wxQTMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags
)
1078 return false; //no movie controller...
1080 bool bSizeChanged
= false;
1082 // if the controller is visible and we want to hide it do so
1083 if (m_interfaceflags
&& !flags
)
1085 bSizeChanged
= true;
1087 ::MCSetVisible(m_mc
, false);
1089 else if (!m_interfaceflags
&& flags
) //show controller if hidden
1091 bSizeChanged
= true;
1092 DoSetControllerVisible(flags
);
1095 // readjust parent sizers
1098 NotifyMovieSizeChanged();
1100 //remember state in case of loading new media
1101 m_interfaceflags
= flags
;
1104 return ::GetMoviesError() == noErr
;
1107 //---------------------------------------------------------------------------
1108 // wxQTMediaBackend::OnEraseBackground
1110 // Suggestion from Greg Hazel to repaint the movie when idle
1112 //---------------------------------------------------------------------------
1113 #if !wxUSE_CREATEMOVIECONTROL
1114 void wxQTMediaEvtHandler::OnEraseBackground(wxEraseEvent
& evt
)
1116 // Work around Nasty OSX drawing bug -
1117 // http://lists.apple.com/archives/QuickTime-API/2002/Feb/msg00311.html
1119 (WindowRef
) m_qtb
->m_ctrl
->MacGetTopLevelWindowRef();
1121 RgnHandle region
= MCGetControllerBoundsRgn(m_qtb
->m_mc
);
1122 MCInvalidate(m_qtb
->m_mc
, wrTLW
, region
);
1123 MCIdle(m_qtb
->m_mc
);
1127 //---------------------------------------------------------------------------
1128 // wxQTMediaWindowEventHandler
1130 // Event callback for the top level window of our control that passes
1131 // messages to our moviecontroller so it can recieve mouse clicks etc.
1132 //---------------------------------------------------------------------------
1133 #if !wxUSE_CREATEMOVIECONTROL
1134 OSStatus
wxQTMediaWindowEventHandler(
1135 EventHandlerCallRef inHandlerCallRef
,
1136 EventRef inEvent
, void *inUserData
)
1138 EventRecord theEvent
;
1139 ConvertEventRefToEventRecord( inEvent
, &theEvent
);
1141 err
= ::MCIsPlayerEvent( (MovieController
) inUserData
, &theEvent
);
1143 // pass on to other event handlers if not handled- i.e. wx
1147 return eventNotHandledErr
;
1151 // in source file that contains stuff you don't directly use
1152 #include "wx/html/forcelnk.h"
1153 FORCE_LINK_ME(basewxmediabackends
)
1155 #endif // wxUSE_MEDIACTRL