Remove singlethreaded, old ffmpeg decoding code.
This commit is contained in:
@@ -150,54 +150,14 @@ void MovieDecoder_FFMpeg::Init()
|
|||||||
{
|
{
|
||||||
m_iEOF = 0;
|
m_iEOF = 0;
|
||||||
m_fTimestamp = 0;
|
m_fTimestamp = 0;
|
||||||
m_fLastFrameDelay = 0;
|
|
||||||
m_iFrameNumber = 0;
|
m_iFrameNumber = 0;
|
||||||
m_totalFrames = 0;
|
m_totalFrames = 0;
|
||||||
m_fTimestampOffset = 0;
|
m_fTimestampOffset = 0;
|
||||||
m_fLastFrame = 0;
|
|
||||||
m_swsctx = nullptr;
|
m_swsctx = nullptr;
|
||||||
m_avioContext = nullptr;
|
m_avioContext = nullptr;
|
||||||
m_buffer = 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
|
float MovieDecoder_FFMpeg::GetTimestamp() const
|
||||||
{
|
{
|
||||||
// Always display the first frame.
|
// Always display the first frame.
|
||||||
@@ -233,11 +193,6 @@ bool MovieDecoder_FFMpeg::IsCurrentFrameReady() {
|
|||||||
return m_FrameBuffer[m_iFrameNumber].decoded;
|
return m_FrameBuffer[m_iFrameNumber].decoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
float MovieDecoder_FFMpeg::GetFrameDuration() const
|
|
||||||
{
|
|
||||||
return m_fLastFrameDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
int MovieDecoder_FFMpeg::DecodeNextFrame()
|
int MovieDecoder_FFMpeg::DecodeNextFrame()
|
||||||
{
|
{
|
||||||
// Add in a new FrameBuffer entry, and lock it immediately.
|
// Add in a new FrameBuffer entry, and lock it immediately.
|
||||||
@@ -402,128 +357,6 @@ int MovieDecoder_FFMpeg::DecodePacketInBuffer() {
|
|||||||
return 0; /* packet done */
|
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() {
|
bool MovieDecoder_FFMpeg::SkipNextFrame() {
|
||||||
if (m_iFrameNumber > (m_totalFrames - 1)) {
|
if (m_iFrameNumber > (m_totalFrames - 1)) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -100,7 +100,6 @@ public:
|
|||||||
RageSurface *CreateCompatibleSurface( int iTextureWidth, int iTextureHeight, bool bPreferHighColor, MovieDecoderPixelFormatYCbCr &fmtout );
|
RageSurface *CreateCompatibleSurface( int iTextureWidth, int iTextureHeight, bool bPreferHighColor, MovieDecoderPixelFormatYCbCr &fmtout );
|
||||||
|
|
||||||
float GetTimestamp() const;
|
float GetTimestamp() const;
|
||||||
float GetFrameDuration() const;
|
|
||||||
|
|
||||||
void Cancel() { cancel = true; };
|
void Cancel() { cancel = true; };
|
||||||
|
|
||||||
@@ -110,8 +109,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
void Init();
|
void Init();
|
||||||
RString OpenCodec();
|
RString OpenCodec();
|
||||||
int ReadPacket();
|
|
||||||
int DecodePacket( float fTargetTime );
|
|
||||||
|
|
||||||
// Read a packet and send it to our frame data buffer.
|
// Read a packet and send it to our frame data buffer.
|
||||||
// Returns -2 on cancel, -1 on error, 0 on EOF, 1 on OK.
|
// Returns -2 on cancel, -1 on error, 0 on EOF, 1 on OK.
|
||||||
@@ -130,7 +127,6 @@ private:
|
|||||||
avcodec::AVFormatContext *m_fctx;
|
avcodec::AVFormatContext *m_fctx;
|
||||||
float m_fTimestamp;
|
float m_fTimestamp;
|
||||||
float m_fTimestampOffset;
|
float m_fTimestampOffset;
|
||||||
float m_fLastFrameDelay;
|
|
||||||
int m_iFrameNumber;
|
int m_iFrameNumber;
|
||||||
int m_totalFrames; // Total number of frames in the movie.
|
int m_totalFrames; // Total number of frames in the movie.
|
||||||
|
|
||||||
@@ -140,13 +136,10 @@ private:
|
|||||||
// The movie buffer.
|
// The movie buffer.
|
||||||
std::vector<FrameHolder> m_FrameBuffer;
|
std::vector<FrameHolder> m_FrameBuffer;
|
||||||
|
|
||||||
avcodec::AVPacket m_Packet;
|
|
||||||
int m_iCurrentPacketOffset;
|
int m_iCurrentPacketOffset;
|
||||||
float m_fLastFrame;
|
|
||||||
|
|
||||||
/* 0 = no EOF
|
// 0 = no EOF
|
||||||
* 1 = EOF from ReadPacket
|
// 1 = EOF while decoding
|
||||||
* 2 = EOF from ReadPacket and DecodePacket */
|
|
||||||
int m_iEOF;
|
int m_iEOF;
|
||||||
|
|
||||||
// If true, received a cancel signal from the MovieTexture.
|
// 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_bLoop = true;
|
||||||
m_pSurface = nullptr;
|
m_pSurface = nullptr;
|
||||||
m_pTextureLock = nullptr;
|
m_pTextureLock = nullptr;
|
||||||
m_ImageWaiting = FRAME_NONE;
|
|
||||||
m_fRate = 1;
|
m_fRate = 1;
|
||||||
m_bWantRewind = false;
|
|
||||||
m_fClock = 0;
|
m_fClock = 0;
|
||||||
m_bFrameSkipMode = false;
|
|
||||||
m_pSprite = new Sprite;
|
m_pSprite = new Sprite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,12 +129,6 @@ public:
|
|||||||
m_PixFmt = pixfmt;
|
m_PixFmt = pixfmt;
|
||||||
m_iSourceWidth = iWidth;
|
m_iSourceWidth = iWidth;
|
||||||
m_iSourceHeight = iHeight;
|
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_iImageWidth = iImageWidth;
|
||||||
m_iImageHeight = iImageHeight;
|
m_iImageHeight = iImageHeight;
|
||||||
@@ -315,62 +306,6 @@ void MovieTexture_Generic::CreateTexture()
|
|||||||
m_uTexHandle = DISPLAY->CreateTexture( pixfmt, m_pSurface, false );
|
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:
|
* Returns:
|
||||||
* <= 0 if it's time for the next frame to display
|
* <= 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.
|
// Returns true if the frame we want to display has been decoded already.
|
||||||
virtual bool IsCurrentFrameReady() = 0;
|
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.
|
* Get the currently-decoded frame.
|
||||||
*/
|
*/
|
||||||
@@ -88,9 +76,6 @@ public:
|
|||||||
|
|
||||||
// Cancels the decoding of the movie.
|
// Cancels the decoding of the movie.
|
||||||
virtual void Cancel() = 0;
|
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;
|
std::unique_ptr<std::thread> decoding_thread;
|
||||||
|
|
||||||
float m_fRate;
|
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;
|
bool m_bLoop;
|
||||||
|
|
||||||
// If true, halts all decoding and display.
|
// If true, halts all decoding and display.
|
||||||
bool m_failure = false;
|
bool m_failure = false;
|
||||||
bool m_bWantRewind;
|
|
||||||
|
|
||||||
enum State { DECODER_QUIT, DECODER_RUNNING } m_State;
|
|
||||||
|
|
||||||
std::uintptr_t m_uTexHandle;
|
std::uintptr_t m_uTexHandle;
|
||||||
RageTextureRenderTarget *m_pRenderTarget;
|
RageTextureRenderTarget *m_pRenderTarget;
|
||||||
@@ -147,7 +125,6 @@ private:
|
|||||||
|
|
||||||
/* The time the movie is actually at: */
|
/* The time the movie is actually at: */
|
||||||
float m_fClock;
|
float m_fClock;
|
||||||
bool m_bFrameSkipMode;
|
|
||||||
|
|
||||||
void UpdateFrame();
|
void UpdateFrame();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user