diff --git a/stepmania/src/arch/MovieTexture/MovieTexture_DShow.cpp b/stepmania/src/arch/MovieTexture/MovieTexture_DShow.cpp index ebbe9818c8..7c751e88e7 100644 --- a/stepmania/src/arch/MovieTexture/MovieTexture_DShow.cpp +++ b/stepmania/src/arch/MovieTexture/MovieTexture_DShow.cpp @@ -43,40 +43,65 @@ MovieTexture_DShow::MovieTexture_DShow( RageTextureID ID ) : { LOG->Trace( "RageBitmapTexture::RageBitmapTexture()" ); - buffer_changed = false; - m_uGLTextureID = 0; buffer = NULL; - - Create(); + buffer_lock = SDL_CreateSemaphore(1); + buffer_finished = SDL_CreateSemaphore(0); + Create(); CreateFrameRects(); + // flip all frame rects because movies are upside down for( unsigned i=0; iTrace("MovieTexture_DShow::~MovieTexture_DShow"); + LOG->Flush(); - // Shut down the graph + SkipUpdates(); + + /* Shut down the graph. We can't call Stop() here, since that will + * call SkipUpdates again, which will deadlock if we call it twice + * in a row. */ if (m_pGB) { - Stop(); - m_pGB.Release (); + LOG->Trace("MovieTexture_DShow: shutdown"); + LOG->Flush(); + CComPtr pMC; + m_pGB.QueryInterface(&pMC); + + HRESULT hr; + if( FAILED( hr = pMC->Stop() ) ) + RageException::Throw( hr_ssprintf(hr, "Could not stop the DirectShow graph.") ); + +// Stop(); + m_pGB.Release(); } - - delete [] buffer; - + LOG->Trace("MovieTexture_DShow: shutdown ok"); + LOG->Flush(); if(m_uGLTextureID) glDeleteTextures(1, &m_uGLTextureID); + + SDL_DestroySemaphore(buffer_lock); + SDL_DestroySemaphore(buffer_finished); } void MovieTexture_DShow::Reload() @@ -85,25 +110,29 @@ void MovieTexture_DShow::Reload() } -unsigned int MovieTexture_DShow::GetGLTextureID() -{ - CheckMovieStatus(); // restart the movie if we reach the end - return m_uGLTextureID; -} - void MovieTexture_DShow::Update(float fDeltaTime) { - LockMutex L(buffer_mutex); + // restart the movie if we reach the end + if(m_bLoop) + { + // Check for completion events + CComPtr pME; + m_pGB.QueryInterface(&pME); - if(!buffer_changed) + long lEventCode, lParam1, lParam2; + pME->GetEvent( &lEventCode, &lParam1, &lParam2, 0 ); + if( lEventCode == EC_COMPLETE ) + SetPosition(0); + } + + if(buffer == NULL) return; - buffer_changed = false; - /* Just in case we were invalidated: */ - CreateTexture(); + CreateTextures(); + + glBindTexture( GL_TEXTURE_2D, m_uGLTextureID ); - DISPLAY->SetTexture(this); glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -123,6 +152,13 @@ void MovieTexture_DShow::Update(float fDeltaTime) glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glFlush(); + + buffer = NULL; + + LOG->Trace("processed, signalling"); + + /* Start the decoding thread again. */ + SDL_SemPost(buffer_finished); } void PrintCodecError(HRESULT hr, CString s) @@ -208,33 +244,51 @@ void MovieTexture_DShow::Create() m_iTextureWidth = power_of_two(m_iImageWidth); m_iTextureHeight = power_of_two(m_iImageHeight); - if(buffer == NULL) - buffer = new char[m_iSourceWidth * m_iSourceHeight * 3]; - /* We've set up the movie, so we know the dimensions we need. Set * up the texture. */ - CreateTexture(); + CreateTextures(); // Start the graph running if( !PlayMovie() ) RageException::Throw( "Could not run the DirectShow graph." ); } + void MovieTexture_DShow::NewData(const char *data) { - LockMutex L(buffer_mutex); - buffer_changed = true; - memcpy(buffer, data, m_iSourceWidth * m_iSourceHeight * 3); + ASSERT(data); + + /* Try to lock. */ + if(SDL_SemTryWait(buffer_lock)) + { + /* The main thread is doing something uncommon, such as pausing. + * Drop this frame. */ + return; + } + + buffer = data; + + SDL_SemWait(buffer_finished); + + ASSERT(buffer == NULL); + + SDL_SemPost(buffer_lock); } -void MovieTexture_DShow::CreateTexture() + + +void MovieTexture_DShow::CreateTextures() { - if(m_uGLTextureID) - return; + if(!m_uGLTextureID) + m_uGLTextureID = CreateTexture(); +} - glGenTextures(1, &m_uGLTextureID); +unsigned MovieTexture_DShow::CreateTexture() +{ + unsigned TextureID; - DISPLAY->SetTexture(this); + glGenTextures(1, &TextureID); + glBindTexture( GL_TEXTURE_2D, TextureID ); /* Initialize the texture and set it to black. */ string buf(m_iTextureWidth*m_iTextureHeight*3, 0); @@ -256,10 +310,14 @@ void MovieTexture_DShow::CreateTexture() glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_iTextureWidth, m_iTextureHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, buf.data()); + + return TextureID; } bool MovieTexture_DShow::PlayMovie() { + SkipUpdates(); + LOG->Trace("MovieTexture_DShow::PlayMovie()"); CComPtr pMC; m_pGB.QueryInterface(&pMC); @@ -271,27 +329,12 @@ bool MovieTexture_DShow::PlayMovie() m_bPlaying = true; - return true; + StopSkippingUpdates(); + + return true; } -//----------------------------------------------------------------------------- -// CheckMovieStatus: If the movie has ended, rewind to beginning -//----------------------------------------------------------------------------- -void MovieTexture_DShow::CheckMovieStatus() -{ - if(!m_bLoop) return; - - // Check for completion events - CComPtr pME; - m_pGB.QueryInterface(&pME); - - long lEventCode, lParam1, lParam2; - pME->GetEvent( &lEventCode, &lParam1, &lParam2, 0 ); - if( EC_COMPLETE == lEventCode ) - SetPosition(0); -} - void MovieTexture_DShow::Play() { PlayMovie(); @@ -299,16 +342,22 @@ void MovieTexture_DShow::Play() void MovieTexture_DShow::Pause() { + SkipUpdates(); + CComPtr pMC; m_pGB.QueryInterface(&pMC); HRESULT hr; if( FAILED( hr = pMC->Pause() ) ) RageException::Throw( hr_ssprintf(hr, "Could not pause the DirectShow graph.") ); + + StopSkippingUpdates(); } void MovieTexture_DShow::Stop() { + SkipUpdates(); + CComPtr pMC; m_pGB.QueryInterface(&pMC); @@ -317,13 +366,19 @@ void MovieTexture_DShow::Stop() RageException::Throw( hr_ssprintf(hr, "Could not stop the DirectShow graph.") ); m_bPlaying = false; + + StopSkippingUpdates(); } void MovieTexture_DShow::SetPosition( float fSeconds ) { + SkipUpdates(); + CComPtr pMP; m_pGB.QueryInterface(&pMP); pMP->put_CurrentPosition(0); + + StopSkippingUpdates(); } bool MovieTexture_DShow::IsPlaying() const diff --git a/stepmania/src/arch/MovieTexture/MovieTexture_DShow.h b/stepmania/src/arch/MovieTexture/MovieTexture_DShow.h index c04e697ffe..79d291d942 100644 --- a/stepmania/src/arch/MovieTexture/MovieTexture_DShow.h +++ b/stepmania/src/arch/MovieTexture/MovieTexture_DShow.h @@ -62,23 +62,21 @@ public: void NewData(const char *buffer); -protected: - char *buffer; - bool buffer_changed; - RageMutex buffer_mutex; +private: + const char *buffer; + SDL_sem *buffer_lock, *buffer_finished; void Create(); - void CreateTexture(); + unsigned CreateTexture(); + void CreateTextures(); bool PlayMovie(); - void CheckMovieStatus(); + void SkipUpdates(); + void StopSkippingUpdates(); - virtual unsigned int GetGLTextureID(); + unsigned int GetGLTextureID() { return m_uGLTextureID; } unsigned int m_uGLTextureID; - //----------------------------------------------------------------------------- - // DirectShow pointers - //----------------------------------------------------------------------------- CComPtr m_pGB; // GraphBuilder bool m_bLoop; bool m_bPlaying;