fix cocoa wxTimer Stop crash, proper autorelease stuff in cocoa wxtimer, use our own custom c implementation for cocoa wxMediaCtrl because NSMovieView implementation isnt very good

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@31753 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Ryan Norton
2005-02-04 17:56:49 +00:00
parent 2fcd7f64a5
commit 0b6d471427
2 changed files with 125 additions and 24 deletions

View File

@@ -51,6 +51,7 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// QT Includes // QT Includes
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "wx/timer.h"
#include <QuickTime/QuickTime.h> #include <QuickTime/QuickTime.h>
#include "wx/cocoa/autorelease.h" #include "wx/cocoa/autorelease.h"
@@ -102,6 +103,7 @@ public:
NSMovieView* m_movieview; //NSMovieView instance NSMovieView* m_movieview; //NSMovieView instance
wxControl* m_ctrl; //Parent control wxControl* m_ctrl; //Parent control
bool m_bVideo; //Whether or not we have video bool m_bVideo; //Whether or not we have video
class _wxQTTimer* m_timer; //Timer for streaming the movie
DECLARE_DYNAMIC_CLASS(wxQTMediaBackend); DECLARE_DYNAMIC_CLASS(wxQTMediaBackend);
}; };
@@ -115,12 +117,74 @@ public:
IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend); IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
//Time between timer calls
#define MOVIE_DELAY 100
// --------------------------------------------------------------------------
// wxQTTimer - Handle Asyncronous Playing
// --------------------------------------------------------------------------
class _wxQTTimer : public wxTimer
{
public:
_wxQTTimer(Movie movie, wxQTMediaBackend* parent) :
m_movie(movie), m_bPaused(false), m_parent(parent)
{
}
~_wxQTTimer()
{
}
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()
{
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->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->ProcessEvent(theEvent);
}
}
}
}
protected:
Movie m_movie; //Our movie instance
bool m_bPaused; //Whether we are paused or not
wxQTMediaBackend* m_parent; //Backend pointer
};
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// wxQTMediaBackend Constructor // wxQTMediaBackend Constructor
// //
// Sets m_timer to NULL signifying we havn't loaded anything yet // Sets m_timer to NULL signifying we havn't loaded anything yet
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
wxQTMediaBackend::wxQTMediaBackend() wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL)
{ {
} }
@@ -135,10 +199,11 @@ wxQTMediaBackend::wxQTMediaBackend()
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
wxQTMediaBackend::~wxQTMediaBackend() wxQTMediaBackend::~wxQTMediaBackend()
{ {
if(m_timer)
Cleanup(); Cleanup();
//Note that ExitMovies() is not neccessary... //Note that ExitMovies() is not neccessary...
::ExitMovies(); ExitMovies();
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -203,6 +268,7 @@ bool wxQTMediaBackend::Load(const wxString& fileName)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool wxQTMediaBackend::Load(const wxURI& location) bool wxQTMediaBackend::Load(const wxURI& location)
{ {
if(m_timer)
Cleanup(); Cleanup();
wxString theURI = location.BuildURI(); wxString theURI = location.BuildURI();
@@ -212,6 +278,16 @@ bool wxQTMediaBackend::Load(const wxURI& location)
m_movie = (Movie) [[m_movieview movie] QTMovie]; m_movie = (Movie) [[m_movieview movie] QTMovie];
//preroll movie for streaming
//TODO:Async this using threads?
TimeValue timeNow;
Fixed playRate;
timeNow = GetMovieTime(m_movie, NULL);
playRate = GetMoviePreferredRate(m_movie);
PrePrerollMovie(m_movie, timeNow, playRate, NULL, NULL);
PrerollMovie(m_movie, timeNow, playRate);
SetMovieRate(m_movie, playRate);
FinishLoad(); FinishLoad();
return ::GetMoviesError() == noErr; return ::GetMoviesError() == noErr;
@@ -219,9 +295,20 @@ bool wxQTMediaBackend::Load(const wxURI& location)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// wxQTMediaBackend::FinishLoad // wxQTMediaBackend::FinishLoad
//
// 1) Create the movie timer
// 2) Get real size of movie for GetBestSize/sizers
// 3) See if there is video in the movie, and if so then either
// SetMovieGWorld if < 10.2 or use Native CreateMovieControl
// 4) Set the movie time scale to something usable so that seeking
// etc. will work correctly
// 5) Refresh parent window
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void wxQTMediaBackend::FinishLoad() void wxQTMediaBackend::FinishLoad()
{ {
m_timer = new _wxQTTimer(m_movie, (wxQTMediaBackend*) this);
wxASSERT(m_timer);
//get the real size of the movie //get the real size of the movie
Rect outRect; Rect outRect;
::GetMovieNaturalBoundsRect (m_movie, &outRect); ::GetMovieNaturalBoundsRect (m_movie, &outRect);
@@ -253,7 +340,9 @@ void wxQTMediaBackend::FinishLoad()
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool wxQTMediaBackend::Play() bool wxQTMediaBackend::Play()
{ {
[m_movieview start:NULL]; ::StartMovie(m_movie);
m_timer->SetPaused(false);
m_timer->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
return ::GetMoviesError() == noErr; return ::GetMoviesError() == noErr;
} }
@@ -265,7 +354,9 @@ bool wxQTMediaBackend::Play()
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool wxQTMediaBackend::Pause() bool wxQTMediaBackend::Pause()
{ {
[m_movieview stop:NULL]; ::StopMovie(m_movie);
m_timer->SetPaused(true);
m_timer->Stop();
return ::GetMoviesError() == noErr; return ::GetMoviesError() == noErr;
} }
@@ -278,8 +369,14 @@ bool wxQTMediaBackend::Pause()
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool wxQTMediaBackend::Stop() bool wxQTMediaBackend::Stop()
{ {
[m_movieview stop:NULL]; m_timer->SetPaused(false);
[m_movieview gotoBeginning:NULL]; m_timer->Stop();
::StopMovie(m_movie);
if(::GetMoviesError() != noErr)
return false;
::GoToBeginningOfMovie(m_movie);
return ::GetMoviesError() == noErr; return ::GetMoviesError() == noErr;
} }
@@ -353,11 +450,12 @@ wxLongLong wxQTMediaBackend::GetDuration()
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
wxMediaState wxQTMediaBackend::GetState() wxMediaState wxQTMediaBackend::GetState()
{ {
if ( [m_movieview isPlaying] ) if ( !m_timer || (m_timer->IsRunning() == false &&
return wxMEDIASTATE_PLAYING; m_timer->GetPaused() == false) )
if( wxQTMediaBackend::GetPosition() == 0 )
return wxMEDIASTATE_STOPPED; return wxMEDIASTATE_STOPPED;
if( m_timer->IsRunning() == true )
return wxMEDIASTATE_PLAYING;
else else
return wxMEDIASTATE_PAUSED; return wxMEDIASTATE_PAUSED;
} }
@@ -370,12 +468,12 @@ wxMediaState wxQTMediaBackend::GetState()
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void wxQTMediaBackend::Cleanup() void wxQTMediaBackend::Cleanup()
{ {
if([m_movieview movie]) delete m_timer;
{ m_timer = NULL;
[[m_movieview movie] release]; [[m_movieview movie] release];
[m_movieview setMovie:NULL]; [m_movieview setMovie:NULL];
} }
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// wxQTMediaBackend::GetVideoSize // wxQTMediaBackend::GetVideoSize
@@ -402,8 +500,3 @@ void wxQTMediaBackend::Move(int x, int y, int w, int h)
FORCE_LINK_ME(basewxmediabackends); FORCE_LINK_ME(basewxmediabackends);
#endif //wxUSE_MEDIACTRL #endif //wxUSE_MEDIACTRL

View File

@@ -26,6 +26,8 @@
#include "wx/timer.h" #include "wx/timer.h"
#endif #endif
#include "wx/cocoa/autorelease.h"
#import <Foundation/NSTimer.h> #import <Foundation/NSTimer.h>
// ============================================================================ // ============================================================================
@@ -94,6 +96,10 @@ void wxTimer::Init()
bool wxTimer::Start(int millisecs, bool oneShot) bool wxTimer::Start(int millisecs, bool oneShot)
{ {
Stop();
wxAutoNSAutoreleasePool thePool;
m_cocoaNSTimer = [[NSTimer m_cocoaNSTimer = [[NSTimer
scheduledTimerWithTimeInterval: millisecs / 1000.0 //seconds scheduledTimerWithTimeInterval: millisecs / 1000.0 //seconds
target: wxTimer::sm_cocoaDelegate target: wxTimer::sm_cocoaDelegate
@@ -108,9 +114,11 @@ void wxTimer::Stop()
{ {
if (m_cocoaNSTimer) if (m_cocoaNSTimer)
{ {
NSObject* theUserInfo = [m_cocoaNSTimer userInfo];
[m_cocoaNSTimer invalidate]; [m_cocoaNSTimer invalidate];
[[m_cocoaNSTimer userInfo] release]; [theUserInfo release];
[m_cocoaNSTimer release]; [m_cocoaNSTimer release];
m_cocoaNSTimer = NULL;
} }
} }