From ed2610cf1a89e48292959a23da74a6ce078e100c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 20 Feb 2021 15:11:48 -0800 Subject: [PATCH 1/3] Atrac: Update to latest FFmpeg packet pump. --- Core/HLE/sceAtrac.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index d2d35720a826..4fb30b2211dc 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -556,7 +556,27 @@ struct Atrac { } int got_frame = 0; +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) + if (packet_->size != 0) { + int err = avcodec_send_packet(codecCtx_, packet_); + if (err < 0) { + ERROR_LOG_REPORT(ME, "avcodec_send_packet: Error decoding audio %d / %08x", err, err); + failedDecode_ = true; + return ATDECODE_FAILED; + } + } + + int err = avcodec_receive_frame(codecCtx_, frame_); + int bytes_read = 0; + if (err >= 0) { + bytes_read = frame_->pkt_size; + got_frame = 1; + } else if (err != AVERROR(EAGAIN)) { + bytes_read = err; + } +#else int bytes_read = avcodec_decode_audio4(codecCtx_, frame_, &got_frame, packet_); +#endif #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100) av_packet_unref(packet_); #else From d8e3bae2da1a81dc821ed2e0c01f28c5673b1584 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 20 Feb 2021 15:12:37 -0800 Subject: [PATCH 2/3] Mpeg: Prevent sending flush packets to decode. --- Core/HLE/sceMpeg.cpp | 3 ++- Core/HW/MediaEngine.cpp | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index 3701f08a476a..37e500ebb9db 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -994,7 +994,8 @@ static bool decodePmpVideo(PSPPointer ringbuffer, u32 pmpctxA // decode video frame #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) - avcodec_send_packet(pCodecCtx, &packet); + if (packet.size != 0) + avcodec_send_packet(pCodecCtx, &packet); int len = avcodec_receive_frame(pCodecCtx, pFrame); if (len == 0) { len = pFrame->pkt_size; diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp index 4f7b213e5d85..e162ffd72553 100644 --- a/Core/HW/MediaEngine.cpp +++ b/Core/HW/MediaEngine.cpp @@ -314,7 +314,7 @@ bool MediaEngine::openContext(bool keepReadPos) { if (!SetupStreams()) { // Fallback to old behavior. Reads too much and corrupts when game doesn't read fast enough. - // SetupStreams should work for newer FFmpeg 3.1+ now. + // SetupStreams sometimes work for newer FFmpeg 3.1+ now, but sometimes framerate is missing. WARN_LOG_REPORT_ONCE(setupStreams, ME, "Failed to read valid video stream data from header"); if (avformat_find_stream_info(m_pFormatCtx, nullptr) < 0) { closeContext(); @@ -677,7 +677,8 @@ bool MediaEngine::stepVideo(int videoPixelMode, bool skipFrame) { #endif #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) - avcodec_send_packet(m_pCodecCtx, &packet); + if (packet.size != 0) + avcodec_send_packet(m_pCodecCtx, &packet); int result = avcodec_receive_frame(m_pCodecCtx, m_pFrame); if (result == 0) { result = m_pFrame->pkt_size; From 9d031caa9d8b34d61146f07e3521fb403382e34f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 20 Feb 2021 15:33:45 -0800 Subject: [PATCH 3/3] Mpeg: Assume 29.97 if bad frame rate returned. FFmpeg 3.1+ reads the frame rate only into private data, and can only expose it publicly when using the find stream info API that reads too far ahead. --- Core/HW/MediaEngine.cpp | 24 ++++++++++++++++++++---- Core/HW/MediaEngine.h | 3 ++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp index e162ffd72553..5b64f4a07ae2 100644 --- a/Core/HW/MediaEngine.cpp +++ b/Core/HW/MediaEngine.cpp @@ -138,7 +138,6 @@ MediaEngine::MediaEngine(): m_pdata(0) { m_desHeight = 0; m_decodingsize = 0; m_bufSize = 0x2000; - m_videopts = 0; m_pdata = 0; m_demux = 0; m_audioContext = 0; @@ -171,7 +170,7 @@ void MediaEngine::closeMedia() { } void MediaEngine::DoState(PointerWrap &p) { - auto s = p.Section("MediaEngine", 1, 6); + auto s = p.Section("MediaEngine", 1, 7); if (!s) return; @@ -213,6 +212,11 @@ void MediaEngine::DoState(PointerWrap &p) { m_demux->DoState(p); Do(p, m_videopts); + if (s >= 7) { + Do(p, m_lastPts); + } else { + m_lastPts = m_videopts; + } Do(p, m_audiopts); if (s >= 2) { @@ -390,6 +394,7 @@ bool MediaEngine::loadStream(const u8 *buffer, int readSize, int RingbufferSize) closeMedia(); m_videopts = 0; + m_lastPts = -1; m_audiopts = 0; m_ringbuffersize = RingbufferSize; m_pdata = new BufferQueue(RingbufferSize + 2048); @@ -713,10 +718,21 @@ bool MediaEngine::stepVideo(int videoPixelMode, bool skipFrame) { int64_t bestPts = av_frame_get_best_effort_timestamp(m_pFrame); int64_t ptsDuration = av_frame_get_pkt_duration(m_pFrame); #endif - if (bestPts != AV_NOPTS_VALUE) + if (ptsDuration == 0) { + if (m_lastPts == bestPts - m_firstTimeStamp || bestPts == AV_NOPTS_VALUE) { + // TODO: Assuming 29.97 if missing. + m_videopts += 3003; + } else { + m_videopts = bestPts - m_firstTimeStamp; + m_lastPts = m_videopts; + } + } else if (bestPts != AV_NOPTS_VALUE) { m_videopts = bestPts + ptsDuration - m_firstTimeStamp; - else + m_lastPts = m_videopts; + } else { m_videopts += ptsDuration; + m_lastPts = m_videopts; + } bGetFrame = true; } if (result <= 0 && dataEnd) { diff --git a/Core/HW/MediaEngine.h b/Core/HW/MediaEngine.h index 7e9bc2c585f9..aaef4ae37797 100644 --- a/Core/HW/MediaEngine.h +++ b/Core/HW/MediaEngine.h @@ -124,7 +124,8 @@ class MediaEngine int m_desHeight; int m_decodingsize; int m_bufSize; - s64 m_videopts; + s64 m_videopts = 0; + s64 m_lastPts = -1; BufferQueue *m_pdata; MpegDemux *m_demux;