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) Ryan Norton
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 // BACKEND DECLARATIONS
43 //===========================================================================
45 //---------------------------------------------------------------------------
49 //---------------------------------------------------------------------------
51 //---------------------------------------------------------------------------
53 //---------------------------------------------------------------------------
54 //uma is for wxMacFSSpec
55 #include "wx/mac/uma.h"
59 #include <QuickTimeComponents.h> //Standard QT stuff
61 //Determines whether version 6 of QT is installed
62 Boolean
_wxIsQuickTime4Installed (void)
67 error
= Gestalt (gestaltQuickTime
, &result
);
68 return (error
== noErr
) && (((result
>> 16) & 0xffff) >= 0x0400);
71 class wxQTMediaBackend
: public wxMediaBackend
78 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
83 const wxValidator
& validator
,
84 const wxString
& name
);
90 virtual bool Load(const wxString
& fileName
);
91 virtual bool Load(const wxURI
& location
);
93 virtual wxMediaState
GetState();
95 virtual bool SetPosition(wxLongLong where
);
96 virtual wxLongLong
GetPosition();
97 virtual wxLongLong
GetDuration();
99 virtual void Move(int x
, int y
, int w
, int h
);
100 wxSize
GetVideoSize() const;
102 virtual double GetPlaybackRate();
103 virtual bool SetPlaybackRate(double dRate
);
108 wxSize m_bestSize
; //Original movie size
109 struct MovieType
** m_movie
; //QT Movie handle/instance
110 wxControl
* m_ctrl
; //Parent control
111 bool m_bVideo
; //Whether or not we have video
112 class _wxQTTimer
* m_timer
; //Timer for streaming the movie
114 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend
);
118 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
122 // TODO: Use a less cludgy way to pause/get state/set state
123 // TODO: Dynamically load from qtml.dll
124 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
126 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend
, wxMediaBackend
);
128 //Time between timer calls
129 #define MOVIE_DELAY 100
131 // --------------------------------------------------------------------------
132 // wxQTTimer - Handle Asyncronous Playing
133 // --------------------------------------------------------------------------
134 class _wxQTTimer
: public wxTimer
137 _wxQTTimer(Movie movie
, wxQTMediaBackend
* parent
) :
138 m_movie(movie
), m_bPaused(false), m_parent(parent
)
146 bool GetPaused() {return m_bPaused
;}
147 void SetPaused(bool bPaused
) {m_bPaused
= bPaused
;}
149 //-----------------------------------------------------------------------
150 // _wxQTTimer::Notify
152 // 1) Checks to see if the movie is done, and if not continues
153 // streaming the movie
154 // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
156 //-----------------------------------------------------------------------
161 if(!IsMovieDone(m_movie
))
162 MoviesTask(m_movie
, MOVIE_DELAY
);
165 wxMediaEvent
theEvent(wxEVT_MEDIA_STOP
,
166 m_parent
->m_ctrl
->GetId());
167 m_parent
->m_ctrl
->ProcessEvent(theEvent
);
169 if(theEvent
.IsAllowed())
173 wxASSERT(::GetMoviesError() == noErr
);
175 //send the event to our child
176 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
,
177 m_parent
->m_ctrl
->GetId());
178 m_parent
->m_ctrl
->ProcessEvent(theEvent
);
185 Movie m_movie
; //Our movie instance
186 bool m_bPaused
; //Whether we are paused or not
187 wxQTMediaBackend
* m_parent
; //Backend pointer
190 //---------------------------------------------------------------------------
191 // wxQTMediaBackend Destructor
193 // Sets m_timer to NULL signifying we havn't loaded anything yet
194 //---------------------------------------------------------------------------
195 wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL
)
199 //---------------------------------------------------------------------------
200 // wxQTMediaBackend Destructor
202 // 1) Cleans up the QuickTime movie instance
203 // 2) Decrements the QuickTime reference counter - if this reaches
204 // 0, QuickTime shuts down
205 // 3) Decrements the QuickTime Windows Media Layer reference counter -
206 // if this reaches 0, QuickTime shuts down the Windows Media Layer
207 //---------------------------------------------------------------------------
208 wxQTMediaBackend::~wxQTMediaBackend()
213 //Note that ExitMovies() is not neccessary...
217 //---------------------------------------------------------------------------
218 // wxQTMediaBackend::CreateControl
220 // 1) Intializes QuickTime
221 // 2) Creates the control window
222 //---------------------------------------------------------------------------
223 bool wxQTMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
228 const wxValidator
& validator
,
229 const wxString
& name
)
231 if (!_wxIsQuickTime4Installed())
238 // By default wxWindow(s) is created with a border -
239 // so we need to get rid of those
241 // Since we don't have a child window like most other
242 // backends, we don't need wxCLIP_CHILDREN
244 if ( !ctrl
->wxControl::Create(parent
, id
, pos
, size
,
245 m_ctrl
->MacRemoveBordersFromStyle(style
),
250 //Set our background color to black by default
252 ctrl
->SetBackgroundColour(*wxBLACK
);
258 //---------------------------------------------------------------------------
259 // wxQTMediaBackend::Load (file version)
261 // 1) Get an FSSpec from the Windows path name
263 // 3) Obtain the movie instance from the movie resource
265 //---------------------------------------------------------------------------
266 bool wxQTMediaBackend::Load(const wxString
& fileName
)
275 wxMacFilename2FSSpec( fileName
, &sfFile
);
277 if (OpenMovieFile (&sfFile
, &movieResFile
, fsRdPerm
) != noErr
)
280 short movieResID
= 0;
283 err
= NewMovieFromFile (
291 CloseMovieFile (movieResFile
);
298 return ::GetMoviesError() == noErr
;
301 //---------------------------------------------------------------------------
302 // wxQTMediaBackend::Move
305 //---------------------------------------------------------------------------
306 bool wxQTMediaBackend::Load(const wxURI
& location
)
311 wxString theURI
= location
.BuildURI();
315 Handle theHandle
= NewHandleClear(theURI
.length() + 1);
318 BlockMove(theURI
.mb_str(), *theHandle
, theURI
.length() + 1);
320 //create the movie from the handle that refers to the URI
321 err
= NewMovieFromDataRef(&m_movie
, newMovieActive
,
323 URLDataHandlerSubType
);
325 DisposeHandle(theHandle
);
330 //preroll movie for streaming
334 timeNow
= GetMovieTime(m_movie
, NULL
);
335 playRate
= GetMoviePreferredRate(m_movie
);
336 PrePrerollMovie(m_movie
, timeNow
, playRate
, NULL
, NULL
);
337 PrerollMovie(m_movie
, timeNow
, playRate
);
338 SetMovieRate(m_movie
, playRate
);
342 return ::GetMoviesError() == noErr
;
345 //---------------------------------------------------------------------------
346 // wxQTMediaBackend::Move
349 //---------------------------------------------------------------------------
350 void wxQTMediaBackend::FinishLoad()
352 m_timer
= new _wxQTTimer(m_movie
, (wxQTMediaBackend
*) this);
355 //get the real size of the movie
357 ::GetMovieNaturalBoundsRect (m_movie
, &outRect
);
358 wxASSERT(::GetMoviesError() == noErr
);
360 m_bestSize
.x
= outRect
.right
- outRect
.left
;
361 m_bestSize
.y
= outRect
.bottom
- outRect
.top
;
363 //reparent movie/*AudioMediaCharacteristic*/
364 if(GetMovieIndTrackType(m_movie
, 1,
365 VisualMediaCharacteristic
,
366 movieTrackCharacteristic
|
367 movieTrackEnabledOnly
) != NULL
)
369 SetMovieGWorld(m_movie
,
373 m_ctrl
->MacGetTopLevelWindowRef()
378 //we want millisecond precision
379 ::SetMovieTimeScale(m_movie
, 1000);
380 wxASSERT(::GetMoviesError() == noErr
);
383 //Here, if the parent of the control has a sizer - we
384 //tell it to recalculate the size of this control since
385 //the user opened a seperate media file
387 m_ctrl
->InvalidateBestSize();
388 m_ctrl
->GetParent()->Layout();
389 m_ctrl
->GetParent()->Refresh();
390 m_ctrl
->GetParent()->Update();
393 //---------------------------------------------------------------------------
394 // wxQTMediaBackend::Move
397 //---------------------------------------------------------------------------
398 bool wxQTMediaBackend::Play()
400 ::StartMovie(m_movie
);
401 m_timer
->SetPaused(false);
402 m_timer
->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
);
403 return ::GetMoviesError() == noErr
;
406 //---------------------------------------------------------------------------
407 // wxQTMediaBackend::Move
410 //---------------------------------------------------------------------------
411 bool wxQTMediaBackend::Pause()
413 ::StopMovie(m_movie
);
414 m_timer
->SetPaused(true);
416 return ::GetMoviesError() == noErr
;
419 //---------------------------------------------------------------------------
420 // wxQTMediaBackend::Move
423 //---------------------------------------------------------------------------
424 bool wxQTMediaBackend::Stop()
426 m_timer
->SetPaused(false);
429 ::StopMovie(m_movie
);
430 if(::GetMoviesError() != noErr
)
433 ::GoToBeginningOfMovie(m_movie
);
434 return ::GetMoviesError() == noErr
;
437 //---------------------------------------------------------------------------
438 // wxQTMediaBackend::Move
441 //---------------------------------------------------------------------------
442 double wxQTMediaBackend::GetPlaybackRate()
444 return ( ((double)::GetMovieRate(m_movie
)) / 0x10000);
447 //---------------------------------------------------------------------------
448 // wxQTMediaBackend::Move
451 //---------------------------------------------------------------------------
452 bool wxQTMediaBackend::SetPlaybackRate(double dRate
)
454 ::SetMovieRate(m_movie
, (Fixed
) (dRate
* 0x10000));
455 return ::GetMoviesError() == noErr
;
458 //---------------------------------------------------------------------------
459 // wxQTMediaBackend::Move
462 //---------------------------------------------------------------------------
463 bool wxQTMediaBackend::SetPosition(wxLongLong where
)
465 TimeRecord theTimeRecord
;
466 memset(&theTimeRecord
, 0, sizeof(TimeRecord
));
467 theTimeRecord
.value
.lo
= where
.GetValue();
468 theTimeRecord
.scale
= ::GetMovieTimeScale(m_movie
);
469 theTimeRecord
.base
= ::GetMovieTimeBase(m_movie
);
470 ::SetMovieTime(m_movie
, &theTimeRecord
);
472 if (::GetMoviesError() != noErr
)
478 //---------------------------------------------------------------------------
479 // wxQTMediaBackend::Move
482 //---------------------------------------------------------------------------
483 wxLongLong
wxQTMediaBackend::GetPosition()
485 return ::GetMovieTime(m_movie
, NULL
);
488 //---------------------------------------------------------------------------
489 // wxQTMediaBackend::Move
492 //---------------------------------------------------------------------------
493 wxLongLong
wxQTMediaBackend::GetDuration()
495 return ::GetMovieDuration(m_movie
);
498 //---------------------------------------------------------------------------
499 // wxQTMediaBackend::Move
502 //---------------------------------------------------------------------------
503 wxMediaState
wxQTMediaBackend::GetState()
505 if ( !m_timer
|| (m_timer
->IsRunning() == false &&
506 m_timer
->GetPaused() == false) )
507 return wxMEDIASTATE_STOPPED
;
509 if( m_timer
->IsRunning() == true )
510 return wxMEDIASTATE_PLAYING
;
512 return wxMEDIASTATE_PAUSED
;
515 //---------------------------------------------------------------------------
516 // wxQTMediaBackend::Move
519 //---------------------------------------------------------------------------
520 void wxQTMediaBackend::Cleanup()
526 DisposeMovie(m_movie
);
529 //---------------------------------------------------------------------------
530 // wxQTMediaBackend::Move
533 //---------------------------------------------------------------------------
534 wxSize
wxQTMediaBackend::GetVideoSize() const
539 //---------------------------------------------------------------------------
540 // wxQTMediaBackend::Move
543 //---------------------------------------------------------------------------
544 void wxQTMediaBackend::Move(int x
, int y
, int w
, int h
)
548 Rect theRect
= {y
, x
, y
+h
, x
+w
};
550 ::SetMovieBox(m_movie
, &theRect
);
551 wxASSERT(::GetMoviesError() == noErr
);
556 //in source file that contains stuff you don't directly use
557 #include <wx/html/forcelnk.h>
558 FORCE_LINK_ME(basewxmediabackends
);
560 #endif //wxUSE_MEDIACTRL