1 /////////////////////////////////////////////////////////////////////////////
2 // Name: mac/carbon/mediactrl.cpp
3 // Purpose: Built-in Media Backends for Mac
4 // Author: Ryan Norton <wxprojects@comcast.net>
8 // Copyright: (c) 2004-2005 Ryan Norton, portions (c) 2004 Kevin Olliver
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 //===========================================================================
14 //===========================================================================
16 //---------------------------------------------------------------------------
17 // Pre-compiled header stuff
18 //---------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "mediactrl.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
31 //---------------------------------------------------------------------------
33 //---------------------------------------------------------------------------
34 #include "wx/mediactrl.h"
36 //---------------------------------------------------------------------------
38 //---------------------------------------------------------------------------
41 //---------------------------------------------------------------------------
42 // Whether or not to use OSX 10.2's CreateMovieControl for native QuickTime
43 // control - i.e. native positioning and event handling etc..
44 //---------------------------------------------------------------------------
45 #ifndef wxUSE_CREATEMOVIECONTROL
46 # if defined( __WXMAC_OSX__ ) && ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2 )
47 # define wxUSE_CREATEMOVIECONTROL 1
49 # define wxUSE_CREATEMOVIECONTROL 0
53 //===========================================================================
54 // BACKEND DECLARATIONS
55 //===========================================================================
57 //---------------------------------------------------------------------------
61 //---------------------------------------------------------------------------
63 //---------------------------------------------------------------------------
65 //---------------------------------------------------------------------------
66 //uma is for wxMacFSSpec
67 #include "wx/mac/uma.h"
71 #include <QuickTimeComponents.h> //Standard QT stuff
73 //Determines whether version 4 of QT is installed (Pretty much for classic only)
74 Boolean
_wxIsQuickTime4Installed (void)
79 error
= Gestalt (gestaltQuickTime
, &result
);
80 return (error
== noErr
) && (((result
>> 16) & 0xffff) >= 0x0400);
83 class WXDLLIMPEXP_MEDIA wxQTMediaBackend
: public wxMediaBackend
90 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
95 const wxValidator
& validator
,
96 const wxString
& name
);
102 virtual bool Load(const wxString
& fileName
);
103 virtual bool Load(const wxURI
& location
);
105 virtual wxMediaState
GetState();
107 virtual bool SetPosition(wxLongLong where
);
108 virtual wxLongLong
GetPosition();
109 virtual wxLongLong
GetDuration();
111 virtual void Move(int x
, int y
, int w
, int h
);
112 wxSize
GetVideoSize() const;
114 virtual double GetPlaybackRate();
115 virtual bool SetPlaybackRate(double dRate
);
120 wxSize m_bestSize
; //Original movie size
121 struct MovieType
** m_movie
; //QT Movie handle/instance
122 wxControl
* m_ctrl
; //Parent control
123 bool m_bVideo
; //Whether or not we have video
124 class _wxQTTimer
* m_timer
; //Timer for streaming the movie
126 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend
);
130 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
134 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
136 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend
, wxMediaBackend
);
138 //Time between timer calls
139 #define MOVIE_DELAY 100
141 // --------------------------------------------------------------------------
142 // wxQTTimer - Handle Asyncronous Playing
143 // --------------------------------------------------------------------------
144 class _wxQTTimer
: public wxTimer
147 _wxQTTimer(Movie movie
, wxQTMediaBackend
* parent
) :
148 m_movie(movie
), m_bPaused(false), m_parent(parent
)
156 bool GetPaused() {return m_bPaused
;}
157 void SetPaused(bool bPaused
) {m_bPaused
= bPaused
;}
159 //-----------------------------------------------------------------------
160 // _wxQTTimer::Notify
162 // 1) Checks to see if the movie is done, and if not continues
163 // streaming the movie
164 // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
166 //-----------------------------------------------------------------------
171 if(!IsMovieDone(m_movie
))
172 MoviesTask(m_movie
, MOVIE_DELAY
);
175 wxMediaEvent
theEvent(wxEVT_MEDIA_STOP
,
176 m_parent
->m_ctrl
->GetId());
177 m_parent
->m_ctrl
->ProcessEvent(theEvent
);
179 if(theEvent
.IsAllowed())
183 wxASSERT(::GetMoviesError() == noErr
);
185 //send the event to our child
186 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
,
187 m_parent
->m_ctrl
->GetId());
188 m_parent
->m_ctrl
->ProcessEvent(theEvent
);
195 Movie m_movie
; //Our movie instance
196 bool m_bPaused
; //Whether we are paused or not
197 wxQTMediaBackend
* m_parent
; //Backend pointer
200 //---------------------------------------------------------------------------
201 // wxQTMediaBackend Constructor
203 // Sets m_timer to NULL signifying we havn't loaded anything yet
204 //---------------------------------------------------------------------------
205 wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL
)
209 //---------------------------------------------------------------------------
210 // wxQTMediaBackend Destructor
212 // 1) Cleans up the QuickTime movie instance
213 // 2) Decrements the QuickTime reference counter - if this reaches
214 // 0, QuickTime shuts down
215 // 3) Decrements the QuickTime Windows Media Layer reference counter -
216 // if this reaches 0, QuickTime shuts down the Windows Media Layer
217 //---------------------------------------------------------------------------
218 wxQTMediaBackend::~wxQTMediaBackend()
223 //Note that ExitMovies() is not neccessary...
227 //---------------------------------------------------------------------------
228 // wxQTMediaBackend::CreateControl
230 // 1) Intializes QuickTime
231 // 2) Creates the control window
232 //---------------------------------------------------------------------------
233 bool wxQTMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
238 const wxValidator
& validator
,
239 const wxString
& name
)
241 //Don't bother in Native control mode
242 #if defined( __WXMAC__ ) && TARGET_API_MAC_OSX && ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_2 )
243 if (!_wxIsQuickTime4Installed())
251 // By default wxWindow(s) is created with a border -
252 // so we need to get rid of those
254 // Since we don't have a child window like most other
255 // backends, we don't need wxCLIP_CHILDREN
259 #if wxUSE_CREATEMOVIECONTROL
260 ctrl
->wxControl::Create(parent
, id
, pos
, size
,
261 m_ctrl
->MacRemoveBordersFromStyle(style
),
264 ctrl
->wxWindow::Create(parent
, id
, pos
, size
,
265 m_ctrl
->MacRemoveBordersFromStyle(style
),
275 //---------------------------------------------------------------------------
276 // wxQTMediaBackend::Load (file version)
278 // 1) Get an FSSpec from the Windows path name
280 // 3) Obtain the movie instance from the movie resource
281 // 4) Close the movie resource
283 //---------------------------------------------------------------------------
284 bool wxQTMediaBackend::Load(const wxString
& fileName
)
293 wxMacFilename2FSSpec( fileName
, &sfFile
);
295 if (OpenMovieFile (&sfFile
, &movieResFile
, fsRdPerm
) != noErr
)
298 short movieResID
= 0;
301 err
= NewMovieFromFile (
309 CloseMovieFile (movieResFile
);
316 return ::GetMoviesError() == noErr
;
319 //---------------------------------------------------------------------------
320 // wxQTMediaBackend::Load (URL Version)
322 // 1) Build an escaped URI from location
323 // 2) Create a handle to store the URI string
324 // 3) Put the URI string inside the handle
325 // 4) Make a QuickTime URL data ref from the handle with the URI in it
326 // 5) Clean up the URI string handle
327 // 6) Do some prerolling
329 //---------------------------------------------------------------------------
330 bool wxQTMediaBackend::Load(const wxURI
& location
)
335 wxString theURI
= location
.BuildURI();
339 Handle theHandle
= NewHandleClear(theURI
.length() + 1);
342 BlockMove(theURI
.mb_str(), *theHandle
, theURI
.length() + 1);
344 //create the movie from the handle that refers to the URI
345 err
= NewMovieFromDataRef(&m_movie
, newMovieActive
,
347 URLDataHandlerSubType
);
349 DisposeHandle(theHandle
);
354 //preroll movie for streaming
355 //TODO:Async this using threads?
358 timeNow
= GetMovieTime(m_movie
, NULL
);
359 playRate
= GetMoviePreferredRate(m_movie
);
360 PrePrerollMovie(m_movie
, timeNow
, playRate
, NULL
, NULL
);
361 PrerollMovie(m_movie
, timeNow
, playRate
);
362 SetMovieRate(m_movie
, playRate
);
366 return ::GetMoviesError() == noErr
;
369 //---------------------------------------------------------------------------
370 // wxQTMediaBackend::FinishLoad
372 // 1) Create the movie timer
373 // 2) Get real size of movie for GetBestSize/sizers
374 // 3) See if there is video in the movie, and if so then either
375 // SetMovieGWorld if < 10.2 or use Native CreateMovieControl
376 // 4) Set the movie time scale to something usable so that seeking
377 // etc. will work correctly
378 // 5) Refresh parent window
379 //---------------------------------------------------------------------------
380 void wxQTMediaBackend::FinishLoad()
382 m_timer
= new _wxQTTimer(m_movie
, (wxQTMediaBackend
*) this);
385 //get the real size of the movie
387 ::GetMovieNaturalBoundsRect (m_movie
, &outRect
);
388 wxASSERT(::GetMoviesError() == noErr
);
390 m_bestSize
.x
= outRect
.right
- outRect
.left
;
391 m_bestSize
.y
= outRect
.bottom
- outRect
.top
;
393 //reparent movie/*AudioMediaCharacteristic*/
394 if(GetMovieIndTrackType(m_movie
, 1,
395 VisualMediaCharacteristic
,
396 movieTrackCharacteristic
|
397 movieTrackEnabledOnly
) != NULL
)
399 #if wxUSE_CREATEMOVIECONTROL
401 //Native CreateMovieControl QT control (Thanks to Kevin Olliver's
402 //wxQTMovie for some of this).
404 Rect bounds
= wxMacGetBoundsForControl(m_ctrl
,
405 m_ctrl
->GetPosition(),
408 //Dispose of old control for new one
409 if (GetControlPeer(m_ctrl
) && GetControlPeer(m_ctrl
)->Ok() )
410 GetControlPeer(m_ctrl
)->Dispose();
413 //kMovieControlOptionXXX
414 //HideController - hide the movie controller
415 //LocateTopLeft - movie is pinned to top left rather than centered in the control
416 //EnableEditing - Allows programmatic editing and dragn'drop
417 //HandleEditingHI- Installs event stuff for edit menu - forces EnableEditing also
418 //SetKeysEnabled - Allows keyboard input
419 //ManuallyIdled - app handles movie idling rather than internal timer event loop
420 ::CreateMovieControl(
422 m_ctrl
->MacGetTopLevelWindowRef(), //parent
423 &bounds
, //control bounds
424 m_movie
, //movie handle
425 kMovieControlOptionHideController
426 | kMovieControlOptionLocateTopLeft
427 | kMovieControlOptionSetKeysEnabled
428 // | kMovieControlOptionManuallyIdled
430 GetControlPeer(m_ctrl
)->GetControlRefAddr() );
432 ::EmbedControl(GetControlPeer(m_ctrl
)->GetControlRef(),
433 (ControlRef
) m_ctrl
->GetParent()->GetHandle());
438 SetMovieGWorld(m_movie
,
442 m_ctrl
->MacGetTopLevelWindowRef()
448 //we want millisecond precision
449 ::SetMovieTimeScale(m_movie
, 1000);
450 wxASSERT(::GetMoviesError() == noErr
);
453 //Here, if the parent of the control has a sizer - we
454 //tell it to recalculate the size of this control since
455 //the user opened a seperate media file
457 m_ctrl
->InvalidateBestSize();
458 m_ctrl
->GetParent()->Layout();
459 m_ctrl
->GetParent()->Refresh();
460 m_ctrl
->GetParent()->Update();
463 //---------------------------------------------------------------------------
464 // wxQTMediaBackend::Play
466 // 1) Start the QT movie
467 // 2) Start the movie loading timer
468 //---------------------------------------------------------------------------
469 bool wxQTMediaBackend::Play()
471 ::StartMovie(m_movie
);
472 m_timer
->SetPaused(false);
473 m_timer
->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
);
474 return ::GetMoviesError() == noErr
;
477 //---------------------------------------------------------------------------
478 // wxQTMediaBackend::Pause
481 // 2) Stop the movie timer
482 //---------------------------------------------------------------------------
483 bool wxQTMediaBackend::Pause()
485 ::StopMovie(m_movie
);
486 m_timer
->SetPaused(true);
488 return ::GetMoviesError() == noErr
;
491 //---------------------------------------------------------------------------
492 // wxQTMediaBackend::Stop
495 // 2) Stop the movie timer
496 // 3) Seek to the beginning of the movie
497 //---------------------------------------------------------------------------
498 bool wxQTMediaBackend::Stop()
500 m_timer
->SetPaused(false);
503 ::StopMovie(m_movie
);
504 if(::GetMoviesError() != noErr
)
507 ::GoToBeginningOfMovie(m_movie
);
508 return ::GetMoviesError() == noErr
;
511 //---------------------------------------------------------------------------
512 // wxQTMediaBackend::GetPlaybackRate
514 // 1) Get the movie playback rate from ::GetMovieRate
515 //---------------------------------------------------------------------------
516 double wxQTMediaBackend::GetPlaybackRate()
518 return ( ((double)::GetMovieRate(m_movie
)) / 0x10000);
521 //---------------------------------------------------------------------------
522 // wxQTMediaBackend::SetPlaybackRate
524 // 1) Convert dRate to Fixed and Set the movie rate through SetMovieRate
525 //---------------------------------------------------------------------------
526 bool wxQTMediaBackend::SetPlaybackRate(double dRate
)
528 ::SetMovieRate(m_movie
, (Fixed
) (dRate
* 0x10000));
529 return ::GetMoviesError() == noErr
;
532 //---------------------------------------------------------------------------
533 // wxQTMediaBackend::SetPosition
535 // 1) Create a time record struct (TimeRecord) with appropriate values
536 // 2) Pass struct to SetMovieTime
537 //---------------------------------------------------------------------------
538 bool wxQTMediaBackend::SetPosition(wxLongLong where
)
540 TimeRecord theTimeRecord
;
541 memset(&theTimeRecord
, 0, sizeof(TimeRecord
));
542 theTimeRecord
.value
.lo
= where
.GetValue();
543 theTimeRecord
.scale
= ::GetMovieTimeScale(m_movie
);
544 theTimeRecord
.base
= ::GetMovieTimeBase(m_movie
);
545 ::SetMovieTime(m_movie
, &theTimeRecord
);
547 if (::GetMoviesError() != noErr
)
553 //---------------------------------------------------------------------------
554 // wxQTMediaBackend::GetPosition
556 // Calls GetMovieTime
557 //---------------------------------------------------------------------------
558 wxLongLong
wxQTMediaBackend::GetPosition()
560 return ::GetMovieTime(m_movie
, NULL
);
563 //---------------------------------------------------------------------------
564 // wxQTMediaBackend::GetDuration
566 // Calls GetMovieDuration
567 //---------------------------------------------------------------------------
568 wxLongLong
wxQTMediaBackend::GetDuration()
570 return ::GetMovieDuration(m_movie
);
573 //---------------------------------------------------------------------------
574 // wxQTMediaBackend::GetState
576 // Determines the current state - the timer keeps track of whether or not
577 // we are paused or stopped (if the timer is running we are playing)
578 //---------------------------------------------------------------------------
579 wxMediaState
wxQTMediaBackend::GetState()
581 if ( !m_timer
|| (m_timer
->IsRunning() == false &&
582 m_timer
->GetPaused() == false) )
583 return wxMEDIASTATE_STOPPED
;
585 if( m_timer
->IsRunning() == true )
586 return wxMEDIASTATE_PLAYING
;
588 return wxMEDIASTATE_PAUSED
;
591 //---------------------------------------------------------------------------
592 // wxQTMediaBackend::Cleanup
594 // Diposes of the movie timer, Control if native, and stops and disposes
596 //---------------------------------------------------------------------------
597 void wxQTMediaBackend::Cleanup()
602 #if wxUSE_CREATEMOVIECONTROL
603 DisposeControl(GetControlPeer(m_ctrl
)->GetControlRef());
607 DisposeMovie(m_movie
);
610 //---------------------------------------------------------------------------
611 // wxQTMediaBackend::GetVideoSize
613 // Returns the actual size of the QT movie
614 //---------------------------------------------------------------------------
615 wxSize
wxQTMediaBackend::GetVideoSize() const
620 //---------------------------------------------------------------------------
621 // wxQTMediaBackend::Move
623 // If not using a native 10.2 QT control performs some emulated window
625 //---------------------------------------------------------------------------
626 void wxQTMediaBackend::Move(int x
, int y
, int w
, int h
)
628 #if !wxUSE_CREATEMOVIECONTROL
633 m_ctrl
->GetParent()->MacWindowToRootWindow(&x
, &y
);
636 Rect theRect
= {y
, x
, y
+h
, x
+w
};
638 ::SetMovieBox(m_movie
, &theRect
);
639 wxASSERT(::GetMoviesError() == noErr
);
645 //in source file that contains stuff you don't directly use
646 #include <wx/html/forcelnk.h>
647 FORCE_LINK_ME(basewxmediabackends
);
649 #endif //wxUSE_MEDIACTRL