1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/cocoa/mediactrl.cpp
3 // Purpose: Built-in Media Backends for Cocoa
4 // Author: Ryan Norton <wxprojects@comcast.net>
7 // RCS-ID: $Id: mediactrl.mm 39285 2006-05-23 11:04:37Z ABX $
8 // Copyright: (c) 2004-2005 Ryan Norton, (c) 2005 David Elliot
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 //===========================================================================
14 //===========================================================================
16 //---------------------------------------------------------------------------
17 // Pre-compiled header stuff
18 //---------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
27 //---------------------------------------------------------------------------
29 //---------------------------------------------------------------------------
32 #include "wx/mediactrl.h"
38 #include "wx/osx/private.h"
40 //===========================================================================
41 // BACKEND DECLARATIONS
42 //===========================================================================
44 //---------------------------------------------------------------------------
48 //---------------------------------------------------------------------------
50 //---------------------------------------------------------------------------
52 //---------------------------------------------------------------------------
53 #include <QTKit/QTKit.h>
55 #include "wx/cocoa/autorelease.h"
56 #include "wx/cocoa/string.h"
58 class WXDLLIMPEXP_FWD_MEDIA wxQTMediaBackend;
60 @interface wxQTMovie : QTMovie {
62 wxQTMediaBackend* m_backend;
69 class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackendCommonBase
76 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
81 const wxValidator& validator,
82 const wxString& name);
88 virtual bool Load(const wxString& fileName);
89 virtual bool Load(const wxURI& location);
91 virtual wxMediaState GetState();
93 virtual bool SetPosition(wxLongLong where);
94 virtual wxLongLong GetPosition();
95 virtual wxLongLong GetDuration();
97 virtual void Move(int x, int y, int w, int h);
98 wxSize GetVideoSize() const;
100 virtual double GetPlaybackRate();
101 virtual bool SetPlaybackRate(double dRate);
103 virtual double GetVolume();
104 virtual bool SetVolume(double dVolume);
109 virtual bool ShowPlayerControls(wxMediaCtrlPlayerControls flags);
111 void DoShowPlayerControls(wxMediaCtrlPlayerControls flags);
113 wxSize m_bestSize; //Original movie size
114 wxQTMovie* m_movie; //QTMovie handle/instance
115 QTMovieView* m_movieview; //QTMovieView instance
117 wxMediaCtrlPlayerControls m_interfaceflags; // Saved interface flags
119 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend);
122 // --------------------------------------------------------------------------
124 // --------------------------------------------------------------------------
126 @implementation wxQTMovie
128 - (id)initWithURL:(NSURL *)url error:(NSError **)errorPtr
130 if ( [super initWithURL:url error:errorPtr] != nil )
134 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
135 [nc addObserver:self selector:@selector(movieDidEnd:)
136 name:QTMovieDidEndNotification object:nil];
137 [nc addObserver:self selector:@selector(movieRateChanged:)
138 name:QTMovieRateDidChangeNotification object:nil];
139 [nc addObserver:self selector:@selector(loadStateChanged:)
140 name:QTMovieLoadStateDidChangeNotification object:nil];
150 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
151 [nc removeObserver:self];
156 -(wxQTMediaBackend*) backend;
161 -(void) setBackend:(wxQTMediaBackend*) backend
166 - (void)movieDidEnd:(NSNotification *)notification
170 if ( m_backend->SendStopEvent() )
171 m_backend->QueueFinishEvent();
175 - (void)movieRateChanged:(NSNotification *)notification
177 NSDictionary *userInfo = [notification userInfo];
179 NSNumber *newRate = [userInfo objectForKey:QTMovieRateDidChangeNotificationParameter];
181 if ([newRate intValue] == 0)
183 m_backend->QueuePauseEvent();
185 else if ( [self isPlaying] == NO )
187 m_backend->QueuePlayEvent();
191 -(void)loadStateChanged:(NSNotification *)notification
193 QTMovie *movie = [notification object];
194 long loadState = [[movie attributeForKey:QTMovieLoadStateAttribute] longValue];
195 if ( loadState == QTMovieLoadStateError )
199 else if (loadState >= QTMovieLoadStatePlayable)
201 // the movie has loaded enough media data to begin playing, but we don't have an event for that yet
203 else if (loadState >= QTMovieLoadStateComplete) // we might use QTMovieLoadStatePlaythroughOK
205 m_backend->FinishLoad();
211 if ([self rate] == 0)
221 // --------------------------------------------------------------------------
223 // --------------------------------------------------------------------------
225 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
227 wxQTMediaBackend::wxQTMediaBackend() :
228 m_movie(nil), m_movieview(nil),
229 m_interfaceflags(wxMEDIACTRLPLAYERCONTROLS_NONE)
233 wxQTMediaBackend::~wxQTMediaBackend()
238 bool wxQTMediaBackend::CreateControl(wxControl* inctrl, wxWindow* parent,
243 const wxValidator& validator,
244 const wxString& name)
246 wxMediaCtrl* mediactrl = (wxMediaCtrl*) inctrl;
248 mediactrl->DontCreatePeer();
250 if ( !mediactrl->wxControl::Create(
251 parent, wid, pos, size,
252 wxWindow::MacRemoveBordersFromStyle(style),
258 NSRect r = wxOSXGetFrameForControl( mediactrl, pos , size ) ;
259 QTMovieView* theView = [[QTMovieView alloc] initWithFrame: r];
261 wxWidgetCocoaImpl* impl = new wxWidgetCocoaImpl(mediactrl,theView);
262 mediactrl->SetPeer(impl);
264 m_movieview = theView;
265 // will be set up after load
266 [theView setControllerVisible:NO];
272 bool wxQTMediaBackend::Load(const wxString& fileName)
276 wxString( wxT("file://") ) + fileName
281 bool wxQTMediaBackend::Load(const wxURI& location)
283 wxCFStringRef uri(location.BuildURI());
284 NSURL *url = [NSURL URLWithString: uri.AsNSString()];
286 if (! [wxQTMovie canInitWithURL:url])
290 wxQTMovie* movie = [[wxQTMovie alloc] initWithURL:url error: nil ];
295 [m_movie setBackend:this];
296 [m_movieview setMovie:movie];
298 // If the media file is able to be loaded quickly then there may not be
299 // any QTMovieLoadStateDidChangeNotification message sent, so we need to
300 // also check the load state here and finish our initialization if it has
302 long loadState = [[m_movie attributeForKey:QTMovieLoadStateAttribute] longValue];
303 if (loadState >= QTMovieLoadStateComplete)
312 void wxQTMediaBackend::FinishLoad()
314 DoShowPlayerControls(m_interfaceflags);
316 NSSize s = [[m_movie attributeForKey:QTMovieNaturalSizeAttribute] sizeValue];
317 m_bestSize = wxSize(s.width, s.height);
322 bool wxQTMediaBackend::Play()
324 [m_movieview play:nil];
328 bool wxQTMediaBackend::Pause()
330 [m_movieview pause:nil];
334 bool wxQTMediaBackend::Stop()
336 [m_movieview pause:nil];
337 [m_movieview gotoBeginning:nil];
341 double wxQTMediaBackend::GetVolume()
343 return [m_movie volume];
346 bool wxQTMediaBackend::SetVolume(double dVolume)
348 [m_movie setVolume:dVolume];
351 double wxQTMediaBackend::GetPlaybackRate()
353 return [m_movie rate];
356 bool wxQTMediaBackend::SetPlaybackRate(double dRate)
358 [m_movie setRate:dRate];
362 bool wxQTMediaBackend::SetPosition(wxLongLong where)
365 position = [m_movie currentTime];
366 position.timeValue = (where.GetValue() / 1000.0) * position.timeScale;
367 [m_movie setCurrentTime:position];
371 wxLongLong wxQTMediaBackend::GetPosition()
373 QTTime position = [m_movie currentTime];
374 return ((double) position.timeValue) / position.timeScale * 1000;
377 wxLongLong wxQTMediaBackend::GetDuration()
379 QTTime duration = [m_movie duration];
380 return ((double) duration.timeValue) / duration.timeScale * 1000;
383 wxMediaState wxQTMediaBackend::GetState()
385 if ( [m_movie isPlaying] )
386 return wxMEDIASTATE_PLAYING;
389 if ( GetPosition() == 0 )
390 return wxMEDIASTATE_STOPPED;
392 return wxMEDIASTATE_PAUSED;
396 void wxQTMediaBackend::Cleanup()
398 [m_movieview setMovie:NULL];
403 wxSize wxQTMediaBackend::GetVideoSize() const
408 void wxQTMediaBackend::Move(int x, int y, int w, int h)
410 // as we have a native player, no need to move the video area
413 bool wxQTMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags)
415 if ( m_interfaceflags != flags )
416 DoShowPlayerControls(flags);
418 m_interfaceflags = flags;
422 void wxQTMediaBackend::DoShowPlayerControls(wxMediaCtrlPlayerControls flags)
424 if (flags == wxMEDIACTRLPLAYERCONTROLS_NONE )
426 [m_movieview setControllerVisible:NO];
430 [m_movieview setControllerVisible:YES];
432 [m_movieview setStepButtonsVisible:(flags & wxMEDIACTRLPLAYERCONTROLS_STEP) ? YES:NO];
433 [m_movieview setVolumeButtonVisible:(flags & wxMEDIACTRLPLAYERCONTROLS_VOLUME) ? YES:NO];
437 //in source file that contains stuff you don't directly use
438 #include "wx/html/forcelnk.h"
439 FORCE_LINK_ME(basewxmediabackends);
441 #endif //wxUSE_MEDIACTRL