1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/cocoa/mediactrl.cpp
3 // Purpose: Built-in Media Backends for Cocoa
4 // Author: Ryan Norton <wxprojects@comcast.net>
7 // Copyright: (c) 2004-2005 Ryan Norton, (c) 2005 David Elliot
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 //===========================================================================
13 //===========================================================================
15 //---------------------------------------------------------------------------
16 // Pre-compiled header stuff
17 //---------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
26 //---------------------------------------------------------------------------
28 //---------------------------------------------------------------------------
31 #include "wx/mediactrl.h"
37 #include "wx/osx/private.h"
39 //===========================================================================
40 // BACKEND DECLARATIONS
41 //===========================================================================
43 //---------------------------------------------------------------------------
47 //---------------------------------------------------------------------------
49 //---------------------------------------------------------------------------
51 //---------------------------------------------------------------------------
52 #include <QTKit/QTKit.h>
54 #include "wx/cocoa/autorelease.h"
55 #include "wx/cocoa/string.h"
57 class WXDLLIMPEXP_FWD_MEDIA wxQTMediaBackend;
59 @interface wxQTMovie : QTMovie {
61 wxQTMediaBackend* m_backend;
68 class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackendCommonBase
75 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
80 const wxValidator& validator,
81 const wxString& name);
87 virtual bool Load(const wxString& fileName);
88 virtual bool Load(const wxURI& location);
90 virtual wxMediaState GetState();
92 virtual bool SetPosition(wxLongLong where);
93 virtual wxLongLong GetPosition();
94 virtual wxLongLong GetDuration();
96 virtual void Move(int x, int y, int w, int h);
97 wxSize GetVideoSize() const;
99 virtual double GetPlaybackRate();
100 virtual bool SetPlaybackRate(double dRate);
102 virtual double GetVolume();
103 virtual bool SetVolume(double dVolume);
108 virtual bool ShowPlayerControls(wxMediaCtrlPlayerControls flags);
110 void DoShowPlayerControls(wxMediaCtrlPlayerControls flags);
112 wxSize m_bestSize; //Original movie size
113 wxQTMovie* m_movie; //QTMovie handle/instance
114 QTMovieView* m_movieview; //QTMovieView instance
116 wxMediaCtrlPlayerControls m_interfaceflags; // Saved interface flags
118 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend);
121 // --------------------------------------------------------------------------
123 // --------------------------------------------------------------------------
125 @implementation wxQTMovie
127 - (id)initWithURL:(NSURL *)url error:(NSError **)errorPtr
129 if ( [super initWithURL:url error:errorPtr] != nil )
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];
149 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
150 [nc removeObserver:self];
155 -(wxQTMediaBackend*) backend;
160 -(void) setBackend:(wxQTMediaBackend*) backend
165 - (void)movieDidEnd:(NSNotification *)notification
169 if ( m_backend->SendStopEvent() )
170 m_backend->QueueFinishEvent();
174 - (void)movieRateChanged:(NSNotification *)notification
176 NSDictionary *userInfo = [notification userInfo];
178 NSNumber *newRate = [userInfo objectForKey:QTMovieRateDidChangeNotificationParameter];
180 if ([newRate intValue] == 0)
182 m_backend->QueuePauseEvent();
184 else if ( [self isPlaying] == NO )
186 m_backend->QueuePlayEvent();
190 -(void)loadStateChanged:(NSNotification *)notification
192 QTMovie *movie = [notification object];
193 long loadState = [[movie attributeForKey:QTMovieLoadStateAttribute] longValue];
194 if ( loadState == QTMovieLoadStateError )
198 else if (loadState >= QTMovieLoadStatePlayable)
200 // the movie has loaded enough media data to begin playing, but we don't have an event for that yet
202 else if (loadState >= QTMovieLoadStateComplete) // we might use QTMovieLoadStatePlaythroughOK
204 m_backend->FinishLoad();
210 if ([self rate] == 0)
220 // --------------------------------------------------------------------------
222 // --------------------------------------------------------------------------
224 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
226 wxQTMediaBackend::wxQTMediaBackend() :
227 m_movie(nil), m_movieview(nil),
228 m_interfaceflags(wxMEDIACTRLPLAYERCONTROLS_NONE)
232 wxQTMediaBackend::~wxQTMediaBackend()
237 bool wxQTMediaBackend::CreateControl(wxControl* inctrl, wxWindow* parent,
242 const wxValidator& validator,
243 const wxString& name)
245 wxMediaCtrl* mediactrl = (wxMediaCtrl*) inctrl;
247 mediactrl->DontCreatePeer();
249 if ( !mediactrl->wxControl::Create(
250 parent, wid, pos, size,
251 wxWindow::MacRemoveBordersFromStyle(style),
257 NSRect r = wxOSXGetFrameForControl( mediactrl, pos , size ) ;
258 QTMovieView* theView = [[QTMovieView alloc] initWithFrame: r];
260 wxWidgetCocoaImpl* impl = new wxWidgetCocoaImpl(mediactrl,theView);
261 mediactrl->SetPeer(impl);
263 m_movieview = theView;
264 // will be set up after load
265 [theView setControllerVisible:NO];
271 bool wxQTMediaBackend::Load(const wxString& fileName)
275 wxString( wxT("file://") ) + fileName
280 bool wxQTMediaBackend::Load(const wxURI& location)
282 wxCFStringRef uri(location.BuildURI());
283 NSURL *url = [NSURL URLWithString: uri.AsNSString()];
285 if (! [wxQTMovie canInitWithURL:url])
289 wxQTMovie* movie = [[wxQTMovie alloc] initWithURL:url error: nil ];
294 [m_movie setBackend:this];
295 [m_movieview setMovie:movie];
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
301 long loadState = [[m_movie attributeForKey:QTMovieLoadStateAttribute] longValue];
302 if (loadState >= QTMovieLoadStateComplete)
311 void wxQTMediaBackend::FinishLoad()
313 DoShowPlayerControls(m_interfaceflags);
315 NSSize s = [[m_movie attributeForKey:QTMovieNaturalSizeAttribute] sizeValue];
316 m_bestSize = wxSize(s.width, s.height);
321 bool wxQTMediaBackend::Play()
323 [m_movieview play:nil];
327 bool wxQTMediaBackend::Pause()
329 [m_movieview pause:nil];
333 bool wxQTMediaBackend::Stop()
335 [m_movieview pause:nil];
336 [m_movieview gotoBeginning:nil];
340 double wxQTMediaBackend::GetVolume()
342 return [m_movie volume];
345 bool wxQTMediaBackend::SetVolume(double dVolume)
347 [m_movie setVolume:dVolume];
350 double wxQTMediaBackend::GetPlaybackRate()
352 return [m_movie rate];
355 bool wxQTMediaBackend::SetPlaybackRate(double dRate)
357 [m_movie setRate:dRate];
361 bool wxQTMediaBackend::SetPosition(wxLongLong where)
364 position = [m_movie currentTime];
365 position.timeValue = (where.GetValue() / 1000.0) * position.timeScale;
366 [m_movie setCurrentTime:position];
370 wxLongLong wxQTMediaBackend::GetPosition()
372 QTTime position = [m_movie currentTime];
373 return ((double) position.timeValue) / position.timeScale * 1000;
376 wxLongLong wxQTMediaBackend::GetDuration()
378 QTTime duration = [m_movie duration];
379 return ((double) duration.timeValue) / duration.timeScale * 1000;
382 wxMediaState wxQTMediaBackend::GetState()
384 if ( [m_movie isPlaying] )
385 return wxMEDIASTATE_PLAYING;
388 if ( GetPosition() == 0 )
389 return wxMEDIASTATE_STOPPED;
391 return wxMEDIASTATE_PAUSED;
395 void wxQTMediaBackend::Cleanup()
397 [m_movieview setMovie:NULL];
402 wxSize wxQTMediaBackend::GetVideoSize() const
407 void wxQTMediaBackend::Move(int x, int y, int w, int h)
409 // as we have a native player, no need to move the video area
412 bool wxQTMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags)
414 if ( m_interfaceflags != flags )
415 DoShowPlayerControls(flags);
417 m_interfaceflags = flags;
421 void wxQTMediaBackend::DoShowPlayerControls(wxMediaCtrlPlayerControls flags)
423 if (flags == wxMEDIACTRLPLAYERCONTROLS_NONE )
425 [m_movieview setControllerVisible:NO];
429 [m_movieview setControllerVisible:YES];
431 [m_movieview setStepButtonsVisible:(flags & wxMEDIACTRLPLAYERCONTROLS_STEP) ? YES:NO];
432 [m_movieview setVolumeButtonVisible:(flags & wxMEDIACTRLPLAYERCONTROLS_VOLUME) ? YES:NO];
436 //in source file that contains stuff you don't directly use
437 #include "wx/html/forcelnk.h"
438 FORCE_LINK_ME(basewxmediabackends);
440 #endif //wxUSE_MEDIACTRL