]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/mediactrl.cpp
wxTextPos for all GetLastPosition with constants for special cases. Make it virtual...
[wxWidgets.git] / src / mac / carbon / mediactrl.cpp
CommitLineData
1a680109 1/////////////////////////////////////////////////////////////////////////////
ff4aedc5
RN
2// Name: mac/carbon/mediactrl.cpp
3// Purpose: Built-in Media Backends for Mac
1a680109 4// Author: Ryan Norton <wxprojects@comcast.net>
ff4aedc5 5// Modified by:
1a680109
RN
6// Created: 11/07/04
7// RCS-ID: $Id$
8// Copyright: (c) Ryan Norton
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
ff4aedc5
RN
12//===========================================================================
13// DECLARATIONS
14//===========================================================================
15
16//---------------------------------------------------------------------------
17// Pre-compiled header stuff
18//---------------------------------------------------------------------------
19
20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21#pragma implementation "mediactrl.h"
22#endif
1a680109
RN
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28#pragma hdrstop
29#endif
30
ff4aedc5
RN
31//---------------------------------------------------------------------------
32// Includes
33//---------------------------------------------------------------------------
34#include "wx/mediactrl.h"
1a680109 35
ff4aedc5
RN
36//---------------------------------------------------------------------------
37// Compilation guard
38//---------------------------------------------------------------------------
1a680109
RN
39#if wxUSE_MEDIACTRL
40
ff4aedc5
RN
41//===========================================================================
42// BACKEND DECLARATIONS
43//===========================================================================
212945de 44
ff4aedc5
RN
45//---------------------------------------------------------------------------
46//
47// wxQTMediaBackend
48//
49//---------------------------------------------------------------------------
1a680109 50
ff4aedc5
RN
51//---------------------------------------------------------------------------
52// QT Includes
53//---------------------------------------------------------------------------
1a680109 54//uma is for wxMacFSSpec
1a680109 55#include "wx/mac/uma.h"
ff4aedc5 56#include "wx/timer.h"
1a680109
RN
57#include <Movies.h>
58#include <Gestalt.h>
ff4aedc5 59#include <QuickTimeComponents.h> //Standard QT stuff
1a680109 60
ff4aedc5
RN
61//Determines whether version 6 of QT is installed
62Boolean _wxIsQuickTime4Installed (void)
63{
64 short error;
65 long result;
1a680109 66
ff4aedc5
RN
67 error = Gestalt (gestaltQuickTime, &result);
68 return (error == noErr) && (((result >> 16) & 0xffff) >= 0x0400);
69}
70
ff2b312f 71class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackend
ff4aedc5
RN
72{
73public:
74
75 wxQTMediaBackend();
76 ~wxQTMediaBackend();
77
78 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
79 wxWindowID id,
80 const wxPoint& pos,
81 const wxSize& size,
82 long style,
83 const wxValidator& validator,
84 const wxString& name);
85
86 virtual bool Play();
87 virtual bool Pause();
88 virtual bool Stop();
89
90 virtual bool Load(const wxString& fileName);
91 virtual bool Load(const wxURI& location);
92
93 virtual wxMediaState GetState();
94
95 virtual bool SetPosition(wxLongLong where);
96 virtual wxLongLong GetPosition();
97 virtual wxLongLong GetDuration();
98
99 virtual void Move(int x, int y, int w, int h);
100 wxSize GetVideoSize() const;
101
102 virtual double GetPlaybackRate();
103 virtual bool SetPlaybackRate(double dRate);
104
105 void Cleanup();
106 void FinishLoad();
107
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
113
114 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend);
115};
116
117
118//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
119//
120// wxQTMediaBackend
121//
122// TODO: Use a less cludgy way to pause/get state/set state
123// TODO: Dynamically load from qtml.dll
124//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
125
126IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
1a680109
RN
127
128//Time between timer calls
ff4aedc5 129#define MOVIE_DELAY 100
1a680109 130
ff4aedc5 131// --------------------------------------------------------------------------
1a680109 132// wxQTTimer - Handle Asyncronous Playing
ff4aedc5 133// --------------------------------------------------------------------------
1a680109
RN
134class _wxQTTimer : public wxTimer
135{
136public:
ff4aedc5 137 _wxQTTimer(Movie movie, wxQTMediaBackend* parent) :
1a680109
RN
138 m_movie(movie), m_bPaused(false), m_parent(parent)
139 {
140 }
141
142 ~_wxQTTimer()
143 {
144 }
145
146 bool GetPaused() {return m_bPaused;}
147 void SetPaused(bool bPaused) {m_bPaused = bPaused;}
148
ff4aedc5
RN
149 //-----------------------------------------------------------------------
150 // _wxQTTimer::Notify
151 //
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
155 // the movie.
156 //-----------------------------------------------------------------------
1a680109
RN
157 void Notify()
158 {
159 if (!m_bPaused)
160 {
161 if(!IsMovieDone(m_movie))
ff4aedc5 162 MoviesTask(m_movie, MOVIE_DELAY);
1a680109
RN
163 else
164 {
ff4aedc5
RN
165 wxMediaEvent theEvent(wxEVT_MEDIA_STOP,
166 m_parent->m_ctrl->GetId());
167 m_parent->m_ctrl->ProcessEvent(theEvent);
168
169 if(theEvent.IsAllowed())
170 {
171 Stop();
172 m_parent->Stop();
173 wxASSERT(::GetMoviesError() == noErr);
174
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);
179 }
1a680109
RN
180 }
181 }
182 }
183
184protected:
ff4aedc5
RN
185 Movie m_movie; //Our movie instance
186 bool m_bPaused; //Whether we are paused or not
187 wxQTMediaBackend* m_parent; //Backend pointer
1a680109
RN
188};
189
ff4aedc5 190//---------------------------------------------------------------------------
e7b97da3 191// wxQTMediaBackend Constructor
ff4aedc5
RN
192//
193// Sets m_timer to NULL signifying we havn't loaded anything yet
194//---------------------------------------------------------------------------
195wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL)
1a680109 196{
1a680109
RN
197}
198
ff4aedc5
RN
199//---------------------------------------------------------------------------
200// wxQTMediaBackend Destructor
201//
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//---------------------------------------------------------------------------
208wxQTMediaBackend::~wxQTMediaBackend()
1a680109 209{
ff4aedc5
RN
210 if(m_timer)
211 Cleanup();
1a680109 212
ff4aedc5
RN
213 //Note that ExitMovies() is not neccessary...
214 ExitMovies();
1a680109
RN
215}
216
ff4aedc5
RN
217//---------------------------------------------------------------------------
218// wxQTMediaBackend::CreateControl
219//
220// 1) Intializes QuickTime
221// 2) Creates the control window
222//---------------------------------------------------------------------------
223bool wxQTMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
224 wxWindowID id,
225 const wxPoint& pos,
226 const wxSize& size,
227 long style,
228 const wxValidator& validator,
229 const wxString& name)
1a680109 230{
ff4aedc5 231 if (!_wxIsQuickTime4Installed())
1a680109 232 return false;
1a680109 233
ff4aedc5
RN
234 EnterMovies();
235
236 //
237 // Create window
238 // By default wxWindow(s) is created with a border -
239 // so we need to get rid of those
240 //
241 // Since we don't have a child window like most other
242 // backends, we don't need wxCLIP_CHILDREN
243 //
244 if ( !ctrl->wxControl::Create(parent, id, pos, size,
245 m_ctrl->MacRemoveBordersFromStyle(style),
246 validator, name) )
1a680109
RN
247 return false;
248
ff4aedc5 249 //
1a680109 250 //Set our background color to black by default
ff4aedc5
RN
251 //
252 ctrl->SetBackgroundColour(*wxBLACK);
1a680109 253
ff4aedc5 254 m_ctrl = ctrl;
1a680109
RN
255 return true;
256}
257
ff4aedc5
RN
258//---------------------------------------------------------------------------
259// wxQTMediaBackend::Load (file version)
260//
261// 1) Get an FSSpec from the Windows path name
262// 2) Open the movie
263// 3) Obtain the movie instance from the movie resource
264// 4)
265//---------------------------------------------------------------------------
266bool wxQTMediaBackend::Load(const wxString& fileName)
1a680109 267{
ff4aedc5 268 if(m_timer)
1a680109
RN
269 Cleanup();
270
1a680109
RN
271 OSErr err = noErr;
272 short movieResFile;
273 FSSpec sfFile;
ff4aedc5
RN
274
275 wxMacFilename2FSSpec( fileName , &sfFile );
276
1a680109
RN
277 if (OpenMovieFile (&sfFile, &movieResFile, fsRdPerm) != noErr)
278 return false;
279
280 short movieResID = 0;
281 Str255 movieName;
282
283 err = NewMovieFromFile (
284 &m_movie,
285 movieResFile,
286 &movieResID,
287 movieName,
288 newMovieActive,
289 NULL); //wasChanged
290
291 CloseMovieFile (movieResFile);
292
293 if (err != noErr)
294 return false;
295
296 FinishLoad();
297
ff4aedc5 298 return ::GetMoviesError() == noErr;
1a680109
RN
299}
300
ff4aedc5 301//---------------------------------------------------------------------------
e7b97da3 302// wxQTMediaBackend::Load
ff4aedc5
RN
303//
304// TODO
305//---------------------------------------------------------------------------
306bool wxQTMediaBackend::Load(const wxURI& location)
1a680109 307{
ff4aedc5 308 if(m_timer)
1a680109
RN
309 Cleanup();
310
1a680109
RN
311 wxString theURI = location.BuildURI();
312
313 OSErr err = noErr;
314
315 Handle theHandle = NewHandleClear(theURI.length() + 1);
316 wxASSERT(theHandle);
317
318 BlockMove(theURI.mb_str(), *theHandle, theURI.length() + 1);
319
320 //create the movie from the handle that refers to the URI
321 err = NewMovieFromDataRef(&m_movie, newMovieActive,
322 NULL, theHandle,
323 URLDataHandlerSubType);
324
325 DisposeHandle(theHandle);
326
327 if (err != noErr)
328 return false;
329
330 //preroll movie for streaming
331 //TODO:Async this?
332 TimeValue timeNow;
333 Fixed playRate;
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);
339
340 FinishLoad();
341
ff4aedc5 342 return ::GetMoviesError() == noErr;
1a680109
RN
343}
344
ff4aedc5 345//---------------------------------------------------------------------------
e7b97da3 346// wxQTMediaBackend::FinishLoad
ff4aedc5
RN
347//
348// TODO
349//---------------------------------------------------------------------------
350void wxQTMediaBackend::FinishLoad()
1a680109 351{
ff4aedc5 352 m_timer = new _wxQTTimer(m_movie, (wxQTMediaBackend*) this);
1a680109
RN
353 wxASSERT(m_timer);
354
355 //get the real size of the movie
356 Rect outRect;
357 ::GetMovieNaturalBoundsRect (m_movie, &outRect);
358 wxASSERT(::GetMoviesError() == noErr);
359
360 m_bestSize.x = outRect.right - outRect.left;
361 m_bestSize.y = outRect.bottom - outRect.top;
362
ff4aedc5
RN
363 //reparent movie/*AudioMediaCharacteristic*/
364 if(GetMovieIndTrackType(m_movie, 1,
365 VisualMediaCharacteristic,
366 movieTrackCharacteristic |
367 movieTrackEnabledOnly) != NULL)
368 {
369 SetMovieGWorld(m_movie,
370 (CGrafPtr)
371 GetWindowPort(
372 (WindowRef)
373 m_ctrl->MacGetTopLevelWindowRef()
374 ),
375 nil);
1a680109
RN
376 }
377
1a680109
RN
378 //we want millisecond precision
379 ::SetMovieTimeScale(m_movie, 1000);
ff4aedc5
RN
380 wxASSERT(::GetMoviesError() == noErr);
381
382 //
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
386 //
387 m_ctrl->InvalidateBestSize();
388 m_ctrl->GetParent()->Layout();
389 m_ctrl->GetParent()->Refresh();
390 m_ctrl->GetParent()->Update();
1a680109
RN
391}
392
ff4aedc5 393//---------------------------------------------------------------------------
e7b97da3 394// wxQTMediaBackend::Play
ff4aedc5
RN
395//
396// TODO
397//---------------------------------------------------------------------------
398bool wxQTMediaBackend::Play()
1a680109 399{
1a680109
RN
400 ::StartMovie(m_movie);
401 m_timer->SetPaused(false);
402 m_timer->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
403 return ::GetMoviesError() == noErr;
404}
405
ff4aedc5 406//---------------------------------------------------------------------------
e7b97da3 407// wxQTMediaBackend::Pause
ff4aedc5
RN
408//
409// TODO
410//---------------------------------------------------------------------------
411bool wxQTMediaBackend::Pause()
1a680109 412{
1a680109
RN
413 ::StopMovie(m_movie);
414 m_timer->SetPaused(true);
415 m_timer->Stop();
416 return ::GetMoviesError() == noErr;
417}
418
ff4aedc5 419//---------------------------------------------------------------------------
e7b97da3 420// wxQTMediaBackend::Stop
ff4aedc5
RN
421//
422// TODO
423//---------------------------------------------------------------------------
424bool wxQTMediaBackend::Stop()
1a680109 425{
1a680109
RN
426 m_timer->SetPaused(false);
427 m_timer->Stop();
428
429 ::StopMovie(m_movie);
430 if(::GetMoviesError() != noErr)
431 return false;
432
433 ::GoToBeginningOfMovie(m_movie);
434 return ::GetMoviesError() == noErr;
435}
436
ff4aedc5 437//---------------------------------------------------------------------------
e7b97da3 438// wxQTMediaBackend::GetPlaybackRate
ff4aedc5
RN
439//
440// TODO
441//---------------------------------------------------------------------------
442double wxQTMediaBackend::GetPlaybackRate()
1a680109 443{
1a680109
RN
444 return ( ((double)::GetMovieRate(m_movie)) / 0x10000);
445}
446
ff4aedc5 447//---------------------------------------------------------------------------
e7b97da3 448// wxQTMediaBackend::SetPlaybackRate
ff4aedc5
RN
449//
450// TODO
451//---------------------------------------------------------------------------
452bool wxQTMediaBackend::SetPlaybackRate(double dRate)
1a680109 453{
1a680109
RN
454 ::SetMovieRate(m_movie, (Fixed) (dRate * 0x10000));
455 return ::GetMoviesError() == noErr;
456}
457
ff4aedc5 458//---------------------------------------------------------------------------
e7b97da3 459// wxQTMediaBackend::SetPosition
ff4aedc5
RN
460//
461// TODO
462//---------------------------------------------------------------------------
463bool wxQTMediaBackend::SetPosition(wxLongLong where)
1a680109 464{
1a680109
RN
465 TimeRecord theTimeRecord;
466 memset(&theTimeRecord, 0, sizeof(TimeRecord));
ff4aedc5 467 theTimeRecord.value.lo = where.GetValue();
1a680109
RN
468 theTimeRecord.scale = ::GetMovieTimeScale(m_movie);
469 theTimeRecord.base = ::GetMovieTimeBase(m_movie);
470 ::SetMovieTime(m_movie, &theTimeRecord);
471
472 if (::GetMoviesError() != noErr)
473 return false;
474
475 return true;
476}
477
ff4aedc5 478//---------------------------------------------------------------------------
e7b97da3 479// wxQTMediaBackend::GetPosition
ff4aedc5
RN
480//
481// TODO
482//---------------------------------------------------------------------------
483wxLongLong wxQTMediaBackend::GetPosition()
1a680109 484{
1a680109
RN
485 return ::GetMovieTime(m_movie, NULL);
486}
487
ff4aedc5 488//---------------------------------------------------------------------------
e7b97da3 489// wxQTMediaBackend::GetDuration
ff4aedc5
RN
490//
491// TODO
492//---------------------------------------------------------------------------
493wxLongLong wxQTMediaBackend::GetDuration()
1a680109 494{
1a680109
RN
495 return ::GetMovieDuration(m_movie);
496}
497
ff4aedc5 498//---------------------------------------------------------------------------
e7b97da3 499// wxQTMediaBackend::GetState
ff4aedc5
RN
500//
501// TODO
502//---------------------------------------------------------------------------
503wxMediaState wxQTMediaBackend::GetState()
1a680109 504{
ff4aedc5
RN
505 if ( !m_timer || (m_timer->IsRunning() == false &&
506 m_timer->GetPaused() == false) )
1a680109
RN
507 return wxMEDIASTATE_STOPPED;
508
509 if( m_timer->IsRunning() == true )
510 return wxMEDIASTATE_PLAYING;
511 else
512 return wxMEDIASTATE_PAUSED;
513}
514
ff4aedc5 515//---------------------------------------------------------------------------
e7b97da3 516// wxQTMediaBackend::Cleanup
ff4aedc5
RN
517//
518// TODO
519//---------------------------------------------------------------------------
520void wxQTMediaBackend::Cleanup()
1a680109
RN
521{
522 delete m_timer;
523 m_timer = NULL;
524
525 StopMovie(m_movie);
526 DisposeMovie(m_movie);
1a680109
RN
527}
528
ff4aedc5 529//---------------------------------------------------------------------------
e7b97da3 530// wxQTMediaBackend::GetVideoSize
ff4aedc5
RN
531//
532// TODO
533//---------------------------------------------------------------------------
534wxSize wxQTMediaBackend::GetVideoSize() const
1a680109
RN
535{
536 return m_bestSize;
537}
538
ff4aedc5
RN
539//---------------------------------------------------------------------------
540// wxQTMediaBackend::Move
541//
542// TODO
543//---------------------------------------------------------------------------
544void wxQTMediaBackend::Move(int x, int y, int w, int h)
1a680109 545{
ff4aedc5 546 if(m_timer)
1a680109 547 {
e7b97da3
RD
548 if ( m_ctrl )
549 {
550 m_ctrl->GetParent()->MacWindowToRootWindow(&x, &y);
551 }
552
1a680109 553 Rect theRect = {y, x, y+h, x+w};
ff4aedc5 554
1a680109
RN
555 ::SetMovieBox(m_movie, &theRect);
556 wxASSERT(::GetMoviesError() == noErr);
557 }
558}
559
ff4aedc5
RN
560
561//in source file that contains stuff you don't directly use
562#include <wx/html/forcelnk.h>
563FORCE_LINK_ME(basewxmediabackends);
564
565#endif //wxUSE_MEDIACTRL
566
567
568
569
570