Remove singlethreaded, old ffmpeg decoding code.
This commit is contained in:
@@ -150,54 +150,14 @@ void MovieDecoder_FFMpeg::Init()
|
||||
{
|
||||
m_iEOF = 0;
|
||||
m_fTimestamp = 0;
|
||||
m_fLastFrameDelay = 0;
|
||||
m_iFrameNumber = 0;
|
||||
m_totalFrames = 0;
|
||||
m_fTimestampOffset = 0;
|
||||
m_fLastFrame = 0;
|
||||
m_swsctx = nullptr;
|
||||
m_avioContext = nullptr;
|
||||
m_buffer = nullptr;
|
||||
}
|
||||
|
||||
/* 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::DecodeFrame( float fTargetTime )
|
||||
{
|
||||
//hack to filter out stuttering
|
||||
if(fTargetTime<m_fLastFrame)
|
||||
{
|
||||
fTargetTime=m_fLastFrame;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_fLastFrame=fTargetTime;
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int ret = DecodePacket( fTargetTime );
|
||||
|
||||
if( ret == 1 )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if( ret == -1 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if( ret == 0 && m_iEOF > 0 )
|
||||
{
|
||||
return 0; /* eof */
|
||||
}
|
||||
ASSERT( ret == 0 );
|
||||
ret = ReadPacket();
|
||||
if( ret < 0 )
|
||||
{
|
||||
return ret; /* error */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float MovieDecoder_FFMpeg::GetTimestamp() const
|
||||
{
|
||||
// Always display the first frame.
|
||||
@@ -233,11 +193,6 @@ bool MovieDecoder_FFMpeg::IsCurrentFrameReady() {
|
||||
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.
|
||||
@@ -402,128 +357,6 @@ int MovieDecoder_FFMpeg::DecodePacketInBuffer() {
|
||||
return 0; /* packet done */
|
||||
}
|
||||
|
||||
|
||||
/* Read a packet. Return -1 on error, 0 on EOF, 1 on OK. */
|
||||
int MovieDecoder_FFMpeg::ReadPacket()
|
||||
{
|
||||
if( m_iEOF > 0 )
|
||||
return 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if( m_iCurrentPacketOffset != -1 )
|
||||
{
|
||||
m_iCurrentPacketOffset = -1;
|
||||
avcodec::av_packet_unref( &m_Packet );
|
||||
}
|
||||
|
||||
int ret = avcodec::av_read_frame( m_fctx, &m_Packet );
|
||||
/* XXX: why is avformat returning AVERROR_NOMEM on EOF? */
|
||||
if( ret < 0 )
|
||||
{
|
||||
/* EOF. */
|
||||
m_iEOF = 1;
|
||||
m_Packet.size = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( m_Packet.stream_index == m_pStream->index )
|
||||
{
|
||||
m_iCurrentPacketOffset = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* It's not for the video stream; ignore it. */
|
||||
avcodec::av_packet_unref( &m_Packet );
|
||||
}
|
||||
}
|
||||
|
||||
/* 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( float fTargetTime )
|
||||
{
|
||||
if( m_iEOF == 0 && m_iCurrentPacketOffset == -1 )
|
||||
return 0; /* no packet */
|
||||
|
||||
while( m_iEOF == 1 || (m_iEOF == 0 && m_iCurrentPacketOffset < m_Packet.size) )
|
||||
{
|
||||
/* If we have no data on the first frame, just return EOF; passing an empty packet
|
||||
* to avcodec_decode_video in this case is crashing it. However, passing an empty
|
||||
* packet is normal with B-frames, to flush. This may be unnecessary in newer
|
||||
* versions of avcodec, but I'm waiting until a new stable release to upgrade. */
|
||||
if( m_Packet.size == 0 && m_iFrameNumber == -1 )
|
||||
return 0; /* eof */
|
||||
|
||||
bool bSkipThisFrame =
|
||||
fTargetTime != -1 &&
|
||||
GetTimestamp() + GetFrameDuration() < fTargetTime &&
|
||||
(m_pStreamCodec->frame_number % 2) == 0;
|
||||
|
||||
int iGotFrame;
|
||||
int len;
|
||||
/* Hack: we need to send size = 0 to flush frames at the end, but we have
|
||||
* to give it a buffer to read from since it tries to read anyway. */
|
||||
m_Packet.data = m_Packet.size ? m_Packet.data : nullptr;
|
||||
len = m_Packet.size;
|
||||
avcodec::avcodec_send_packet(m_pStreamCodec, &m_Packet);
|
||||
iGotFrame = !avcodec::avcodec_receive_frame(m_pStreamCodec, m_Frame);
|
||||
|
||||
if( len < 0 )
|
||||
{
|
||||
LOG->Warn("avcodec_decode_video2: %i", len);
|
||||
return -1; // XXX
|
||||
}
|
||||
|
||||
m_iCurrentPacketOffset += len;
|
||||
|
||||
if( !iGotFrame )
|
||||
{
|
||||
if( m_iEOF == 1 )
|
||||
m_iEOF = 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( m_Frame->pkt_dts != AV_NOPTS_VALUE )
|
||||
{
|
||||
m_fTimestamp = (float) (m_Frame->pkt_dts * av_q2d(m_pStream->time_base));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the timestamp is zero, this frame is to be played at the
|
||||
* time of the last frame plus the length of the last frame. */
|
||||
m_fTimestamp += m_fLastFrameDelay;
|
||||
}
|
||||
|
||||
/* Length of this frame: */
|
||||
m_fLastFrameDelay = (float) av_q2d(m_pStream->time_base);
|
||||
m_fLastFrameDelay += m_Frame->repeat_pict * (m_fLastFrameDelay * 0.5f);
|
||||
|
||||
++m_iFrameNumber;
|
||||
|
||||
if( m_iFrameNumber == 0 )
|
||||
{
|
||||
/* Some videos start with a timestamp other than 0. I think this is used
|
||||
* when audio starts before the video. We don't want to honor that, since
|
||||
* the DShow renderer doesn't and we don't want to break sync compatibility. */
|
||||
const float expect = 0;
|
||||
const float actual = m_fTimestamp;
|
||||
if( actual - expect > 0 )
|
||||
{
|
||||
LOG->Trace("Expect %f, got %f -> %f", expect, actual, actual - expect );
|
||||
m_fTimestampOffset = actual - expect;
|
||||
}
|
||||
}
|
||||
|
||||
if( bSkipThisFrame )
|
||||
continue;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0; /* packet done */
|
||||
}
|
||||
|
||||
bool MovieDecoder_FFMpeg::SkipNextFrame() {
|
||||
if (m_iFrameNumber > (m_totalFrames - 1)) {
|
||||
return true;
|
||||
|
||||
@@ -100,7 +100,6 @@ public:
|
||||
RageSurface *CreateCompatibleSurface( int iTextureWidth, int iTextureHeight, bool bPreferHighColor, MovieDecoderPixelFormatYCbCr &fmtout );
|
||||
|
||||
float GetTimestamp() const;
|
||||
float GetFrameDuration() const;
|
||||
|
||||
void Cancel() { cancel = true; };
|
||||
|
||||
@@ -110,8 +109,6 @@ public:
|
||||
private:
|
||||
void Init();
|
||||
RString OpenCodec();
|
||||
int ReadPacket();
|
||||
int DecodePacket( float fTargetTime );
|
||||
|
||||
// Read a packet and send it to our frame data buffer.
|
||||
// Returns -2 on cancel, -1 on error, 0 on EOF, 1 on OK.
|
||||
@@ -130,7 +127,6 @@ private:
|
||||
avcodec::AVFormatContext *m_fctx;
|
||||
float m_fTimestamp;
|
||||
float m_fTimestampOffset;
|
||||
float m_fLastFrameDelay;
|
||||
int m_iFrameNumber;
|
||||
int m_totalFrames; // Total number of frames in the movie.
|
||||
|
||||
@@ -140,13 +136,10 @@ private:
|
||||
// The movie buffer.
|
||||
std::vector<FrameHolder> m_FrameBuffer;
|
||||
|
||||
avcodec::AVPacket m_Packet;
|
||||
int m_iCurrentPacketOffset;
|
||||
float m_fLastFrame;
|
||||
|
||||
/* 0 = no EOF
|
||||
* 1 = EOF from ReadPacket
|
||||
* 2 = EOF from ReadPacket and DecodePacket */
|
||||
// 0 = no EOF
|
||||
// 1 = EOF while decoding
|
||||
int m_iEOF;
|
||||
|
||||
// If true, received a cancel signal from the MovieTexture.
|
||||
|
||||
@@ -34,11 +34,8 @@ MovieTexture_Generic::MovieTexture_Generic( RageTextureID ID, MovieDecoder *pDec
|
||||
m_bLoop = true;
|
||||
m_pSurface = nullptr;
|
||||
m_pTextureLock = nullptr;
|
||||
m_ImageWaiting = FRAME_NONE;
|
||||
m_fRate = 1;
|
||||
m_bWantRewind = false;
|
||||
m_fClock = 0;
|
||||
m_bFrameSkipMode = false;
|
||||
m_pSprite = new Sprite;
|
||||
}
|
||||
|
||||
@@ -132,12 +129,6 @@ public:
|
||||
m_PixFmt = pixfmt;
|
||||
m_iSourceWidth = iWidth;
|
||||
m_iSourceHeight = iHeight;
|
||||
/* int iMaxSize = std::min( GetID().iMaxSize, DISPLAY->GetMaxTextureSize() );
|
||||
m_iImageWidth = std::min( m_iSourceWidth, iMaxSize );
|
||||
m_iImageHeight = std::min( m_iSourceHeight, iMaxSize );
|
||||
m_iTextureWidth = power_of_two( m_iImageWidth );
|
||||
m_iTextureHeight = power_of_two( m_iImageHeight );
|
||||
*/
|
||||
|
||||
m_iImageWidth = iImageWidth;
|
||||
m_iImageHeight = iImageHeight;
|
||||
@@ -315,62 +306,6 @@ void MovieTexture_Generic::CreateTexture()
|
||||
m_uTexHandle = DISPLAY->CreateTexture( pixfmt, m_pSurface, false );
|
||||
}
|
||||
|
||||
/* Handle decoding for a frame. Return true if a frame was decoded, false if not
|
||||
* (due to quit, error, EOF, etc). If true is returned, we'll be in FRAME_DECODED. */
|
||||
bool MovieTexture_Generic::DecodeFrame()
|
||||
{
|
||||
bool bTriedRewind = false;
|
||||
do
|
||||
{
|
||||
if( m_bWantRewind )
|
||||
{
|
||||
if( bTriedRewind )
|
||||
{
|
||||
LOG->Trace( "File \"%s\" looped more than once in one frame", GetID().filename.c_str() );
|
||||
return false;
|
||||
}
|
||||
m_bWantRewind = false;
|
||||
bTriedRewind = true;
|
||||
|
||||
/* When resetting the clock, set it back by the length of the last frame,
|
||||
* so it has a proper delay. */
|
||||
float fDelay = m_pDecoder->GetFrameDuration();
|
||||
|
||||
/* Restart. */
|
||||
m_pDecoder->Rewind();
|
||||
|
||||
m_fClock = -fDelay;
|
||||
}
|
||||
|
||||
/* Read a frame. */
|
||||
float fTargetTime = -1;
|
||||
if( m_bFrameSkipMode && m_fClock > m_pDecoder->GetTimestamp() )
|
||||
fTargetTime = m_fClock;
|
||||
|
||||
int ret = m_pDecoder->DecodeFrame( fTargetTime );
|
||||
if( ret == -1 )
|
||||
return false;
|
||||
|
||||
if( m_bWantRewind && m_pDecoder->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;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We got a frame. */
|
||||
} while( m_bWantRewind );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* <= 0 if it's time for the next frame to display
|
||||
|
||||
@@ -37,18 +37,6 @@ public:
|
||||
// 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.
|
||||
*
|
||||
* If we're lagging behind the video, fTargetTime will be the target
|
||||
* timestamp. The decoder may skip frames to catch up. On return,
|
||||
* the current timestamp must be <= fTargetTime.
|
||||
*
|
||||
* Otherwise, fTargetTime will be -1, and the next frame should be
|
||||
* decoded; skip frames only if necessary to recover from errors.
|
||||
*/
|
||||
virtual int DecodeFrame( float fTargetTime ) = 0;
|
||||
|
||||
/*
|
||||
* Get the currently-decoded frame.
|
||||
*/
|
||||
@@ -88,9 +76,6 @@ public:
|
||||
|
||||
// Cancels the decoding of the movie.
|
||||
virtual void Cancel() = 0;
|
||||
|
||||
/* Get the duration, in seconds, to display the current frame. */
|
||||
virtual float GetFrameDuration() const = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -124,17 +109,10 @@ private:
|
||||
std::unique_ptr<std::thread> decoding_thread;
|
||||
|
||||
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 */
|
||||
} m_ImageWaiting;
|
||||
bool m_bLoop;
|
||||
|
||||
// If true, halts all decoding and display.
|
||||
bool m_failure = false;
|
||||
bool m_bWantRewind;
|
||||
|
||||
enum State { DECODER_QUIT, DECODER_RUNNING } m_State;
|
||||
|
||||
std::uintptr_t m_uTexHandle;
|
||||
RageTextureRenderTarget *m_pRenderTarget;
|
||||
@@ -147,7 +125,6 @@ private:
|
||||
|
||||
/* The time the movie is actually at: */
|
||||
float m_fClock;
|
||||
bool m_bFrameSkipMode;
|
||||
|
||||
void UpdateFrame();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user