From eb8f76023ef8d97fbd00a62506ce1dfb928d8655 Mon Sep 17 00:00:00 2001 From: Brandon W Date: Thu, 8 Aug 2024 22:02:07 -0400 Subject: [PATCH] Allow frames that didn't decode to skip. --- src/arch/MovieTexture/MovieTexture_FFMpeg.cpp | 35 ++++++++++++++++--- src/arch/MovieTexture/MovieTexture_FFMpeg.h | 5 +++ .../MovieTexture/MovieTexture_Generic.cpp | 4 +++ src/arch/MovieTexture/MovieTexture_Generic.h | 3 ++ 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/arch/MovieTexture/MovieTexture_FFMpeg.cpp b/src/arch/MovieTexture/MovieTexture_FFMpeg.cpp index b61d8faf9e..7772442f3e 100644 --- a/src/arch/MovieTexture/MovieTexture_FFMpeg.cpp +++ b/src/arch/MovieTexture/MovieTexture_FFMpeg.cpp @@ -223,8 +223,12 @@ bool MovieDecoder_FFMpeg::IsCurrentFrameReady() { } std::lock_guard(m_FrameBuffer[m_iFrameNumber].lock); + if (m_FrameBuffer[m_iFrameNumber].skip) { + LOG->Info("Frame %i not decoded, skipping...", m_iFrameNumber); + return true; + } if (!m_FrameBuffer[m_iFrameNumber].decoded) { - LOG->Info("Frame %i not decoded, total frames: %i", m_iFrameNumber, m_totalFrames); + LOG->Info("Frame %i not decoded and was not skipped, total frames: %i", m_iFrameNumber, m_totalFrames); } return m_FrameBuffer[m_iFrameNumber].decoded; } @@ -344,19 +348,22 @@ int MovieDecoder_FFMpeg::DecodePacketInBuffer() { m_FrameBuffer.back().packet.data = m_FrameBuffer.back().packet.size ? m_FrameBuffer.back().packet.data : nullptr; int len = m_FrameBuffer.back().packet.size; avcodec::avcodec_send_packet(m_pStreamCodec, &m_FrameBuffer.back().packet); - int iGotFrame = !avcodec::avcodec_receive_frame(m_pStreamCodec, &m_FrameBuffer.back().frame); + int avcodec_return = avcodec::avcodec_receive_frame(m_pStreamCodec, &m_FrameBuffer.back().frame); if (len < 0) { - LOG->Warn("avcodec_decode_video2: %i", len); + LOG->Warn("avcodec_decode_video2 fatal error, packet size negative: %i", len); return -1; } m_iCurrentPacketOffset += len; - if (!iGotFrame) + if (avcodec_return != 0) { - LOG->Warn("Frame number %i not successfully decoded into buffer.", static_cast(m_FrameBuffer.size() - 1)); + LOG->Warn( + "Frame number %i not successfully decoded into buffer. avcodec_receive_frame status: %i", + static_cast(m_FrameBuffer.size() - 1), + avcodec_return); continue; } @@ -385,6 +392,13 @@ int MovieDecoder_FFMpeg::DecodePacketInBuffer() { return 1; } + // This if statement means the packet did not decode correctly. This is not + // necessarily fatal for video playback, but out of caution the frame should + // be skipped. + if (!m_FrameBuffer.back().decoded) { + m_FrameBuffer.back().skip = true; + } + return 0; /* packet done */ } @@ -510,6 +524,17 @@ int MovieDecoder_FFMpeg::DecodePacket( float fTargetTime ) return 0; /* packet done */ } +bool MovieDecoder_FFMpeg::SkipNextFrame() { + if (m_iFrameNumber > (m_totalFrames - 1)) { + return true; + } + if (m_FrameBuffer[m_iFrameNumber].skip) { + m_iFrameNumber++; + return true; + } + return false; +} + bool MovieDecoder_FFMpeg::GetFrame(RageSurface* pSurface) { avcodec::AVFrame pict; diff --git a/src/arch/MovieTexture/MovieTexture_FFMpeg.h b/src/arch/MovieTexture/MovieTexture_FFMpeg.h index e2601a3c96..9d572c6df7 100644 --- a/src/arch/MovieTexture/MovieTexture_FFMpeg.h +++ b/src/arch/MovieTexture/MovieTexture_FFMpeg.h @@ -30,6 +30,7 @@ struct FrameHolder { float frameTimestamp; float frameDelay; bool decoded = false; + bool skip = false; std::mutex lock; // Protects the frame as it's being initialized. FrameHolder() = default; @@ -42,6 +43,7 @@ struct FrameHolder { frameTimestamp = fh.frameTimestamp; frameDelay = fh.frameDelay; decoded = fh.decoded; + skip = fh.skip; } }; @@ -102,6 +104,9 @@ public: void Cancel() { cancel = true; }; + // If the next frame to display had an issue decoding, skip it. + bool SkipNextFrame(); + private: void Init(); RString OpenCodec(); diff --git a/src/arch/MovieTexture/MovieTexture_Generic.cpp b/src/arch/MovieTexture/MovieTexture_Generic.cpp index eaf300ff6d..80e5cfdab2 100644 --- a/src/arch/MovieTexture/MovieTexture_Generic.cpp +++ b/src/arch/MovieTexture/MovieTexture_Generic.cpp @@ -407,6 +407,10 @@ void MovieTexture_Generic::UpdateFrame() /* Just in case we were invalidated: */ CreateTexture(); + if (m_pDecoder->SkipNextFrame()) { + return; + } + if(m_pTextureLock != nullptr) { std::uintptr_t iHandle = m_pTextureIntermediate != nullptr ? m_pTextureIntermediate->GetTexHandle(): this->GetTexHandle(); diff --git a/src/arch/MovieTexture/MovieTexture_Generic.h b/src/arch/MovieTexture/MovieTexture_Generic.h index 3dc08d937b..1521b96fb8 100644 --- a/src/arch/MovieTexture/MovieTexture_Generic.h +++ b/src/arch/MovieTexture/MovieTexture_Generic.h @@ -54,6 +54,9 @@ public: */ virtual bool GetFrame( RageSurface *pOut ) = 0; + // Returns true if the frame should be skipped. + virtual bool SkipNextFrame() = 0; + /* Return the dimensions of the image, in pixels (before aspect ratio * adjustments). */ virtual int GetWidth() const = 0;