Remove singlethreaded, old ffmpeg decoding code.

This commit is contained in:
Brandon W
2024-08-10 15:44:06 -07:00
committed by teejusb
parent 10125caa7f
commit d74ad50707
4 changed files with 2 additions and 264 deletions
@@ -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;
+2 -9
View File
@@ -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();