Add DecodeNextFrame and DecodeMovie functions to populate the
FrameBuffer.
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
static void FixLilEndian()
|
static void FixLilEndian()
|
||||||
{
|
{
|
||||||
@@ -213,11 +214,71 @@ float MovieDecoder_FFMpeg::GetTimestamp() const
|
|||||||
return m_fTimestamp - m_fTimestampOffset;
|
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
|
float MovieDecoder_FFMpeg::GetFrameDuration() const
|
||||||
{
|
{
|
||||||
return m_fLastFrameDelay;
|
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()
|
int MovieDecoder_FFMpeg::SendPacketToBuffer()
|
||||||
{
|
{
|
||||||
if (cancel) {
|
if (cancel) {
|
||||||
|
|||||||
@@ -73,6 +73,23 @@ public:
|
|||||||
void GetFrame( RageSurface *pOut );
|
void GetFrame( RageSurface *pOut );
|
||||||
int DecodeFrame( float fTargetTime );
|
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 GetWidth() const { return m_pStreamCodec->width; }
|
||||||
int GetHeight() const { return m_pStreamCodec->height; }
|
int GetHeight() const { return m_pStreamCodec->height; }
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,14 @@ public:
|
|||||||
virtual void Close() = 0;
|
virtual void Close() = 0;
|
||||||
virtual void Rewind() = 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.
|
* Decode a frame. Return 1 on success, 0 on EOF, -1 on fatal error.
|
||||||
*
|
*
|
||||||
@@ -95,6 +103,10 @@ public:
|
|||||||
virtual void Reload();
|
virtual void Reload();
|
||||||
|
|
||||||
virtual void SetPosition( float fSeconds );
|
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 UpdateMovie( float fSeconds );
|
||||||
virtual void SetPlaybackRate( float fRate ) { m_fRate = fRate; }
|
virtual void SetPlaybackRate( float fRate ) { m_fRate = fRate; }
|
||||||
void SetLooping( bool bLooping=true ) { m_bLoop = bLooping; }
|
void SetLooping( bool bLooping=true ) { m_bLoop = bLooping; }
|
||||||
|
|||||||
Reference in New Issue
Block a user