#include "wx/cocoa/autorelease.h"
#include "wx/cocoa/string.h"
-#import <AppKit/NSMovie.h>
-#import <AppKit/NSMovieView.h>
+class WXDLLIMPEXP_FWD_MEDIA wxQTMediaBackend;
+@interface wxQTMovie : QTMovie {
+
+ wxQTMediaBackend* m_backend;
+}
+
+-(BOOL)isPlaying;
-class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackend
+@end
+
+class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackendCommonBase
{
public:
void DoShowPlayerControls(wxMediaCtrlPlayerControls flags);
wxSize m_bestSize; //Original movie size
- QTMovie* m_movie; //QTMovie handle/instance
+ wxQTMovie* m_movie; //QTMovie handle/instance
QTMovieView* m_movieview; //QTMovieView instance
- wxControl* m_ctrl; //Parent control
wxMediaCtrlPlayerControls m_interfaceflags; // Saved interface flags
DECLARE_DYNAMIC_CLASS(wxQTMediaBackend);
};
+// --------------------------------------------------------------------------
+// wxQTMovie
+// --------------------------------------------------------------------------
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-//
-// wxQTMediaBackend
-//
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+@implementation wxQTMovie
-IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
+- (id)initWithURL:(NSURL *)url error:(NSError **)errorPtr
+{
+ if ( [super initWithURL:url error:errorPtr] != nil )
+ {
+ m_backend = NULL;
+
+ NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+ [nc addObserver:self selector:@selector(movieDidEnd:)
+ name:QTMovieDidEndNotification object:nil];
+ [nc addObserver:self selector:@selector(movieRateChanged:)
+ name:QTMovieRateDidChangeNotification object:nil];
+ [nc addObserver:self selector:@selector(loadStateChanged:)
+ name:QTMovieLoadStateDidChangeNotification object:nil];
+
+ return self;
+ }
+ else
+ return nil;
+}
-//Time between timer calls
-#define MOVIE_DELAY 100
+-(void)dealloc
+{
+ NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+ [nc removeObserver:self];
+
+ [super dealloc];
+}
-// --------------------------------------------------------------------------
-// wxQTTimer - Handle Asyncronous Playing
-// --------------------------------------------------------------------------
-class _wxQTTimer : public wxTimer
+-(wxQTMediaBackend*) backend;
{
-public:
- _wxQTTimer(QTMovie movie, wxQTMediaBackend* parent) :
- m_movie(movie), m_bPaused(false), m_parent(parent)
+ return m_backend;
+}
+
+-(void) setBackend:(wxQTMediaBackend*) backend
+{
+ m_backend = backend;
+}
+
+- (void)movieDidEnd:(NSNotification *)notification
+{
+ if ( m_backend )
{
+ if ( m_backend->SendStopEvent() )
+ m_backend->QueueFinishEvent();
}
+}
- ~_wxQTTimer()
+- (void)movieRateChanged:(NSNotification *)notification
+{
+ NSDictionary *userInfo = [notification userInfo];
+
+ NSNumber *newRate = [userInfo objectForKey:QTMovieRateDidChangeNotificationParameter];
+
+ if ([newRate intValue] == 0)
+ {
+ m_backend->QueuePauseEvent();
+ }
+ else if ( [self isPlaying] == NO )
{
+ m_backend->QueuePlayEvent();
}
+}
- bool GetPaused() {return m_bPaused;}
- void SetPaused(bool bPaused) {m_bPaused = bPaused;}
-
- //-----------------------------------------------------------------------
- // _wxQTTimer::Notify
- //
- // 1) Checks to see if the movie is done, and if not continues
- // streaming the movie
- // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
- // the movie.
- //-----------------------------------------------------------------------
- void Notify()
+-(void)loadStateChanged:(NSNotification *)notification
+{
+ QTMovie *movie = [notification object];
+ long loadState = [[movie attributeForKey:QTMovieLoadStateAttribute] longValue];
+ if ( loadState == QTMovieLoadStateError )
{
-#if 0
- if (!m_bPaused)
- {
- if(!IsMovieDone(m_movie))
- MoviesTask(m_movie, MOVIE_DELAY);
- else
- {
- wxMediaEvent theEvent(wxEVT_MEDIA_STOP,
- m_parent->m_ctrl->GetId());
- m_parent->m_ctrl->GetEventHandler()->ProcessEvent(theEvent);
-
- if(theEvent.IsAllowed())
- {
- Stop();
- m_parent->Stop();
- wxASSERT(::GetMoviesError() == noErr);
-
- //send the event to our child
- wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
- m_parent->m_ctrl->GetId());
- m_parent->m_ctrl->GetEventHandler()->ProcessEvent(theEvent);
- }
- }
- }
-#endif
+ // error occurred
+ }
+ else if (loadState >= QTMovieLoadStatePlayable)
+ {
+ // the movie has loaded enough media data to begin playing, but we don't have an event for that yet
+ }
+ else if (loadState >= QTMovieLoadStateComplete) // we might use QTMovieLoadStatePlaythroughOK
+ {
+ m_backend->FinishLoad();
}
+}
-protected:
- QTMovie m_movie; //Our movie instance
- bool m_bPaused; //Whether we are paused or not
- wxQTMediaBackend* m_parent; //Backend pointer
-};
+-(BOOL)isPlaying
+{
+ if ([self rate] == 0)
+ {
+ return NO;
+ }
+
+ return YES;
+}
+
+@end
+
+// --------------------------------------------------------------------------
+// wxQTMediaBackend
+// --------------------------------------------------------------------------
+
+IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
-//---------------------------------------------------------------------------
-// wxQTMediaBackend Constructor
-//
-// Sets m_timer to NULL signifying we havn't loaded anything yet
-//---------------------------------------------------------------------------
wxQTMediaBackend::wxQTMediaBackend() :
- m_interfaceflags(wxMEDIACTRLPLAYERCONTROLS_NONE),
- m_movie(nil), m_movieview(nil), m_ctrl(NULL)
+ m_movie(nil), m_movieview(nil),
+ m_interfaceflags(wxMEDIACTRLPLAYERCONTROLS_NONE)
{
}
-//---------------------------------------------------------------------------
-// wxQTMediaBackend Destructor
-//
-// 1) Cleans up the QuickTime movie instance
-// 2) Decrements the QuickTime reference counter - if this reaches
-// 0, QuickTime shuts down
-// 3) Decrements the QuickTime Windows Media Layer reference counter -
-// if this reaches 0, QuickTime shuts down the Windows Media Layer
-//---------------------------------------------------------------------------
wxQTMediaBackend::~wxQTMediaBackend()
{
- [m_movie release];
+ Cleanup();
}
-//---------------------------------------------------------------------------
-// wxQTMediaBackend::CreateControl
-//
-// 1) Intializes QuickTime
-// 2) Creates the control window
-//---------------------------------------------------------------------------
bool wxQTMediaBackend::CreateControl(wxControl* inctrl, wxWindow* parent,
wxWindowID wid,
const wxPoint& pos,
{
wxMediaCtrl* mediactrl = (wxMediaCtrl*) inctrl;
- //
- // Create window
- // By default wxWindow(s) is created with a border -
- // so we need to get rid of those
- //
- // Since we don't have a child window like most other
- // backends, we don't need wxCLIP_CHILDREN
- //
+ mediactrl->DontCreatePeer();
+
if ( !mediactrl->wxControl::Create(
parent, wid, pos, size,
wxWindow::MacRemoveBordersFromStyle(style),
bool wxQTMediaBackend::Load(const wxURI& location)
{
- wxString theURI = location.BuildURI();
-
- QTMovie* movie = [[QTMovie alloc] initWithURL: [NSURL URLWithString: wxNSStringWithWxString(theURI)] error: nil ];
-
- [m_movie release];
- m_movie = movie;
+ wxCFStringRef uri(location.BuildURI());
+ NSURL *url = [NSURL URLWithString: uri.AsNSString()];
- [m_movieview setMovie:movie];
+ if (! [wxQTMovie canInitWithURL:url])
+ return false;
- DoShowPlayerControls(m_interfaceflags);
-
- FinishLoad();
+ [m_movie release];
+ wxQTMovie* movie = [[wxQTMovie alloc] initWithURL:url error: nil ];
+ m_movie = movie;
+ if (movie != nil)
+ {
+ [m_movie setBackend:this];
+ [m_movieview setMovie:movie];
+
+ // If the media file is able to be loaded quickly then there may not be
+ // any QTMovieLoadStateDidChangeNotification message sent, so we need to
+ // also check the load state here and finish our initialization if it has
+ // been loaded.
+ long loadState = [[m_movie attributeForKey:QTMovieLoadStateAttribute] longValue];
+ if (loadState >= QTMovieLoadStateComplete)
+ {
+ FinishLoad();
+ }
+ }
+
return movie != nil;
}
void wxQTMediaBackend::FinishLoad()
{
- NSRect r =[m_movieview movieBounds];
- m_bestSize.x = r.size.width;
- m_bestSize.y = r.size.height;
-
- m_ctrl->InvalidateBestSize();
- m_ctrl->GetParent()->Layout();
- m_ctrl->GetParent()->Refresh();
- m_ctrl->GetParent()->Update();
+ DoShowPlayerControls(m_interfaceflags);
+
+ NSSize s = [[m_movie attributeForKey:QTMovieNaturalSizeAttribute] sizeValue];
+ m_bestSize = wxSize(s.width, s.height);
+
+ NotifyMovieLoaded();
}
bool wxQTMediaBackend::Play()
wxMediaState wxQTMediaBackend::GetState()
{
- /*
- if ( !m_timer || (m_timer->IsRunning() == false &&
- m_timer->GetPaused() == false) )
- return wxMEDIASTATE_STOPPED;
-
- if( m_timer->IsRunning() == true )
+ if ( [m_movie isPlaying] )
return wxMEDIASTATE_PLAYING;
else
- */
- return wxMEDIASTATE_PAUSED;
+ {
+ if ( GetPosition() == 0 )
+ return wxMEDIASTATE_STOPPED;
+ else
+ return wxMEDIASTATE_PAUSED;
+ }
}
void wxQTMediaBackend::Cleanup()
{
- [[m_movieview movie] release];
[m_movieview setMovie:NULL];
+ [m_movie release];
+ m_movie = nil;
}
wxSize wxQTMediaBackend::GetVideoSize() const
void wxQTMediaBackend::Move(int x, int y, int w, int h)
{
+ // as we have a native player, no need to move the video area
}
bool wxQTMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags)
}
else
{
+ [m_movieview setControllerVisible:YES];
+
[m_movieview setStepButtonsVisible:(flags & wxMEDIACTRLPLAYERCONTROLS_STEP) ? YES:NO];
[m_movieview setVolumeButtonVisible:(flags & wxMEDIACTRLPLAYERCONTROLS_VOLUME) ? YES:NO];
}