Add DecodeNextFrame and DecodeMovie functions to populate the
FrameBuffer.
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <thread>
|
||||
|
||||
static void FixLilEndian()
|
||||
{
|
||||
@@ -213,11 +214,71 @@ float MovieDecoder_FFMpeg::GetTimestamp() const
|
||||
return m_fTimestamp - m_fTimestampOffset;
|
||||
}
|
||||
|
||||
bool MovieDecoder_FFMpeg::IsCurrentFrameReady() {
|
||||
std::lock_guard<std::mutex>(m_FrameBuffer[m_iFrameNumber].lock);
|
||||
if (!m_FrameBuffer[m_iFrameNumber].decoded) {
|
||||
LOG->Info("Frame %i not decoded, total frames: %i", m_iFrameNumber, m_totalFrames);
|
||||
}
|
||||
return m_FrameBuffer[m_iFrameNumber].decoded;
|
||||
}
|
||||
|
||||
float MovieDecoder_FFMpeg::GetFrameDuration() const
|
||||
{
|
||||
return m_fLastFrameDelay;
|
||||
}
|
||||
|
||||
int MovieDecoder_FFMpeg::DecodeNextFrame()
|
||||
{
|
||||
// Add in a new FrameBuffer entry, and lock it immediately.
|
||||
m_FrameBuffer.push_back(FrameHolder());
|
||||
std::lock_guard<std::mutex>(m_FrameBuffer.back().lock);
|
||||
int status = SendPacketToBuffer();
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
status = DecodePacketInBuffer();
|
||||
if (firstFrame) {
|
||||
firstFrame = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int MovieDecoder_FFMpeg::DecodeMovie()
|
||||
{
|
||||
using std::chrono::operator""ms;
|
||||
|
||||
// The first frame expected to be decoded and drawn already,
|
||||
// that is handled by MovieTexture_Generic::Init().
|
||||
int frameNum = 0;
|
||||
while (!m_iEOF) {
|
||||
// This wake up time could be tied to the RageTimer, but as it doesn't
|
||||
// need to sync with other parts of ITGm, using chrono is fine.
|
||||
// The 1ms time here is arbitrary, and means that the game will decode
|
||||
// at a maximum speed of 1 frame per ms (or 1000 fps).
|
||||
auto wake_up = std::chrono::steady_clock::now() + 1ms;
|
||||
|
||||
int status = DecodeNextFrame();
|
||||
|
||||
// If cancelled (quitting a song, scrolling the banner), or fatal error,
|
||||
// stop decoding.
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
frameNum++;
|
||||
|
||||
// This means when opening the file, less frames were detected than
|
||||
// there actually are. Increment to keep up so we don't end the video
|
||||
// early during display.
|
||||
if (frameNum - 1 > m_totalFrames) {
|
||||
m_totalFrames++;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_until(wake_up);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MovieDecoder_FFMpeg::SendPacketToBuffer()
|
||||
{
|
||||
if (cancel) {
|
||||
|
||||
@@ -73,6 +73,23 @@ public:
|
||||
void GetFrame( RageSurface *pOut );
|
||||
int DecodeFrame( float fTargetTime );
|
||||
|
||||
// Decode a single frame. Return -2 on cancel, -1 on error, 0 on EOF, 1 if we have a frame.
|
||||
int DecodeNextFrame();
|
||||
|
||||
// Decode the entire movie.
|
||||
// If we let this decode as fast as possible, it could come at the expense
|
||||
// of gameplay performance. Since dropping frames is undesirable, an
|
||||
// artificial rate limit is introduced.
|
||||
//
|
||||
// Given that most movies will display at 30fps or 60fps, decoding at a
|
||||
// speed of 1000fps should be more than sufficient to ensure we never
|
||||
// run behind. This rate limiting is only needed in case itgmania is
|
||||
// running on a low performance machine, or the movie is REALLY long.
|
||||
//
|
||||
// Returns 0 on success, -1 on fatal error, -2 on cancel.
|
||||
int DecodeMovie();
|
||||
bool IsCurrentFrameReady();
|
||||
|
||||
int GetWidth() const { return m_pStreamCodec->width; }
|
||||
int GetHeight() const { return m_pStreamCodec->height; }
|
||||
|
||||
|
||||
@@ -28,6 +28,14 @@ public:
|
||||
virtual void Close() = 0;
|
||||
virtual void Rewind() = 0;
|
||||
|
||||
// Decode the next frame.
|
||||
// Return 1 on success, 0 on EOF, -1 on fatal error, -2 on cancel.
|
||||
virtual int DecodeNextFrame() = 0;
|
||||
virtual int DecodeMovie() = 0;
|
||||
|
||||
// Returns true if the frame we want to display has been decoded already.
|
||||
virtual bool IsCurrentFrameReady() = 0;
|
||||
|
||||
/*
|
||||
* Decode a frame. Return 1 on success, 0 on EOF, -1 on fatal error.
|
||||
*
|
||||
@@ -95,6 +103,10 @@ public:
|
||||
virtual void Reload();
|
||||
|
||||
virtual void SetPosition( float fSeconds );
|
||||
|
||||
// UpdateMovie tells the MovieTexture to update the displayed frame based
|
||||
// on fSeconds passed in. (e.g., 5.9 input means show the frame that should
|
||||
// be displayed 5.9 seconds into the movie).
|
||||
virtual void UpdateMovie( float fSeconds );
|
||||
virtual void SetPlaybackRate( float fRate ) { m_fRate = fRate; }
|
||||
void SetLooping( bool bLooping=true ) { m_bLoop = bLooping; }
|
||||
|
||||
Reference in New Issue
Block a user