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"
72 #include <QuickTimeComponents.h> //Standard QT stuff
74 #include <QuickTime/QuickTimeComponents.h>
77 //Determines whether version 4 of QT is installed (Pretty much for classic only)
78 Boolean
_wxIsQuickTime4Installed (void)
83 error
= Gestalt (gestaltQuickTime
, &result
);
84 return (error
== noErr
) && (((result
>> 16) & 0xffff) >= 0x0400);
87 class WXDLLIMPEXP_MEDIA wxQTMediaBackend
: public wxMediaBackend
94 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
99 const wxValidator
& validator
,
100 const wxString
& name
);
103 virtual bool Pause();
106 virtual bool Load(const wxString
& fileName
);
107 virtual bool Load(const wxURI
& location
);
109 virtual wxMediaState
GetState();
111 virtual bool SetPosition(wxLongLong where
);
112 virtual wxLongLong
GetPosition();
113 virtual wxLongLong
GetDuration();
115 virtual void Move(int x
, int y
, int w
, int h
);
116 wxSize
GetVideoSize() const;
118 virtual double GetPlaybackRate();
119 virtual bool SetPlaybackRate(double dRate
);
124 wxSize m_bestSize
; //Original movie size
126 struct MovieType
** m_movie
; //QT Movie handle/instance
130 wxControl
* m_ctrl
; //Parent control
131 bool m_bVideo
; //Whether or not we have video
132 class _wxQTTimer
* m_timer
; //Timer for streaming the movie
134 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend
)
138 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
142 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
144 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend
, wxMediaBackend
);
146 //Time between timer calls
147 #define MOVIE_DELAY 100
149 // --------------------------------------------------------------------------
150 // wxQTTimer - Handle Asyncronous Playing
151 // --------------------------------------------------------------------------
152 class _wxQTTimer
: public wxTimer
155 _wxQTTimer(Movie movie
, wxQTMediaBackend
* parent
) :
156 m_movie(movie
), m_bPaused(false), m_parent(parent
)
164 bool GetPaused() {return m_bPaused
;}
165 void SetPaused(bool bPaused
) {m_bPaused
= bPaused
;}
167 //-----------------------------------------------------------------------
168 // _wxQTTimer::Notify
170 // 1) Checks to see if the movie is done, and if not continues
171 // streaming the movie
172 // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
174 //-----------------------------------------------------------------------
179 if(!IsMovieDone(m_movie
))
180 MoviesTask(m_movie
, MOVIE_DELAY
);
183 wxMediaEvent
theEvent(wxEVT_MEDIA_STOP
,
184 m_parent
->m_ctrl
->GetId());
185 m_parent
->m_ctrl
->ProcessEvent(theEvent
);
187 if(theEvent
.IsAllowed())
191 wxASSERT(::GetMoviesError() == noErr
);
193 //send the event to our child
194 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
,
195 m_parent
->m_ctrl
->GetId());
196 m_parent
->m_ctrl
->ProcessEvent(theEvent
);
203 Movie m_movie
; //Our movie instance
204 bool m_bPaused
; //Whether we are paused or not
205 wxQTMediaBackend
* m_parent
; //Backend pointer
208 //---------------------------------------------------------------------------
209 // wxQTMediaBackend Constructor
211 // Sets m_timer to NULL signifying we havn't loaded anything yet
212 //---------------------------------------------------------------------------
213 wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL
)
217 //---------------------------------------------------------------------------
218 // wxQTMediaBackend Destructor
220 // 1) Cleans up the QuickTime movie instance
221 // 2) Decrements the QuickTime reference counter - if this reaches
222 // 0, QuickTime shuts down
223 // 3) Decrements the QuickTime Windows Media Layer reference counter -
224 // if this reaches 0, QuickTime shuts down the Windows Media Layer
225 //---------------------------------------------------------------------------
226 wxQTMediaBackend::~wxQTMediaBackend()
231 //Note that ExitMovies() is not necessary...
235 //---------------------------------------------------------------------------
236 // wxQTMediaBackend::CreateControl
238 // 1) Intializes QuickTime
239 // 2) Creates the control window
240 //---------------------------------------------------------------------------
241 bool wxQTMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
246 const wxValidator
& validator
,
247 const wxString
& name
)
249 //Don't bother in Native control mode
250 #if defined( __WXMAC__ ) && TARGET_API_MAC_OSX && ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_2 )
251 if (!_wxIsQuickTime4Installed())
259 // By default wxWindow(s) is created with a border -
260 // so we need to get rid of those
262 // Since we don't have a child window like most other
263 // backends, we don't need wxCLIP_CHILDREN
267 #if wxUSE_CREATEMOVIECONTROL
268 ctrl
->wxWindow::Create(parent
, id
, pos
, size
,
269 wxWindow::MacRemoveBordersFromStyle(style
),
272 ctrl
->wxControl::Create(parent
, id
, pos
, size
,
273 wxWindow::MacRemoveBordersFromStyle(style
),
280 ctrl
->SetValidator(validator
);
287 //---------------------------------------------------------------------------
288 // wxQTMediaBackend::Load (file version)
290 // 1) Get an FSSpec from the Windows path name
292 // 3) Obtain the movie instance from the movie resource
293 // 4) Close the movie resource
295 //---------------------------------------------------------------------------
296 bool wxQTMediaBackend::Load(const wxString
& fileName
)
305 //FIXME:wxMacFilename2FSSpec crashes on empty string -
306 //does it crash on other strings too and should this
307 //"fix" be put in the carbon wxSound?
308 if (fileName
.empty())
311 wxMacFilename2FSSpec( fileName
, &sfFile
);
313 if (OpenMovieFile (&sfFile
, &movieResFile
, fsRdPerm
) != noErr
)
316 short movieResID
= 0;
319 err
= NewMovieFromFile (
327 CloseMovieFile (movieResFile
);
334 return ::GetMoviesError() == noErr
;
337 //---------------------------------------------------------------------------
338 // wxQTMediaBackend::Load (URL Version)
340 // 1) Build an escaped URI from location
341 // 2) Create a handle to store the URI string
342 // 3) Put the URI string inside the handle
343 // 4) Make a QuickTime URL data ref from the handle with the URI in it
344 // 5) Clean up the URI string handle
345 // 6) Do some prerolling
347 //---------------------------------------------------------------------------
348 bool wxQTMediaBackend::Load(const wxURI
& location
)
353 wxString theURI
= location
.BuildURI();
357 Handle theHandle
= NewHandleClear(theURI
.length() + 1);
360 BlockMove(theURI
.mb_str(), *theHandle
, theURI
.length() + 1);
362 //create the movie from the handle that refers to the URI
363 err
= NewMovieFromDataRef(&m_movie
, newMovieActive
,
365 URLDataHandlerSubType
);
367 DisposeHandle(theHandle
);
372 //preroll movie for streaming
373 //TODO:Async this using threads?
376 timeNow
= GetMovieTime(m_movie
, NULL
);
377 playRate
= GetMoviePreferredRate(m_movie
);
378 PrePrerollMovie(m_movie
, timeNow
, playRate
, NULL
, NULL
);
379 PrerollMovie(m_movie
, timeNow
, playRate
);
380 SetMovieRate(m_movie
, playRate
);
384 return ::GetMoviesError() == noErr
;
387 //---------------------------------------------------------------------------
388 // wxQTMediaBackend::FinishLoad
390 // 1) Create the movie timer
391 // 2) Get real size of movie for GetBestSize/sizers
392 // 3) See if there is video in the movie, and if so then either
393 // SetMovieGWorld if < 10.2 or use Native CreateMovieControl
394 // 4) Set the movie time scale to something usable so that seeking
395 // etc. will work correctly
396 // 5) Refresh parent window
397 //---------------------------------------------------------------------------
398 void wxQTMediaBackend::FinishLoad()
400 m_timer
= new _wxQTTimer(m_movie
, (wxQTMediaBackend
*) this);
403 //get the real size of the movie
405 ::GetMovieNaturalBoundsRect (m_movie
, &outRect
);
406 wxASSERT(::GetMoviesError() == noErr
);
408 m_bestSize
.x
= outRect
.right
- outRect
.left
;
409 m_bestSize
.y
= outRect
.bottom
- outRect
.top
;
411 //reparent movie/*AudioMediaCharacteristic*/
412 if(GetMovieIndTrackType(m_movie
, 1,
413 VisualMediaCharacteristic
,
414 movieTrackCharacteristic
|
415 movieTrackEnabledOnly
) != NULL
)
417 #if wxUSE_CREATEMOVIECONTROL
419 //Native CreateMovieControl QT control (Thanks to Kevin Olliver's
420 //wxQTMovie for some of this).
422 #define GetControlPeer(whatever) ctrl->m_peer
423 wxMediaCtrl
* ctrl
= (wxMediaCtrl
*) m_ctrl
;
424 Rect bounds
= wxMacGetBoundsForControl(m_ctrl
,
425 m_ctrl
->GetPosition(),
428 //Dispose of old control for new one
429 if (GetControlPeer(m_ctrl
) && GetControlPeer(m_ctrl
)->Ok() )
430 GetControlPeer(m_ctrl
)->Dispose();
433 //kMovieControlOptionXXX
434 //HideController - hide the movie controller
435 //LocateTopLeft - movie is pinned to top left rather than centered in the control
436 //EnableEditing - Allows programmatic editing and dragn'drop
437 //HandleEditingHI- Installs event stuff for edit menu - forces EnableEditing also
438 //SetKeysEnabled - Allows keyboard input
439 //ManuallyIdled - app handles movie idling rather than internal timer event loop
440 ::CreateMovieControl(
442 ctrl
->MacGetTopLevelWindowRef(), //parent
443 &bounds
, //control bounds
444 m_movie
, //movie handle
445 kMovieControlOptionHideController
446 | kMovieControlOptionLocateTopLeft
447 | kMovieControlOptionSetKeysEnabled
448 // | kMovieControlOptionManuallyIdled
450 ctrl
->m_peer
->GetControlRefAddr() );
452 ::EmbedControl(ctrl
->m_peer
->GetControlRef(), (ControlRef
)ctrl
->GetParent()->GetHandle());
457 SetMovieGWorld(m_movie
,
461 m_ctrl
->MacGetTopLevelWindowRef()
467 //we want millisecond precision
468 ::SetMovieTimeScale(m_movie
, 1000);
469 wxASSERT(::GetMoviesError() == noErr
);
472 //Here, if the parent of the control has a sizer - we
473 //tell it to recalculate the size of this control since
474 //the user opened a separate media file
476 m_ctrl
->InvalidateBestSize();
477 m_ctrl
->GetParent()->Layout();
478 m_ctrl
->GetParent()->Refresh();
479 m_ctrl
->GetParent()->Update();
482 //---------------------------------------------------------------------------
483 // wxQTMediaBackend::Play
485 // 1) Start the QT movie
486 // 2) Start the movie loading timer
487 //---------------------------------------------------------------------------
488 bool wxQTMediaBackend::Play()
490 ::StartMovie(m_movie
);
491 m_timer
->SetPaused(false);
492 m_timer
->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
);
493 return ::GetMoviesError() == noErr
;
496 //---------------------------------------------------------------------------
497 // wxQTMediaBackend::Pause
500 // 2) Stop the movie timer
501 //---------------------------------------------------------------------------
502 bool wxQTMediaBackend::Pause()
504 ::StopMovie(m_movie
);
505 m_timer
->SetPaused(true);
507 return ::GetMoviesError() == noErr
;
510 //---------------------------------------------------------------------------
511 // wxQTMediaBackend::Stop
514 // 2) Stop the movie timer
515 // 3) Seek to the beginning of the movie
516 //---------------------------------------------------------------------------
517 bool wxQTMediaBackend::Stop()
519 m_timer
->SetPaused(false);
522 ::StopMovie(m_movie
);
523 if(::GetMoviesError() != noErr
)
526 ::GoToBeginningOfMovie(m_movie
);
527 return ::GetMoviesError() == noErr
;
530 //---------------------------------------------------------------------------
531 // wxQTMediaBackend::GetPlaybackRate
533 // 1) Get the movie playback rate from ::GetMovieRate
534 //---------------------------------------------------------------------------
535 double wxQTMediaBackend::GetPlaybackRate()
537 return ( ((double)::GetMovieRate(m_movie
)) / 0x10000);
540 //---------------------------------------------------------------------------
541 // wxQTMediaBackend::SetPlaybackRate
543 // 1) Convert dRate to Fixed and Set the movie rate through SetMovieRate
544 //---------------------------------------------------------------------------
545 bool wxQTMediaBackend::SetPlaybackRate(double dRate
)
547 ::SetMovieRate(m_movie
, (Fixed
) (dRate
* 0x10000));
548 return ::GetMoviesError() == noErr
;
551 //---------------------------------------------------------------------------
552 // wxQTMediaBackend::SetPosition
554 // 1) Create a time record struct (TimeRecord) with appropriate values
555 // 2) Pass struct to SetMovieTime
556 //---------------------------------------------------------------------------
557 bool wxQTMediaBackend::SetPosition(wxLongLong where
)
559 TimeRecord theTimeRecord
;
560 memset(&theTimeRecord
, 0, sizeof(TimeRecord
));
561 theTimeRecord
.value
.lo
= where
.GetValue();
562 theTimeRecord
.scale
= ::GetMovieTimeScale(m_movie
);
563 theTimeRecord
.base
= ::GetMovieTimeBase(m_movie
);
564 ::SetMovieTime(m_movie
, &theTimeRecord
);
566 if (::GetMoviesError() != noErr
)
572 //---------------------------------------------------------------------------
573 // wxQTMediaBackend::GetPosition
575 // Calls GetMovieTime
576 //---------------------------------------------------------------------------
577 wxLongLong
wxQTMediaBackend::GetPosition()
579 return ::GetMovieTime(m_movie
, NULL
);
582 //---------------------------------------------------------------------------
583 // wxQTMediaBackend::GetDuration
585 // Calls GetMovieDuration
586 //---------------------------------------------------------------------------
587 wxLongLong
wxQTMediaBackend::GetDuration()
589 return ::GetMovieDuration(m_movie
);
592 //---------------------------------------------------------------------------
593 // wxQTMediaBackend::GetState
595 // Determines the current state - the timer keeps track of whether or not
596 // we are paused or stopped (if the timer is running we are playing)
597 //---------------------------------------------------------------------------
598 wxMediaState
wxQTMediaBackend::GetState()
600 if ( !m_timer
|| (m_timer
->IsRunning() == false &&
601 m_timer
->GetPaused() == false) )
602 return wxMEDIASTATE_STOPPED
;
604 if( m_timer
->IsRunning() )
605 return wxMEDIASTATE_PLAYING
;
607 return wxMEDIASTATE_PAUSED
;
610 //---------------------------------------------------------------------------
611 // wxQTMediaBackend::Cleanup
613 // Diposes of the movie timer, Control if native, and stops and disposes
615 //---------------------------------------------------------------------------
616 void wxQTMediaBackend::Cleanup()
621 #if wxUSE_CREATEMOVIECONTROL
622 DisposeControl(((wxMediaCtrl
*)m_ctrl
)->m_peer
->GetControlRef());
626 DisposeMovie(m_movie
);
629 //---------------------------------------------------------------------------
630 // wxQTMediaBackend::GetVideoSize
632 // Returns the actual size of the QT movie
633 //---------------------------------------------------------------------------
634 wxSize
wxQTMediaBackend::GetVideoSize() const
639 //---------------------------------------------------------------------------
640 // wxQTMediaBackend::Move
642 // We need to do this even when using native qt control because
643 // CreateMovieControl is broken in this regard...
644 //---------------------------------------------------------------------------
645 void wxQTMediaBackend::Move(int x
, int y
, int w
, int h
)
647 #if !wxUSE_CREATEMOVIECONTROL
652 m_ctrl
->GetParent()->MacWindowToRootWindow(&x
, &y
);
655 Rect theRect
= {y
, x
, y
+h
, x
+w
};
657 ::SetMovieBox(m_movie
, &theRect
);
658 wxASSERT(::GetMoviesError() == noErr
);
661 if(m_timer
&& m_ctrl
)
663 m_ctrl
->GetParent()->MacWindowToRootWindow(&x
, &y
);
665 ::MoveControl( (ControlRef
) m_ctrl
->GetHandle(), x
, y
);
666 m_ctrl
->GetParent()->Refresh();
667 m_ctrl
->GetParent()->Update();
673 //in source file that contains stuff you don't directly use
674 #include "wx/html/forcelnk.h"
675 FORCE_LINK_ME(basewxmediabackends
);
677 #endif //wxUSE_MEDIACTRL