]>
Commit | Line | Data |
---|---|---|
1 | ///////////////////////////////////////////////////////////////////////////// | |
2 | // Name: src/cocoa/mediactrl.cpp | |
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 | #include "wx/osx/private.h" | |
38 | ||
39 | //=========================================================================== | |
40 | // BACKEND DECLARATIONS | |
41 | //=========================================================================== | |
42 | ||
43 | //--------------------------------------------------------------------------- | |
44 | // | |
45 | // wxQTMediaBackend | |
46 | // | |
47 | //--------------------------------------------------------------------------- | |
48 | ||
49 | //--------------------------------------------------------------------------- | |
50 | // QT Includes | |
51 | //--------------------------------------------------------------------------- | |
52 | #include <QTKit/QTKit.h> | |
53 | ||
54 | #include "wx/cocoa/autorelease.h" | |
55 | #include "wx/cocoa/string.h" | |
56 | ||
57 | class WXDLLIMPEXP_FWD_MEDIA wxQTMediaBackend; | |
58 | ||
59 | @interface wxQTMovie : QTMovie { | |
60 | ||
61 | wxQTMediaBackend* m_backend; | |
62 | } | |
63 | ||
64 | -(BOOL)isPlaying; | |
65 | ||
66 | @end | |
67 | ||
68 | class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackendCommonBase | |
69 | { | |
70 | public: | |
71 | ||
72 | wxQTMediaBackend(); | |
73 | ~wxQTMediaBackend(); | |
74 | ||
75 | virtual bool CreateControl(wxControl* ctrl, wxWindow* parent, | |
76 | wxWindowID id, | |
77 | const wxPoint& pos, | |
78 | const wxSize& size, | |
79 | long style, | |
80 | const wxValidator& validator, | |
81 | const wxString& name); | |
82 | ||
83 | virtual bool Play(); | |
84 | virtual bool Pause(); | |
85 | virtual bool Stop(); | |
86 | ||
87 | virtual bool Load(const wxString& fileName); | |
88 | virtual bool Load(const wxURI& location); | |
89 | ||
90 | virtual wxMediaState GetState(); | |
91 | ||
92 | virtual bool SetPosition(wxLongLong where); | |
93 | virtual wxLongLong GetPosition(); | |
94 | virtual wxLongLong GetDuration(); | |
95 | ||
96 | virtual void Move(int x, int y, int w, int h); | |
97 | wxSize GetVideoSize() const; | |
98 | ||
99 | virtual double GetPlaybackRate(); | |
100 | virtual bool SetPlaybackRate(double dRate); | |
101 | ||
102 | virtual double GetVolume(); | |
103 | virtual bool SetVolume(double dVolume); | |
104 | ||
105 | void Cleanup(); | |
106 | void FinishLoad(); | |
107 | ||
108 | virtual bool ShowPlayerControls(wxMediaCtrlPlayerControls flags); | |
109 | private: | |
110 | void DoShowPlayerControls(wxMediaCtrlPlayerControls flags); | |
111 | ||
112 | wxSize m_bestSize; //Original movie size | |
113 | wxQTMovie* m_movie; //QTMovie handle/instance | |
114 | QTMovieView* m_movieview; //QTMovieView instance | |
115 | ||
116 | wxMediaCtrlPlayerControls m_interfaceflags; // Saved interface flags | |
117 | ||
118 | DECLARE_DYNAMIC_CLASS(wxQTMediaBackend); | |
119 | }; | |
120 | ||
121 | // -------------------------------------------------------------------------- | |
122 | // wxQTMovie | |
123 | // -------------------------------------------------------------------------- | |
124 | ||
125 | @implementation wxQTMovie | |
126 | ||
127 | - (id)initWithURL:(NSURL *)url error:(NSError **)errorPtr | |
128 | { | |
129 | if ( [super initWithURL:url error:errorPtr] != nil ) | |
130 | { | |
131 | m_backend = NULL; | |
132 | ||
133 | NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; | |
134 | [nc addObserver:self selector:@selector(movieDidEnd:) | |
135 | name:QTMovieDidEndNotification object:nil]; | |
136 | [nc addObserver:self selector:@selector(movieRateChanged:) | |
137 | name:QTMovieRateDidChangeNotification object:nil]; | |
138 | [nc addObserver:self selector:@selector(loadStateChanged:) | |
139 | name:QTMovieLoadStateDidChangeNotification object:nil]; | |
140 | ||
141 | return self; | |
142 | } | |
143 | else | |
144 | return nil; | |
145 | } | |
146 | ||
147 | -(void)dealloc | |
148 | { | |
149 | NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; | |
150 | [nc removeObserver:self]; | |
151 | ||
152 | [super dealloc]; | |
153 | } | |
154 | ||
155 | -(wxQTMediaBackend*) backend; | |
156 | { | |
157 | return m_backend; | |
158 | } | |
159 | ||
160 | -(void) setBackend:(wxQTMediaBackend*) backend | |
161 | { | |
162 | m_backend = backend; | |
163 | } | |
164 | ||
165 | - (void)movieDidEnd:(NSNotification *)notification | |
166 | { | |
167 | if ( m_backend ) | |
168 | { | |
169 | if ( m_backend->SendStopEvent() ) | |
170 | m_backend->QueueFinishEvent(); | |
171 | } | |
172 | } | |
173 | ||
174 | - (void)movieRateChanged:(NSNotification *)notification | |
175 | { | |
176 | NSDictionary *userInfo = [notification userInfo]; | |
177 | ||
178 | NSNumber *newRate = [userInfo objectForKey:QTMovieRateDidChangeNotificationParameter]; | |
179 | ||
180 | if ([newRate intValue] == 0) | |
181 | { | |
182 | m_backend->QueuePauseEvent(); | |
183 | } | |
184 | else if ( [self isPlaying] == NO ) | |
185 | { | |
186 | m_backend->QueuePlayEvent(); | |
187 | } | |
188 | } | |
189 | ||
190 | -(void)loadStateChanged:(NSNotification *)notification | |
191 | { | |
192 | QTMovie *movie = [notification object]; | |
193 | long loadState = [[movie attributeForKey:QTMovieLoadStateAttribute] longValue]; | |
194 | if ( loadState == QTMovieLoadStateError ) | |
195 | { | |
196 | // error occurred | |
197 | } | |
198 | else if (loadState >= QTMovieLoadStatePlayable) | |
199 | { | |
200 | // the movie has loaded enough media data to begin playing, but we don't have an event for that yet | |
201 | } | |
202 | else if (loadState >= QTMovieLoadStateComplete) // we might use QTMovieLoadStatePlaythroughOK | |
203 | { | |
204 | m_backend->FinishLoad(); | |
205 | } | |
206 | } | |
207 | ||
208 | -(BOOL)isPlaying | |
209 | { | |
210 | if ([self rate] == 0) | |
211 | { | |
212 | return NO; | |
213 | } | |
214 | ||
215 | return YES; | |
216 | } | |
217 | ||
218 | @end | |
219 | ||
220 | // -------------------------------------------------------------------------- | |
221 | // wxQTMediaBackend | |
222 | // -------------------------------------------------------------------------- | |
223 | ||
224 | IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend); | |
225 | ||
226 | wxQTMediaBackend::wxQTMediaBackend() : | |
227 | m_movie(nil), m_movieview(nil), | |
228 | m_interfaceflags(wxMEDIACTRLPLAYERCONTROLS_NONE) | |
229 | { | |
230 | } | |
231 | ||
232 | wxQTMediaBackend::~wxQTMediaBackend() | |
233 | { | |
234 | Cleanup(); | |
235 | } | |
236 | ||
237 | bool wxQTMediaBackend::CreateControl(wxControl* inctrl, wxWindow* parent, | |
238 | wxWindowID wid, | |
239 | const wxPoint& pos, | |
240 | const wxSize& size, | |
241 | long style, | |
242 | const wxValidator& validator, | |
243 | const wxString& name) | |
244 | { | |
245 | wxMediaCtrl* mediactrl = (wxMediaCtrl*) inctrl; | |
246 | ||
247 | mediactrl->DontCreatePeer(); | |
248 | ||
249 | if ( !mediactrl->wxControl::Create( | |
250 | parent, wid, pos, size, | |
251 | wxWindow::MacRemoveBordersFromStyle(style), | |
252 | validator, name)) | |
253 | { | |
254 | return false; | |
255 | } | |
256 | ||
257 | NSRect r = wxOSXGetFrameForControl( mediactrl, pos , size ) ; | |
258 | QTMovieView* theView = [[QTMovieView alloc] initWithFrame: r]; | |
259 | ||
260 | wxWidgetCocoaImpl* impl = new wxWidgetCocoaImpl(mediactrl,theView); | |
261 | mediactrl->SetPeer(impl); | |
262 | ||
263 | m_movieview = theView; | |
264 | // will be set up after load | |
265 | [theView setControllerVisible:NO]; | |
266 | ||
267 | m_ctrl = mediactrl; | |
268 | return true; | |
269 | } | |
270 | ||
271 | bool wxQTMediaBackend::Load(const wxString& fileName) | |
272 | { | |
273 | return Load( | |
274 | wxURI( | |
275 | wxString( wxT("file://") ) + fileName | |
276 | ) | |
277 | ); | |
278 | } | |
279 | ||
280 | bool wxQTMediaBackend::Load(const wxURI& location) | |
281 | { | |
282 | wxCFStringRef uri(location.BuildURI()); | |
283 | NSURL *url = [NSURL URLWithString: uri.AsNSString()]; | |
284 | ||
285 | if (! [wxQTMovie canInitWithURL:url]) | |
286 | return false; | |
287 | ||
288 | [m_movie release]; | |
289 | wxQTMovie* movie = [[wxQTMovie alloc] initWithURL:url error: nil ]; | |
290 | ||
291 | m_movie = movie; | |
292 | if (movie != nil) | |
293 | { | |
294 | [m_movie setBackend:this]; | |
295 | [m_movieview setMovie:movie]; | |
296 | ||
297 | // If the media file is able to be loaded quickly then there may not be | |
298 | // any QTMovieLoadStateDidChangeNotification message sent, so we need to | |
299 | // also check the load state here and finish our initialization if it has | |
300 | // been loaded. | |
301 | long loadState = [[m_movie attributeForKey:QTMovieLoadStateAttribute] longValue]; | |
302 | if (loadState >= QTMovieLoadStateComplete) | |
303 | { | |
304 | FinishLoad(); | |
305 | } | |
306 | } | |
307 | ||
308 | return movie != nil; | |
309 | } | |
310 | ||
311 | void wxQTMediaBackend::FinishLoad() | |
312 | { | |
313 | DoShowPlayerControls(m_interfaceflags); | |
314 | ||
315 | NSSize s = [[m_movie attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]; | |
316 | m_bestSize = wxSize(s.width, s.height); | |
317 | ||
318 | NotifyMovieLoaded(); | |
319 | } | |
320 | ||
321 | bool wxQTMediaBackend::Play() | |
322 | { | |
323 | [m_movieview play:nil]; | |
324 | return true; | |
325 | } | |
326 | ||
327 | bool wxQTMediaBackend::Pause() | |
328 | { | |
329 | [m_movieview pause:nil]; | |
330 | return true; | |
331 | } | |
332 | ||
333 | bool wxQTMediaBackend::Stop() | |
334 | { | |
335 | [m_movieview pause:nil]; | |
336 | [m_movieview gotoBeginning:nil]; | |
337 | return true; | |
338 | } | |
339 | ||
340 | double wxQTMediaBackend::GetVolume() | |
341 | { | |
342 | return [m_movie volume]; | |
343 | } | |
344 | ||
345 | bool wxQTMediaBackend::SetVolume(double dVolume) | |
346 | { | |
347 | [m_movie setVolume:dVolume]; | |
348 | return true; | |
349 | } | |
350 | double wxQTMediaBackend::GetPlaybackRate() | |
351 | { | |
352 | return [m_movie rate]; | |
353 | } | |
354 | ||
355 | bool wxQTMediaBackend::SetPlaybackRate(double dRate) | |
356 | { | |
357 | [m_movie setRate:dRate]; | |
358 | return true; | |
359 | } | |
360 | ||
361 | bool wxQTMediaBackend::SetPosition(wxLongLong where) | |
362 | { | |
363 | QTTime position; | |
364 | position = [m_movie currentTime]; | |
365 | position.timeValue = (where.GetValue() / 1000.0) * position.timeScale; | |
366 | [m_movie setCurrentTime:position]; | |
367 | return true; | |
368 | } | |
369 | ||
370 | wxLongLong wxQTMediaBackend::GetPosition() | |
371 | { | |
372 | QTTime position = [m_movie currentTime]; | |
373 | return ((double) position.timeValue) / position.timeScale * 1000; | |
374 | } | |
375 | ||
376 | wxLongLong wxQTMediaBackend::GetDuration() | |
377 | { | |
378 | QTTime duration = [m_movie duration]; | |
379 | return ((double) duration.timeValue) / duration.timeScale * 1000; | |
380 | } | |
381 | ||
382 | wxMediaState wxQTMediaBackend::GetState() | |
383 | { | |
384 | if ( [m_movie isPlaying] ) | |
385 | return wxMEDIASTATE_PLAYING; | |
386 | else | |
387 | { | |
388 | if ( GetPosition() == 0 ) | |
389 | return wxMEDIASTATE_STOPPED; | |
390 | else | |
391 | return wxMEDIASTATE_PAUSED; | |
392 | } | |
393 | } | |
394 | ||
395 | void wxQTMediaBackend::Cleanup() | |
396 | { | |
397 | [m_movieview setMovie:NULL]; | |
398 | [m_movie release]; | |
399 | m_movie = nil; | |
400 | } | |
401 | ||
402 | wxSize wxQTMediaBackend::GetVideoSize() const | |
403 | { | |
404 | return m_bestSize; | |
405 | } | |
406 | ||
407 | void wxQTMediaBackend::Move(int x, int y, int w, int h) | |
408 | { | |
409 | // as we have a native player, no need to move the video area | |
410 | } | |
411 | ||
412 | bool wxQTMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags) | |
413 | { | |
414 | if ( m_interfaceflags != flags ) | |
415 | DoShowPlayerControls(flags); | |
416 | ||
417 | m_interfaceflags = flags; | |
418 | return true; | |
419 | } | |
420 | ||
421 | void wxQTMediaBackend::DoShowPlayerControls(wxMediaCtrlPlayerControls flags) | |
422 | { | |
423 | if (flags == wxMEDIACTRLPLAYERCONTROLS_NONE ) | |
424 | { | |
425 | [m_movieview setControllerVisible:NO]; | |
426 | } | |
427 | else | |
428 | { | |
429 | [m_movieview setControllerVisible:YES]; | |
430 | ||
431 | [m_movieview setStepButtonsVisible:(flags & wxMEDIACTRLPLAYERCONTROLS_STEP) ? YES:NO]; | |
432 | [m_movieview setVolumeButtonVisible:(flags & wxMEDIACTRLPLAYERCONTROLS_VOLUME) ? YES:NO]; | |
433 | } | |
434 | } | |
435 | ||
436 | //in source file that contains stuff you don't directly use | |
437 | #include "wx/html/forcelnk.h" | |
438 | FORCE_LINK_ME(basewxmediabackends); | |
439 | ||
440 | #endif //wxUSE_MEDIACTRL |