Document domain parameter of wxTranslations::GetTranslatedString().
[wxWidgets.git] / src / cocoa / mediactrl.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/cocoa/mediactrl.mm
3 // Purpose:     Built-in Media Backends for Cocoa
4 // Author:      Ryan Norton <wxprojects@comcast.net>
5 // Modified by:
6 // Created:     02/03/05
7 // Copyright:   (c) 2004-2005 Ryan Norton, (c) 2005 David Elliot
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 //===========================================================================
12 //  DECLARATIONS
13 //===========================================================================
14
15 //---------------------------------------------------------------------------
16 // Pre-compiled header stuff
17 //---------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 //---------------------------------------------------------------------------
27 // Compilation guard
28 //---------------------------------------------------------------------------
29 #if wxUSE_MEDIACTRL
30
31 #include "wx/mediactrl.h"
32
33 #ifndef WX_PRECOMP
34     #include "wx/timer.h"
35 #endif
36
37 //===========================================================================
38 //  BACKEND DECLARATIONS
39 //===========================================================================
40
41 //---------------------------------------------------------------------------
42 //
43 //  wxQTMediaBackend
44 //
45 //---------------------------------------------------------------------------
46
47 //---------------------------------------------------------------------------
48 //  QT Includes
49 //---------------------------------------------------------------------------
50 #include <QuickTime/QuickTime.h>
51
52 #include "wx/cocoa/autorelease.h"
53 #include "wx/cocoa/string.h"
54
55 #import <AppKit/NSMovie.h>
56 #import <AppKit/NSMovieView.h>
57
58
59 class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackend
60 {
61 public:
62
63     wxQTMediaBackend();
64     ~wxQTMediaBackend();
65
66     virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
67                                      wxWindowID id,
68                                      const wxPoint& pos,
69                                      const wxSize& size,
70                                      long style,
71                                      const wxValidator& validator,
72                                      const wxString& name);
73
74     virtual bool Play();
75     virtual bool Pause();
76     virtual bool Stop();
77
78     virtual bool Load(const wxString& fileName);
79     virtual bool Load(const wxURI& location);
80
81     virtual wxMediaState GetState();
82
83     virtual bool SetPosition(wxLongLong where);
84     virtual wxLongLong GetPosition();
85     virtual wxLongLong GetDuration();
86
87     virtual void Move(int x, int y, int w, int h);
88     wxSize GetVideoSize() const;
89
90     virtual double GetPlaybackRate();
91     virtual bool SetPlaybackRate(double dRate);
92
93     void Cleanup();
94     void FinishLoad();
95
96     wxSize m_bestSize;              //Original movie size
97     Movie m_movie;                  //QT Movie handle/instance
98     NSMovieView* m_movieview;       //NSMovieView instance
99     wxControl* m_ctrl;              //Parent control
100     bool m_bVideo;                  //Whether or not we have video
101     class _wxQTTimer* m_timer;      //Timer for streaming the movie
102
103     DECLARE_DYNAMIC_CLASS(wxQTMediaBackend);
104 };
105
106
107 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
108 //
109 // wxQTMediaBackend
110 //
111 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
112
113 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
114
115 //Time between timer calls
116 #define MOVIE_DELAY 100
117
118 // --------------------------------------------------------------------------
119 //          wxQTTimer - Handle Asyncronous Playing
120 // --------------------------------------------------------------------------
121 class _wxQTTimer : public wxTimer
122 {
123 public:
124     _wxQTTimer(Movie movie, wxQTMediaBackend* parent) :
125         m_movie(movie), m_bPaused(false), m_parent(parent)
126     {
127     }
128
129     ~_wxQTTimer()
130     {
131     }
132
133     bool GetPaused() {return m_bPaused;}
134     void SetPaused(bool bPaused) {m_bPaused = bPaused;}
135
136     //-----------------------------------------------------------------------
137     // _wxQTTimer::Notify
138     //
139     // 1) Checks to see if the movie is done, and if not continues
140     //    streaming the movie
141     // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
142     //    the movie.
143     //-----------------------------------------------------------------------
144     void Notify()
145     {
146         if (!m_bPaused)
147         {
148             if(!IsMovieDone(m_movie))
149                 MoviesTask(m_movie, MOVIE_DELAY);
150             else
151             {
152                 wxMediaEvent theEvent(wxEVT_MEDIA_STOP,
153                                       m_parent->m_ctrl->GetId());
154                 m_parent->m_ctrl->ProcessEvent(theEvent);
155
156                 if(theEvent.IsAllowed())
157                 {
158                     Stop();
159                     m_parent->Stop();
160                     wxASSERT(::GetMoviesError() == noErr);
161
162                     //send the event to our child
163                     wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
164                                           m_parent->m_ctrl->GetId());
165                     m_parent->m_ctrl->ProcessEvent(theEvent);
166                 }
167             }
168         }
169     }
170
171 protected:
172     Movie m_movie;                  //Our movie instance
173     bool m_bPaused;                 //Whether we are paused or not
174     wxQTMediaBackend* m_parent;     //Backend pointer
175 };
176
177 //---------------------------------------------------------------------------
178 // wxQTMediaBackend Constructor
179 //
180 // Sets m_timer to NULL signifying we havn't loaded anything yet
181 //---------------------------------------------------------------------------
182 wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL)
183 {
184 }
185
186 //---------------------------------------------------------------------------
187 // wxQTMediaBackend Destructor
188 //
189 // 1) Cleans up the QuickTime movie instance
190 // 2) Decrements the QuickTime reference counter - if this reaches
191 //    0, QuickTime shuts down
192 // 3) Decrements the QuickTime Windows Media Layer reference counter -
193 //    if this reaches 0, QuickTime shuts down the Windows Media Layer
194 //---------------------------------------------------------------------------
195 wxQTMediaBackend::~wxQTMediaBackend()
196 {
197     if(m_timer)
198         Cleanup();
199
200     //Note that ExitMovies() is not necessary...
201     ExitMovies();
202 }
203
204 //---------------------------------------------------------------------------
205 // wxQTMediaBackend::CreateControl
206 //
207 // 1) Intializes QuickTime
208 // 2) Creates the control window
209 //---------------------------------------------------------------------------
210 bool wxQTMediaBackend::CreateControl(wxControl* inctrl, wxWindow* parent,
211                                      wxWindowID wid,
212                                      const wxPoint& pos,
213                                      const wxSize& size,
214                                      long style,
215                                      const wxValidator& validator,
216                                      const wxString& name)
217 {
218     EnterMovies();
219
220     wxMediaCtrl* ctrl = (wxMediaCtrl*) inctrl;
221
222     //Create the control base
223     wxASSERT(ctrl->CreateBase(parent,wid,pos,size,style, validator, name));
224
225     //Create the NSMovieView
226     ctrl->SetNSView(NULL);
227     NSMovieView* theView = [[NSMovieView alloc] initWithFrame: ctrl->MakeDefaultNSRect(size)];
228     ctrl->SetNSView(theView);
229     [theView release];
230
231     if (parent)
232     {
233         parent->AddChild(ctrl);
234         parent->CocoaAddChild(ctrl);
235         ctrl->SetInitialFrameRect(pos,size);
236     }
237
238     [theView showController:false adjustingSize:true];
239     m_movieview = theView;
240     m_ctrl = ctrl;
241     return true;
242 }
243
244 //---------------------------------------------------------------------------
245 // wxQTMediaBackend::Load (file version)
246 //
247 // Calls the URI version
248 //---------------------------------------------------------------------------
249 bool wxQTMediaBackend::Load(const wxString& fileName)
250 {
251     return Load(
252                 wxURI(
253                     wxString( wxT("file://") ) + fileName
254                      )
255                );
256 }
257
258 //---------------------------------------------------------------------------
259 // wxQTMediaBackend::Load (URL Version)
260 //
261 // 1) Build an escaped URI from location
262 // ...
263 //---------------------------------------------------------------------------
264 bool wxQTMediaBackend::Load(const wxURI& location)
265 {
266     if(m_timer)
267         Cleanup();
268
269     wxString theURI = location.BuildURI();
270
271     [m_movieview setMovie:[[NSMovie alloc] initWithURL: [NSURL URLWithString: wxNSStringWithWxString(theURI)]
272                                byReference: YES ] ];
273
274     m_movie = (Movie) [[m_movieview movie] QTMovie];
275
276     //preroll movie for streaming
277     //TODO:Async this using threads?
278     TimeValue timeNow;
279     Fixed playRate;
280     timeNow = GetMovieTime(m_movie, NULL);
281     playRate = GetMoviePreferredRate(m_movie);
282     PrePrerollMovie(m_movie, timeNow, playRate, NULL, NULL);
283     PrerollMovie(m_movie, timeNow, playRate);
284     SetMovieRate(m_movie, playRate);
285
286     FinishLoad();
287
288     return ::GetMoviesError() == noErr;
289 }
290
291 //---------------------------------------------------------------------------
292 // wxQTMediaBackend::FinishLoad
293 //
294 // 1) Create the movie timer
295 // 2) Get real size of movie for GetBestSize/sizers
296 // 3) See if there is video in the movie, and if so then either
297 //    SetMovieGWorld if < 10.2 or use Native CreateMovieControl
298 // 4) Set the movie time scale to something usable so that seeking
299 //    etc.  will work correctly
300 // 5) Refresh parent window
301 //---------------------------------------------------------------------------
302 void wxQTMediaBackend::FinishLoad()
303 {
304     m_timer = new _wxQTTimer(m_movie, (wxQTMediaBackend*) this);
305     wxASSERT(m_timer);
306
307     //get the real size of the movie
308     Rect outRect;
309     ::GetMovieNaturalBoundsRect (m_movie, &outRect);
310     wxASSERT(::GetMoviesError() == noErr);
311
312     m_bestSize.x = outRect.right - outRect.left;
313     m_bestSize.y = outRect.bottom - outRect.top;
314
315     //we want millisecond precision
316     ::SetMovieTimeScale(m_movie, 1000);
317     wxASSERT(::GetMoviesError() == noErr);
318
319     //
320     //Here, if the parent of the control has a sizer - we
321     //tell it to recalculate the size of this control since
322     //the user opened a separate media file
323     //
324     m_ctrl->InvalidateBestSize();
325     m_ctrl->GetParent()->Layout();
326     m_ctrl->GetParent()->Refresh();
327     m_ctrl->GetParent()->Update();
328 }
329
330 //---------------------------------------------------------------------------
331 // wxQTMediaBackend::Play
332 //
333 // 1) Start the QT movie
334 // 2) Start the movie loading timer
335 //---------------------------------------------------------------------------
336 bool wxQTMediaBackend::Play()
337 {
338     ::StartMovie(m_movie);
339     m_timer->SetPaused(false);
340     m_timer->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
341     return ::GetMoviesError() == noErr;
342 }
343
344 //---------------------------------------------------------------------------
345 // wxQTMediaBackend::Pause
346 //
347 // 1) Stop the movie
348 // 2) Stop the movie timer
349 //---------------------------------------------------------------------------
350 bool wxQTMediaBackend::Pause()
351 {
352     ::StopMovie(m_movie);
353     m_timer->SetPaused(true);
354     m_timer->Stop();
355     return ::GetMoviesError() == noErr;
356 }
357
358 //---------------------------------------------------------------------------
359 // wxQTMediaBackend::Stop
360 //
361 // 1) Stop the movie
362 // 2) Stop the movie timer
363 // 3) Seek to the beginning of the movie
364 //---------------------------------------------------------------------------
365 bool wxQTMediaBackend::Stop()
366 {
367     m_timer->SetPaused(false);
368     m_timer->Stop();
369
370     ::StopMovie(m_movie);
371     if(::GetMoviesError() != noErr)
372         return false;
373
374     ::GoToBeginningOfMovie(m_movie);
375     return ::GetMoviesError() == noErr;
376 }
377
378 //---------------------------------------------------------------------------
379 // wxQTMediaBackend::GetPlaybackRate
380 //
381 // 1) Get the movie playback rate from ::GetMovieRate
382 //---------------------------------------------------------------------------
383 double wxQTMediaBackend::GetPlaybackRate()
384 {
385     return ( ((double)::GetMovieRate(m_movie)) / 0x10000);
386 }
387
388 //---------------------------------------------------------------------------
389 // wxQTMediaBackend::SetPlaybackRate
390 //
391 // 1) Convert dRate to Fixed and Set the movie rate through SetMovieRate
392 //---------------------------------------------------------------------------
393 bool wxQTMediaBackend::SetPlaybackRate(double dRate)
394 {
395     ::SetMovieRate(m_movie, (Fixed) (dRate * 0x10000));
396     return ::GetMoviesError() == noErr;
397 }
398
399 //---------------------------------------------------------------------------
400 // wxQTMediaBackend::SetPosition
401 //
402 // 1) Create a time record struct (TimeRecord) with appropriate values
403 // 2) Pass struct to SetMovieTime
404 //---------------------------------------------------------------------------
405 bool wxQTMediaBackend::SetPosition(wxLongLong where)
406 {
407     TimeRecord theTimeRecord;
408     memset(&theTimeRecord, 0, sizeof(TimeRecord));
409     theTimeRecord.value.lo = where.GetValue();
410     theTimeRecord.scale = ::GetMovieTimeScale(m_movie);
411     theTimeRecord.base = ::GetMovieTimeBase(m_movie);
412     ::SetMovieTime(m_movie, &theTimeRecord);
413
414     if (::GetMoviesError() != noErr)
415         return false;
416
417     return true;
418 }
419
420 //---------------------------------------------------------------------------
421 // wxQTMediaBackend::GetPosition
422 //
423 // Calls GetMovieTime
424 //---------------------------------------------------------------------------
425 wxLongLong wxQTMediaBackend::GetPosition()
426 {
427     return ::GetMovieTime(m_movie, NULL);
428 }
429
430 //---------------------------------------------------------------------------
431 // wxQTMediaBackend::GetDuration
432 //
433 // Calls GetMovieDuration
434 //---------------------------------------------------------------------------
435 wxLongLong wxQTMediaBackend::GetDuration()
436 {
437     return ::GetMovieDuration(m_movie);
438 }
439
440 //---------------------------------------------------------------------------
441 // wxQTMediaBackend::GetState
442 //
443 // Determines the current state - the timer keeps track of whether or not
444 // we are paused or stopped (if the timer is running we are playing)
445 //---------------------------------------------------------------------------
446 wxMediaState wxQTMediaBackend::GetState()
447 {
448     if ( !m_timer || (m_timer->IsRunning() == false &&
449                       m_timer->GetPaused() == false) )
450         return wxMEDIASTATE_STOPPED;
451
452     if( m_timer->IsRunning() == true )
453         return wxMEDIASTATE_PLAYING;
454     else
455         return wxMEDIASTATE_PAUSED;
456 }
457
458 //---------------------------------------------------------------------------
459 // wxQTMediaBackend::Cleanup
460 //
461 // Diposes of the movie timer, Control if native, and stops and disposes
462 // of the QT movie
463 //---------------------------------------------------------------------------
464 void wxQTMediaBackend::Cleanup()
465 {
466     delete m_timer;
467     m_timer = NULL;
468
469     [[m_movieview movie] release];
470     [m_movieview setMovie:NULL];
471 }
472
473 //---------------------------------------------------------------------------
474 // wxQTMediaBackend::GetVideoSize
475 //
476 // Returns the actual size of the QT movie
477 //---------------------------------------------------------------------------
478 wxSize wxQTMediaBackend::GetVideoSize() const
479 {
480     return m_bestSize;
481 }
482
483 //---------------------------------------------------------------------------
484 // wxQTMediaBackend::Move
485 //
486 // Nothin... cocoa takes care of this for us
487 //---------------------------------------------------------------------------
488 void wxQTMediaBackend::Move(int x, int y, int w, int h)
489 {
490 }
491
492
493 //in source file that contains stuff you don't directly use
494 #include "wx/html/forcelnk.h"
495 FORCE_LINK_ME(basewxmediabackends);
496
497 #endif //wxUSE_MEDIACTRL