split out RunDecode function
This commit is contained in:
@@ -420,6 +420,8 @@ try {
|
|||||||
m_ImageWaiting = false;
|
m_ImageWaiting = false;
|
||||||
m_Rate = 1;
|
m_Rate = 1;
|
||||||
m_bWantRewind = false;
|
m_bWantRewind = false;
|
||||||
|
m_Clock = 0;
|
||||||
|
m_FrameSkipMode = false;
|
||||||
|
|
||||||
m_BufferFinished = SDL_CreateSemaphore(0);
|
m_BufferFinished = SDL_CreateSemaphore(0);
|
||||||
|
|
||||||
@@ -711,14 +713,118 @@ void MovieTexture_FFMpeg::CreateTexture()
|
|||||||
m_uTexHandle = DISPLAY->CreateTexture( pixfmt, m_img, false );
|
m_uTexHandle = DISPLAY->CreateTexture( pixfmt, m_img, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle decoding for a frame. Return true if a frame was decoded and is waiting
|
||||||
|
* to be handled. */
|
||||||
|
bool MovieTexture_FFMpeg::RunDecode()
|
||||||
|
{
|
||||||
|
if( m_State == PAUSE_DECODER )
|
||||||
|
{
|
||||||
|
/* The video isn't running; skip time. */
|
||||||
|
m_Timer.GetDeltaTime();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_State != PLAYING )
|
||||||
|
return false;
|
||||||
|
CHECKPOINT;
|
||||||
|
|
||||||
|
/* We're playing. Update the clock. */
|
||||||
|
m_Clock += m_Timer.GetDeltaTime() * m_Rate;
|
||||||
|
|
||||||
|
/* Read a frame. */
|
||||||
|
int ret = decoder->GetFrame();
|
||||||
|
if( ret == -1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( m_bWantRewind && decoder->GetTimestamp() == 0 )
|
||||||
|
m_bWantRewind = false; /* ignore */
|
||||||
|
|
||||||
|
if( ret == 0 )
|
||||||
|
{
|
||||||
|
/* EOF. */
|
||||||
|
if( !m_bLoop )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
LOG->Trace( "File \"%s\" looping", GetID().filename.c_str() );
|
||||||
|
m_bWantRewind = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_bWantRewind )
|
||||||
|
{
|
||||||
|
m_bWantRewind = false;
|
||||||
|
|
||||||
|
/* Restart. */
|
||||||
|
DestroyDecoder();
|
||||||
|
CreateDecoder();
|
||||||
|
|
||||||
|
decoder->Init();
|
||||||
|
m_Clock = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We got a frame. */
|
||||||
|
const float Offset = decoder->GetTimestamp() - m_Clock;
|
||||||
|
|
||||||
|
/* If we're ahead, we're decoding too fast; delay. */
|
||||||
|
if( Offset > 0 )
|
||||||
|
{
|
||||||
|
SDL_Delay( int(1000*Offset) );
|
||||||
|
if( m_FrameSkipMode )
|
||||||
|
{
|
||||||
|
/* We're caught up; stop skipping frames. */
|
||||||
|
LOG->Trace( "stopped skipping frames" );
|
||||||
|
m_FrameSkipMode = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* We're behind by -Offset seconds.
|
||||||
|
*
|
||||||
|
* If we're just slightly behind, don't worry about it; we'll simply
|
||||||
|
* not sleep, so we'll move as fast as we can to catch up.
|
||||||
|
*
|
||||||
|
* If we're far behind, we're short on CPU and we need to do something
|
||||||
|
* about it. We have at least two options:
|
||||||
|
*
|
||||||
|
* 1: We can skip texture updates. This is a big bottleneck on many
|
||||||
|
* systems.
|
||||||
|
*
|
||||||
|
* 2: If that's not enough, we can play with hurry_up.
|
||||||
|
*
|
||||||
|
* If we hit a threshold, start skipping frames via #1. If we do that,
|
||||||
|
* don't stop once we hit the threshold; keep doing it until we're fully
|
||||||
|
* caught up.
|
||||||
|
*
|
||||||
|
* I'm not sure when we should do #2. Also, we should try to notice if
|
||||||
|
* we simply don't have enough CPU for the video; it's better to just
|
||||||
|
* stay in frame skip mode than to enter and exit it constantly, but we
|
||||||
|
* don't want to do that due to a single timing glitch.
|
||||||
|
*
|
||||||
|
* XXX: is there a setting for hurry_up we can use when we're going to ignore
|
||||||
|
* a frame to make it take less time?
|
||||||
|
*/
|
||||||
|
const float FrameSkipThreshold = 0.5f;
|
||||||
|
|
||||||
|
if( -Offset >= FrameSkipThreshold && !m_FrameSkipMode )
|
||||||
|
{
|
||||||
|
LOG->Trace( "(%s) Time is %f, and the movie is at %f. Entering frame skip mode.",
|
||||||
|
GetID().filename.c_str(), m_Clock, decoder->GetTimestamp());
|
||||||
|
m_FrameSkipMode = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_FrameSkipMode && decoder->m_stream->codec.frame_number % 2 )
|
||||||
|
return false; /* skip */
|
||||||
|
|
||||||
|
/* Convert it. */
|
||||||
|
ConvertFrame();
|
||||||
|
|
||||||
|
/* Signal the main thread to update the image on the next Update. */
|
||||||
|
m_ImageWaiting=true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void MovieTexture_FFMpeg::DecoderThread()
|
void MovieTexture_FFMpeg::DecoderThread()
|
||||||
{
|
{
|
||||||
RageTimer Timer;
|
|
||||||
float Clock = 0;
|
|
||||||
bool FrameSkipMode = false;
|
|
||||||
|
|
||||||
#if defined(_WINDOWS)
|
#if defined(_WINDOWS)
|
||||||
/* Movie decoding is bursty. We burst decode a frame, then we sleep, then we burst
|
/* Movie decoding is bursty. We burst decode a frame, then we sleep, then we burst
|
||||||
* to YUV->RGB convert, then we wait for the frame to move, and we repeat. */
|
* to YUV->RGB convert, then we wait for the frame to move, and we repeat. */
|
||||||
@@ -736,110 +842,20 @@ void MovieTexture_FFMpeg::DecoderThread()
|
|||||||
|
|
||||||
while( m_State != DECODER_QUIT )
|
while( m_State != DECODER_QUIT )
|
||||||
{
|
{
|
||||||
|
bool bGotFrame = RunDecode();
|
||||||
|
|
||||||
if( m_State == PAUSE_DECODER )
|
if( m_State == PAUSE_DECODER )
|
||||||
{
|
{
|
||||||
|
/* We aren't feeding frames, so we aren't waiting; don't chew CPU. */
|
||||||
SDL_Delay( 10 );
|
SDL_Delay( 10 );
|
||||||
|
|
||||||
/* The video isn't running; skip time. */
|
|
||||||
Timer.GetDeltaTime();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECKPOINT;
|
if( !bGotFrame )
|
||||||
|
|
||||||
/* We're playing. Update the clock. */
|
|
||||||
Clock += Timer.GetDeltaTime() * m_Rate;
|
|
||||||
|
|
||||||
/* Read a frame. */
|
|
||||||
int ret = decoder->GetFrame();
|
|
||||||
if( ret == -1 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if( m_bWantRewind && decoder->GetTimestamp() == 0 )
|
|
||||||
m_bWantRewind = false; /* ignore */
|
|
||||||
|
|
||||||
if( ret == 0 )
|
|
||||||
{
|
|
||||||
/* EOF. */
|
|
||||||
if( !m_bLoop )
|
|
||||||
return;
|
|
||||||
|
|
||||||
LOG->Trace( "File \"%s\" looping", GetID().filename.c_str() );
|
|
||||||
m_bWantRewind = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( m_bWantRewind )
|
|
||||||
{
|
|
||||||
m_bWantRewind = false;
|
|
||||||
|
|
||||||
/* Restart. */
|
|
||||||
DestroyDecoder();
|
|
||||||
CreateDecoder();
|
|
||||||
|
|
||||||
decoder->Init();
|
|
||||||
Clock = 0;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
/* We got a frame. */
|
|
||||||
const float Offset = decoder->GetTimestamp() - Clock;
|
|
||||||
|
|
||||||
/* If we're ahead, we're decoding too fast; delay. */
|
|
||||||
if( Offset > 0 )
|
|
||||||
{
|
|
||||||
SDL_Delay( int(1000*Offset) );
|
|
||||||
if( FrameSkipMode )
|
|
||||||
{
|
|
||||||
/* We're caught up; stop skipping frames. */
|
|
||||||
LOG->Trace( "stopped skipping frames" );
|
|
||||||
FrameSkipMode = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* We're behind by -Offset seconds.
|
|
||||||
*
|
|
||||||
* If we're just slightly behind, don't worry about it; we'll simply
|
|
||||||
* not sleep, so we'll move as fast as we can to catch up.
|
|
||||||
*
|
|
||||||
* If we're far behind, we're short on CPU and we need to do something
|
|
||||||
* about it. We have at least two options:
|
|
||||||
*
|
|
||||||
* 1: We can skip texture updates. This is a big bottleneck on many
|
|
||||||
* systems.
|
|
||||||
*
|
|
||||||
* 2: If that's not enough, we can play with hurry_up.
|
|
||||||
*
|
|
||||||
* If we hit a threshold, start skipping frames via #1. If we do that,
|
|
||||||
* don't stop once we hit the threshold; keep doing it until we're fully
|
|
||||||
* caught up.
|
|
||||||
*
|
|
||||||
* I'm not sure when we should do #2. Also, we should try to notice if
|
|
||||||
* we simply don't have enough CPU for the video; it's better to just
|
|
||||||
* stay in frame skip mode than to enter and exit it constantly, but we
|
|
||||||
* don't want to do that due to a single timing glitch.
|
|
||||||
*
|
|
||||||
* XXX: is there a setting for hurry_up we can use when we're going to ignore
|
|
||||||
* a frame to make it take less time?
|
|
||||||
*/
|
|
||||||
const float FrameSkipThreshold = 0.5f;
|
|
||||||
|
|
||||||
if( -Offset >= FrameSkipThreshold && !FrameSkipMode )
|
|
||||||
{
|
|
||||||
LOG->Trace( "(%s) Time is %f, and the movie is at %f. Entering frame skip mode.",
|
|
||||||
GetID().filename.c_str(), Clock, decoder->GetTimestamp());
|
|
||||||
FrameSkipMode = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( FrameSkipMode && decoder->m_stream->codec.frame_number % 2 )
|
|
||||||
continue; /* skip */
|
|
||||||
|
|
||||||
/* Convert it. */
|
|
||||||
ConvertFrame();
|
|
||||||
|
|
||||||
/* Signal the main thread to update the image on the next Update. */
|
|
||||||
m_ImageWaiting=true;
|
|
||||||
|
|
||||||
/* SDL_SemWait does not properly retry sem_wait in Linux on EINTR. */
|
/* SDL_SemWait does not properly retry sem_wait in Linux on EINTR. */
|
||||||
|
int ret;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
CHECKPOINT;
|
CHECKPOINT;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "RageDisplay.h"
|
#include "RageDisplay.h"
|
||||||
#include "RageTexture.h"
|
#include "RageTexture.h"
|
||||||
#include "RageThreads.h"
|
#include "RageThreads.h"
|
||||||
|
#include "RageTimer.h"
|
||||||
|
|
||||||
#include "SDL_mutex.h"
|
#include "SDL_mutex.h"
|
||||||
|
|
||||||
@@ -64,6 +65,10 @@ private:
|
|||||||
|
|
||||||
SDL_sem *m_BufferFinished;
|
SDL_sem *m_BufferFinished;
|
||||||
|
|
||||||
|
RageTimer m_Timer;
|
||||||
|
float m_Clock;
|
||||||
|
bool m_FrameSkipMode;
|
||||||
|
|
||||||
static int DecoderThread_start(void *p) { ((MovieTexture_FFMpeg *)(p))->DecoderThread(); return 0; }
|
static int DecoderThread_start(void *p) { ((MovieTexture_FFMpeg *)(p))->DecoderThread(); return 0; }
|
||||||
void DecoderThread();
|
void DecoderThread();
|
||||||
RageThread m_DecoderThread;
|
RageThread m_DecoderThread;
|
||||||
@@ -77,6 +82,7 @@ private:
|
|||||||
void DestroyTexture();
|
void DestroyTexture();
|
||||||
void StartThread();
|
void StartThread();
|
||||||
void StopThread();
|
void StopThread();
|
||||||
|
bool RunDecode();
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user