From 813432c98dcd5e8a043827127b86ee5fa2cef374 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Sun, 25 Mar 2007 07:46:20 +0000 Subject: [PATCH] Split decode and convert, and do them on alternating frames. --- .../arch/MovieTexture/MovieTexture_FFMpeg.cpp | 19 ++++--- .../MovieTexture/MovieTexture_Generic.cpp | 50 +++++++------------ .../arch/MovieTexture/MovieTexture_Generic.h | 23 +++------ .../arch/MovieTexture/MovieTexture_Theora.cpp | 11 ++-- 4 files changed, 41 insertions(+), 62 deletions(-) diff --git a/stepmania/src/arch/MovieTexture/MovieTexture_FFMpeg.cpp b/stepmania/src/arch/MovieTexture/MovieTexture_FFMpeg.cpp index 5c15037008..53e601f789 100644 --- a/stepmania/src/arch/MovieTexture/MovieTexture_FFMpeg.cpp +++ b/stepmania/src/arch/MovieTexture/MovieTexture_FFMpeg.cpp @@ -234,7 +234,8 @@ public: void Close(); void Rewind(); - int GetFrame( RageSurface *pOut, float fTargetTime ); + void GetFrame( RageSurface *pOut ); + int DecodeFrame( float fTargetTime ); int GetWidth() const { return m_pStream->codec->width; } int GetHeight() const { return m_pStream->codec->height; } @@ -248,8 +249,7 @@ private: void Init(); RString OpenCodec(); int ReadPacket(); - int DecodePacket( RageSurface *pOut, float fTargetTime ); - void ConvertToSurface( RageSurface *pSurface ) const; + int DecodePacket( float fTargetTime ); avcodec::AVStream *m_pStream; avcodec::AVFrame m_Frame; @@ -315,11 +315,12 @@ void MovieDecoder_FFMpeg::Init() } /* Read until we get a frame, EOF or error. Return -1 on error, 0 on EOF, 1 if we have a frame. */ -int MovieDecoder_FFMpeg::GetFrame( RageSurface *pOut, float fTargetTime ) +int MovieDecoder_FFMpeg::DecodeFrame( float fTargetTime ) { while( 1 ) { - int ret = DecodePacket( pOut, fTargetTime ); + int ret = DecodePacket( fTargetTime ); + if( ret == 1 ) return 1; if( ret == -1 ) @@ -384,7 +385,7 @@ int MovieDecoder_FFMpeg::ReadPacket() /* Decode data from the current packet. Return -1 on error, 0 if the packet is finished, * and 1 if we have a frame (we may have more data in the packet). */ -int MovieDecoder_FFMpeg::DecodePacket( RageSurface *pOut, float fTargetTime ) +int MovieDecoder_FFMpeg::DecodePacket( float fTargetTime ) { if( m_iEOF == 0 && m_iCurrentPacketOffset == -1 ) return 0; /* no packet */ @@ -393,7 +394,7 @@ int MovieDecoder_FFMpeg::DecodePacket( RageSurface *pOut, float fTargetTime ) { if( m_bGetNextTimestamp ) { - if (m_Packet.pts != int64_t(AV_NOPTS_VALUE)) + if (m_Packet.dts != int64_t(AV_NOPTS_VALUE)) { m_fPTS = m_Packet.dts * av_q2d(m_pStream->time_base); @@ -488,15 +489,13 @@ int MovieDecoder_FFMpeg::DecodePacket( RageSurface *pOut, float fTargetTime ) if( bSkipThisFrame ) continue; - ConvertToSurface( pOut ); - return 1; } return 0; /* packet done */ } -void MovieDecoder_FFMpeg::ConvertToSurface( RageSurface *pSurface ) const +void MovieDecoder_FFMpeg::GetFrame( RageSurface *pSurface ) { avcodec::AVPicture pict; pict.data[0] = (unsigned char *) pSurface->pixels; diff --git a/stepmania/src/arch/MovieTexture/MovieTexture_Generic.cpp b/stepmania/src/arch/MovieTexture/MovieTexture_Generic.cpp index 08b25db9e0..3280188959 100644 --- a/stepmania/src/arch/MovieTexture/MovieTexture_Generic.cpp +++ b/stepmania/src/arch/MovieTexture/MovieTexture_Generic.cpp @@ -48,7 +48,7 @@ RString MovieTexture_Generic::Init() CreateFrameRects(); /* Decode one frame, to guarantee that the texture is drawn when this function returns. */ - int ret = GetFrame( -1 ); + int ret = m_pDecoder->DecodeFrame( -1 ); if( ret == -1 ) return ssprintf( "%s: error getting first frame", GetID().filename.c_str() ); if( ret == 0 ) @@ -57,7 +57,7 @@ RString MovieTexture_Generic::Init() return ssprintf( "%s: EOF getting first frame", GetID().filename.c_str() ); } - m_ImageWaiting = FRAME_WAITING; + m_ImageWaiting = FRAME_DECODED; LOG->Trace( "Resolution: %ix%i (%ix%i, %ix%i)", m_iSourceWidth, m_iSourceHeight, @@ -302,8 +302,6 @@ void MovieTexture_Generic::CreateTexture() * (due to quit, error, EOF, etc). If true is returned, we'll be in FRAME_DECODED. */ bool MovieTexture_Generic::DecodeFrame() { - ASSERT_M( m_ImageWaiting == FRAME_NONE, ssprintf("%i", m_ImageWaiting) ); - bool bTriedRewind = false; do { @@ -334,7 +332,7 @@ bool MovieTexture_Generic::DecodeFrame() if( m_bFrameSkipMode && m_fClock > m_pDecoder->GetTimestamp() ) fTargetTime = m_fClock; - int ret = GetFrame( fTargetTime ); + int ret = m_pDecoder->DecodeFrame( fTargetTime ); if( ret == -1 ) return false; @@ -353,22 +351,18 @@ bool MovieTexture_Generic::DecodeFrame() } /* We got a frame. */ - m_ImageWaiting = FRAME_DECODED; } while( m_bWantRewind ); return true; } /* - * Call when m_ImageWaiting == FRAME_DECODED. * Returns: * == 0 if the currently decoded frame is ready to be displayed * > 0 (seconds) if it's not yet time to display; */ float MovieTexture_Generic::CheckFrameTime() { - ASSERT_M( m_ImageWaiting == FRAME_DECODED, ssprintf("%i", m_ImageWaiting) ); - if( m_fRate == 0 ) return 1; // "a long time until the next frame" @@ -428,29 +422,31 @@ void MovieTexture_Generic::DecodeSeconds( float fSeconds ) { /* If we don't have a frame decoded, decode one. */ if( m_ImageWaiting == FRAME_NONE ) - DecodeFrame(); - - /* If we have a frame decoded, see if it's time to display it. */ - if( m_ImageWaiting == FRAME_DECODED ) { - float fTime = CheckFrameTime(); - if( fTime > 0 ) - return; + if( !DecodeFrame() ) + break; - m_ImageWaiting = FRAME_WAITING; + m_ImageWaiting = FRAME_DECODED; } - if( m_ImageWaiting != FRAME_WAITING ) + /* If we have a frame decoded, see if it's time to display it. */ + float fTime = CheckFrameTime(); + if( fTime > 0 ) return; + CHECKPOINT; UpdateFrame(); + + m_ImageWaiting = FRAME_NONE; + + return; } LOG->MapLog( "movie_looping", "MovieTexture_Generic::Update looping" ); } -int MovieTexture_Generic::GetFrame( float fTargetTime ) +void MovieTexture_Generic::UpdateFrame() { /* Just in case we were invalidated: */ CreateTexture(); @@ -461,19 +457,9 @@ int MovieTexture_Generic::GetFrame( float fTargetTime ) m_pTextureLock->Lock( iHandle, m_pSurface ); } - int ret = m_pDecoder->GetFrame( m_pSurface, fTargetTime ); + m_pDecoder->GetFrame( m_pSurface ); if( m_pTextureLock != NULL ) - m_pTextureLock->Unlock( m_pSurface, ret > 0 ); - return ret; -} - -/* Call when m_ImageWaiting == FRAME_WAITING to update the texture. Sets FRAME_NONE. */ -void MovieTexture_Generic::UpdateFrame() -{ - ASSERT_M( m_ImageWaiting == FRAME_WAITING, ssprintf("%i", m_ImageWaiting) ); - - /* Just in case we were invalidated: */ - CreateTexture(); + m_pTextureLock->Unlock( m_pSurface, true ); if( m_pRenderTarget != NULL ) { @@ -503,8 +489,6 @@ void MovieTexture_Generic::UpdateFrame() m_iImageWidth, m_iImageHeight ); CHECKPOINT; } - - m_ImageWaiting = FRAME_NONE; } static EffectMode EffectModes[] = diff --git a/stepmania/src/arch/MovieTexture/MovieTexture_Generic.h b/stepmania/src/arch/MovieTexture/MovieTexture_Generic.h index dcde574b60..2967ddac7e 100644 --- a/stepmania/src/arch/MovieTexture/MovieTexture_Generic.h +++ b/stepmania/src/arch/MovieTexture/MovieTexture_Generic.h @@ -36,7 +36,12 @@ public: * Otherwise, fTargetTime will be -1, and the next frame should be * decoded; skip frames only if necessary to recover from errors. */ - virtual int GetFrame( RageSurface *pOut, float fTargetTime ) = 0; + virtual int DecodeFrame( float fTargetTime ) = 0; + + /* + * Get the currently-decoded frame. + */ + virtual void GetFrame( RageSurface *pOut ) = 0; /* Return the dimensions of the image, in pixels (before aspect ratio * adjustments). */ @@ -93,30 +98,16 @@ public: static EffectMode GetEffectMode( MovieDecoderPixelFormatYCbCr fmt ); private: - int GetFrame( float fTargetTime ); - MovieDecoder *m_pDecoder; float m_fRate; enum { FRAME_NONE, /* no frame available; call GetFrame to get one */ - FRAME_DECODED, /* frame decoded; waiting until it's time to display it */ - FRAME_WAITING /* frame waiting to be uploaded */ + FRAME_DECODED /* frame decoded; waiting until it's time to display it */ } m_ImageWaiting; bool m_bLoop; bool m_bWantRewind; - /* - * Only the main thread can change m_State. - * - * DECODER_QUIT: The decoder thread is not running. We should only - * be in this state internally; when we return after a call, we should - * never be in this state. Start the thread before returning. - * - * PAUSE_DECODER: The decoder thread is idle. - * - * PLAYING: The decoder thread is running. - */ enum State { DECODER_QUIT, DECODER_RUNNING } m_State; unsigned m_uTexHandle; diff --git a/stepmania/src/arch/MovieTexture/MovieTexture_Theora.cpp b/stepmania/src/arch/MovieTexture/MovieTexture_Theora.cpp index b633f2fb73..d08f62bd39 100644 --- a/stepmania/src/arch/MovieTexture/MovieTexture_Theora.cpp +++ b/stepmania/src/arch/MovieTexture/MovieTexture_Theora.cpp @@ -32,7 +32,8 @@ public: void Close(); void Rewind() { } // XXX - int GetFrame( RageSurface *pOut, float fTargetTime ); + int DecodeFrame( float fTargetTime ); + void GetFrame( RageSurface *pOut ); RageSurface *CreateCompatibleSurface( int iTextureWidth, int iTextureHeight, bool bPreferHighColor, MovieDecoderPixelFormatYCbCr &fmtout ); int GetWidth() const { return m_TheoraInfo.frame_width; } @@ -228,7 +229,7 @@ RString MovieDecoder_Theora::Open( RString sFile ) return RString(); } -int MovieDecoder_Theora::GetFrame( RageSurface *pOut, float fTargetTime ) +int MovieDecoder_Theora::DecodeFrame( float fTargetTime ) { while(1) { @@ -245,7 +246,6 @@ int MovieDecoder_Theora::GetFrame( RageSurface *pOut, float fTargetTime ) continue; } - ConvertToSurface( pOut ); m_iGranulepos = m_TheoraState.granulepos; return 1; } @@ -266,6 +266,11 @@ int MovieDecoder_Theora::GetFrame( RageSurface *pOut, float fTargetTime ) } } +void MovieDecoder_Theora::GetFrame( RageSurface *pOut ) +{ + ConvertToSurface( pOut ); +} + RageSurface *MovieDecoder_Theora::CreateCompatibleSurface( int iTextureWidth, int iTextureHeight, bool bPreferHighColor, MovieDecoderPixelFormatYCbCr &fmtout ) { return RageMovieTextureDriver_FFMpeg::AVCodecCreateCompatibleSurface( iTextureWidth, iTextureHeight, bPreferHighColor, *ConvertValue(&m_OutputPixFmt), fmtout );