From 7f96a91be9f4fe18978d966e2f49fbdce3064fab Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Tue, 2 Sep 2003 06:08:02 +0000 Subject: [PATCH] Cleanup. Implement looping. --- .../arch/MovieTexture/MovieTexture_FFMpeg.cpp | 104 +++++++++++------- .../arch/MovieTexture/MovieTexture_FFMpeg.h | 5 +- 2 files changed, 68 insertions(+), 41 deletions(-) diff --git a/stepmania/src/arch/MovieTexture/MovieTexture_FFMpeg.cpp b/stepmania/src/arch/MovieTexture/MovieTexture_FFMpeg.cpp index 6659c52de9..9eb2c046cc 100644 --- a/stepmania/src/arch/MovieTexture/MovieTexture_FFMpeg.cpp +++ b/stepmania/src/arch/MovieTexture/MovieTexture_FFMpeg.cpp @@ -7,7 +7,6 @@ #include "SDL_utils.h" #include "SDL_endian.h" -/* TODO: implement m_bLoop */ #if defined(_WIN32) #pragma comment(lib, "ffmpeg/lib/avcodec.lib") @@ -135,8 +134,32 @@ MovieTexture_FFMpeg::MovieTexture_FFMpeg( RageTextureID ID ): m_BufferFinished = SDL_CreateSemaphore(0); m_OneFrameDecoded = SDL_CreateSemaphore(0); - Create(); + CreateDecoder(); + + LOG->Trace("Codec: %s", m_codec->name ); + LOG->Trace("Resolution: %ix%i (%ix%i, %ix%i)", + m_iSourceWidth, m_iSourceHeight, + m_iImageWidth, m_iImageHeight, m_iTextureWidth, m_iTextureHeight); + LOG->Trace("Bitrate: %i", m_stream->codec.bit_rate ); + LOG->Trace("Codec pixel format: %i", m_stream->codec.pix_fmt ); + + CreateTexture(); + StartThread(); + CreateFrameRects(); + + /* Wait until we decode one frame, to guarantee that the texture is + * drawn when this function returns. */ + ASSERT( m_State == PAUSE_DECODER ); + CHECKPOINT; + m_State = PLAYING_ONE; + SDL_SemWait( m_OneFrameDecoded ); + CHECKPOINT; + m_State = PAUSE_DECODER; + CheckFrame(); + CHECKPOINT; + + Play(); } static CString averr_ssprintf( int err, const char *fmt, ... ) @@ -164,13 +187,10 @@ static CString averr_ssprintf( int err, const char *fmt, ... ) } - -void MovieTexture_FFMpeg::Create() +void MovieTexture_FFMpeg::CreateDecoder() { m_Timer = 0; - ASSERT( m_State == DECODER_QUIT ); - RageTextureID actualID = GetID(); actualID.iAlphaBits = 0; @@ -209,40 +229,22 @@ void MovieTexture_FFMpeg::Create() /* Texture dimensions need to be a power of two; jump to the next. */ m_iTextureWidth = power_of_two(m_iImageWidth); m_iTextureHeight = power_of_two(m_iImageHeight); - - LOG->Trace("Codec: %s", m_codec->name ); - LOG->Trace("Resolution: %ix%i (%ix%i, %ix%i)", - m_iSourceWidth, m_iSourceHeight, - m_iImageWidth, m_iImageHeight, m_iTextureWidth, m_iTextureHeight); - LOG->Trace("Bitrate: %i", m_stream->codec.bit_rate ); - LOG->Trace("Codec pixel format: %i", m_stream->codec.pix_fmt ); - - /* We've set up the movie, so we know the dimensions we need. Set - * up the texture. */ - CreateTexture(); - - StartThread(); - - /* Wait until we decode one frame, to guarantee that the texture is - * drawn when this function returns. */ - ASSERT( m_State == PAUSE_DECODER ); - CHECKPOINT; - m_State = PLAYING_ONE; - SDL_SemWait( m_OneFrameDecoded ); - CHECKPOINT; - m_State = PAUSE_DECODER; - CheckFrame(); - CHECKPOINT; - - Play(); } -void MovieTexture_FFMpeg::Destroy() -{ - StopThread(); +/* Delete the decoder. The decoding thread must be stopped. */ +void MovieTexture_FFMpeg::DestroyDecoder() +{ avcodec::avcodec_close( &m_stream->codec ); - avcodec::av_close_input_file( m_fctx ); m_fctx = NULL; + avcodec::av_close_input_file( m_fctx ); + m_fctx = NULL; + m_stream = NULL; +} + +/* Delete the surface and texture. The decoding thread must be stopped, and this + * is normally done after destroying the decoder. */ +void MovieTexture_FFMpeg::DestroyTexture() +{ if( m_img ) { SDL_FreeSurface( m_img ); @@ -365,6 +367,24 @@ void MovieTexture_FFMpeg::DecoderThread() { CHECKPOINT; int ret = avcodec::av_read_packet(m_fctx, &pkt); + if( ret == -1 ) + { + /* EOF. */ + if( !m_bLoop ) + return; + + /* Restart. */ + DestroyDecoder(); + CreateDecoder(); + + CurrentTimestamp = Last_IP_Timestamp = 0; + GetNextTimestamp = true; + FrameSkipMode = false; + Frame = 0; + LastFrameDelay = 0; + continue; + } + if( ret < 0 ) { /* XXX ? */ @@ -518,7 +538,9 @@ void MovieTexture_FFMpeg::DecoderThread() MovieTexture_FFMpeg::~MovieTexture_FFMpeg() { - Destroy(); + StopThread(); + DestroyDecoder(); + DestroyTexture(); SDL_DestroySemaphore( m_BufferFinished ); SDL_DestroySemaphore( m_OneFrameDecoded ); @@ -615,8 +637,12 @@ void MovieTexture_FFMpeg::SetPosition( float fSeconds ) LOG->Trace( "Seek to %f (from %f)", fSeconds, m_Position ); State OldState = m_State; - Destroy(); - Create(); + /* Recreate the decoder. Do this without touching the actual texture, and without waiting + * for the first frame to be decoded, so we don't take too long. */ + StopThread(); + DestroyDecoder(); + CreateDecoder(); + StartThread(); m_State = OldState; } diff --git a/stepmania/src/arch/MovieTexture/MovieTexture_FFMpeg.h b/stepmania/src/arch/MovieTexture/MovieTexture_FFMpeg.h index 6893ac869f..9ba70cfa33 100644 --- a/stepmania/src/arch/MovieTexture/MovieTexture_FFMpeg.h +++ b/stepmania/src/arch/MovieTexture/MovieTexture_FFMpeg.h @@ -108,9 +108,10 @@ private: void DecoderThread(); RageThread m_DecoderThread; - void Create(); - void Destroy(); + void CreateDecoder(); void CreateTexture(); + void DestroyDecoder(); + void DestroyTexture(); void CheckFrame(); void StartThread(); void StopThread();