]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/mediactrl.cpp
Fix position of the movie when the immediate parent is not the
[wxWidgets.git] / src / mac / carbon / mediactrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: mac/carbon/mediactrl.cpp
3 // Purpose: Built-in Media Backends for Mac
4 // Author: Ryan Norton <wxprojects@comcast.net>
5 // Modified by:
6 // Created: 11/07/04
7 // RCS-ID: $Id$
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
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
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
31 //---------------------------------------------------------------------------
32 // Includes
33 //---------------------------------------------------------------------------
34 #include "wx/mediactrl.h"
35
36 //---------------------------------------------------------------------------
37 // Compilation guard
38 //---------------------------------------------------------------------------
39 #if wxUSE_MEDIACTRL
40
41 //===========================================================================
42 // BACKEND DECLARATIONS
43 //===========================================================================
44
45 //---------------------------------------------------------------------------
46 //
47 // wxQTMediaBackend
48 //
49 //---------------------------------------------------------------------------
50
51 //---------------------------------------------------------------------------
52 // QT Includes
53 //---------------------------------------------------------------------------
54 //uma is for wxMacFSSpec
55 #include "wx/mac/uma.h"
56 #include "wx/timer.h"
57 #include <Movies.h>
58 #include <Gestalt.h>
59 #include <QuickTimeComponents.h> //Standard QT stuff
60
61 //Determines whether version 6 of QT is installed
62 Boolean _wxIsQuickTime4Installed (void)
63 {
64 short error;
65 long result;
66
67 error = Gestalt (gestaltQuickTime, &result);
68 return (error == noErr) && (((result >> 16) & 0xffff) >= 0x0400);
69 }
70
71 class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackend
72 {
73 public:
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
126 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
127
128 //Time between timer calls
129 #define MOVIE_DELAY 100
130
131 // --------------------------------------------------------------------------
132 // wxQTTimer - Handle Asyncronous Playing
133 // --------------------------------------------------------------------------
134 class _wxQTTimer : public wxTimer
135 {
136 public:
137 _wxQTTimer(Movie movie, wxQTMediaBackend* parent) :
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
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 //-----------------------------------------------------------------------
157 void Notify()
158 {
159 if (!m_bPaused)
160 {
161 if(!IsMovieDone(m_movie))
162 MoviesTask(m_movie, MOVIE_DELAY);
163 else
164 {
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 }
180 }
181 }
182 }
183
184 protected:
185 Movie m_movie; //Our movie instance
186 bool m_bPaused; //Whether we are paused or not
187 wxQTMediaBackend* m_parent; //Backend pointer
188 };
189
190 //---------------------------------------------------------------------------
191 // wxQTMediaBackend Constructor
192 //
193 // Sets m_timer to NULL signifying we havn't loaded anything yet
194 //---------------------------------------------------------------------------
195 wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL)
196 {
197 }
198
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 //---------------------------------------------------------------------------
208 wxQTMediaBackend::~wxQTMediaBackend()
209 {
210 if(m_timer)
211 Cleanup();
212
213 //Note that ExitMovies() is not neccessary...
214 ExitMovies();
215 }
216
217 //---------------------------------------------------------------------------
218 // wxQTMediaBackend::CreateControl
219 //
220 // 1) Intializes QuickTime
221 // 2) Creates the control window
222 //---------------------------------------------------------------------------
223 bool 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)
230 {
231 if (!_wxIsQuickTime4Installed())
232 return false;
233
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) )
247 return false;
248
249 //
250 //Set our background color to black by default
251 //
252 ctrl->SetBackgroundColour(*wxBLACK);
253
254 m_ctrl = ctrl;
255 return true;
256 }
257
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 //---------------------------------------------------------------------------
266 bool wxQTMediaBackend::Load(const wxString& fileName)
267 {
268 if(m_timer)
269 Cleanup();
270
271 OSErr err = noErr;
272 short movieResFile;
273 FSSpec sfFile;
274
275 wxMacFilename2FSSpec( fileName , &sfFile );
276
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
298 return ::GetMoviesError() == noErr;
299 }
300
301 //---------------------------------------------------------------------------
302 // wxQTMediaBackend::Load
303 //
304 // TODO
305 //---------------------------------------------------------------------------
306 bool wxQTMediaBackend::Load(const wxURI& location)
307 {
308 if(m_timer)
309 Cleanup();
310
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
342 return ::GetMoviesError() == noErr;
343 }
344
345 //---------------------------------------------------------------------------
346 // wxQTMediaBackend::FinishLoad
347 //
348 // TODO
349 //---------------------------------------------------------------------------
350 void wxQTMediaBackend::FinishLoad()
351 {
352 m_timer = new _wxQTTimer(m_movie, (wxQTMediaBackend*) this);
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
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);
376 }
377
378 //we want millisecond precision
379 ::SetMovieTimeScale(m_movie, 1000);
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();
391 }
392
393 //---------------------------------------------------------------------------
394 // wxQTMediaBackend::Play
395 //
396 // TODO
397 //---------------------------------------------------------------------------
398 bool wxQTMediaBackend::Play()
399 {
400 ::StartMovie(m_movie);
401 m_timer->SetPaused(false);
402 m_timer->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
403 return ::GetMoviesError() == noErr;
404 }
405
406 //---------------------------------------------------------------------------
407 // wxQTMediaBackend::Pause
408 //
409 // TODO
410 //---------------------------------------------------------------------------
411 bool wxQTMediaBackend::Pause()
412 {
413 ::StopMovie(m_movie);
414 m_timer->SetPaused(true);
415 m_timer->Stop();
416 return ::GetMoviesError() == noErr;
417 }
418
419 //---------------------------------------------------------------------------
420 // wxQTMediaBackend::Stop
421 //
422 // TODO
423 //---------------------------------------------------------------------------
424 bool wxQTMediaBackend::Stop()
425 {
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
437 //---------------------------------------------------------------------------
438 // wxQTMediaBackend::GetPlaybackRate
439 //
440 // TODO
441 //---------------------------------------------------------------------------
442 double wxQTMediaBackend::GetPlaybackRate()
443 {
444 return ( ((double)::GetMovieRate(m_movie)) / 0x10000);
445 }
446
447 //---------------------------------------------------------------------------
448 // wxQTMediaBackend::SetPlaybackRate
449 //
450 // TODO
451 //---------------------------------------------------------------------------
452 bool wxQTMediaBackend::SetPlaybackRate(double dRate)
453 {
454 ::SetMovieRate(m_movie, (Fixed) (dRate * 0x10000));
455 return ::GetMoviesError() == noErr;
456 }
457
458 //---------------------------------------------------------------------------
459 // wxQTMediaBackend::SetPosition
460 //
461 // TODO
462 //---------------------------------------------------------------------------
463 bool wxQTMediaBackend::SetPosition(wxLongLong where)
464 {
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);
471
472 if (::GetMoviesError() != noErr)
473 return false;
474
475 return true;
476 }
477
478 //---------------------------------------------------------------------------
479 // wxQTMediaBackend::GetPosition
480 //
481 // TODO
482 //---------------------------------------------------------------------------
483 wxLongLong wxQTMediaBackend::GetPosition()
484 {
485 return ::GetMovieTime(m_movie, NULL);
486 }
487
488 //---------------------------------------------------------------------------
489 // wxQTMediaBackend::GetDuration
490 //
491 // TODO
492 //---------------------------------------------------------------------------
493 wxLongLong wxQTMediaBackend::GetDuration()
494 {
495 return ::GetMovieDuration(m_movie);
496 }
497
498 //---------------------------------------------------------------------------
499 // wxQTMediaBackend::GetState
500 //
501 // TODO
502 //---------------------------------------------------------------------------
503 wxMediaState wxQTMediaBackend::GetState()
504 {
505 if ( !m_timer || (m_timer->IsRunning() == false &&
506 m_timer->GetPaused() == false) )
507 return wxMEDIASTATE_STOPPED;
508
509 if( m_timer->IsRunning() == true )
510 return wxMEDIASTATE_PLAYING;
511 else
512 return wxMEDIASTATE_PAUSED;
513 }
514
515 //---------------------------------------------------------------------------
516 // wxQTMediaBackend::Cleanup
517 //
518 // TODO
519 //---------------------------------------------------------------------------
520 void wxQTMediaBackend::Cleanup()
521 {
522 delete m_timer;
523 m_timer = NULL;
524
525 StopMovie(m_movie);
526 DisposeMovie(m_movie);
527 }
528
529 //---------------------------------------------------------------------------
530 // wxQTMediaBackend::GetVideoSize
531 //
532 // TODO
533 //---------------------------------------------------------------------------
534 wxSize wxQTMediaBackend::GetVideoSize() const
535 {
536 return m_bestSize;
537 }
538
539 //---------------------------------------------------------------------------
540 // wxQTMediaBackend::Move
541 //
542 // TODO
543 //---------------------------------------------------------------------------
544 void wxQTMediaBackend::Move(int x, int y, int w, int h)
545 {
546 if(m_timer)
547 {
548 if ( m_ctrl )
549 {
550 m_ctrl->GetParent()->MacWindowToRootWindow(&x, &y);
551 }
552
553 Rect theRect = {y, x, y+h, x+w};
554
555 ::SetMovieBox(m_movie, &theRect);
556 wxASSERT(::GetMoviesError() == noErr);
557 }
558 }
559
560
561 //in source file that contains stuff you don't directly use
562 #include <wx/html/forcelnk.h>
563 FORCE_LINK_ME(basewxmediabackends);
564
565 #endif //wxUSE_MEDIACTRL
566
567
568
569
570