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