From d69f243c32d65531a1a4d870a41a85435aafb6d3 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 21 Nov 2020 22:25:57 +0100 Subject: [PATCH] FrameDump: Start timing at 0 ticks when starting from boot --- Source/Core/VideoCommon/FrameDump.cpp | 28 ++++++++++++-------------- Source/Core/VideoCommon/FrameDump.h | 9 +++++---- Source/Core/VideoCommon/RenderBase.cpp | 13 ++++++++---- Source/Core/VideoCommon/RenderBase.h | 2 +- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/Source/Core/VideoCommon/FrameDump.cpp b/Source/Core/VideoCommon/FrameDump.cpp index 891aca59b8..4f0f2b581c 100644 --- a/Source/Core/VideoCommon/FrameDump.cpp +++ b/Source/Core/VideoCommon/FrameDump.cpp @@ -47,7 +47,7 @@ struct FrameDumpContext int width = 0; int height = 0; - u64 first_frame_ticks = 0; + u64 start_ticks = 0; u32 savestate_index = 0; bool gave_vfr_warning = false; @@ -111,7 +111,7 @@ std::string GetDumpPath(const std::string& extension, std::time_t time, u32 inde } // namespace -bool FrameDump::Start(int w, int h) +bool FrameDump::Start(int w, int h, u64 start_ticks) { if (IsStarted()) return true; @@ -120,16 +120,19 @@ bool FrameDump::Start(int w, int h) m_start_time = std::time(nullptr); m_file_index = 0; - return PrepareEncoding(w, h); + return PrepareEncoding(w, h, start_ticks, m_savestate_index); } -bool FrameDump::PrepareEncoding(int w, int h) +bool FrameDump::PrepareEncoding(int w, int h, u64 start_ticks, u32 savestate_index) { m_context = std::make_unique(); m_context->width = w; m_context->height = h; + m_context->start_ticks = start_ticks; + m_context->savestate_index = savestate_index; + InitAVCodec(); const bool success = CreateVideoFile(); if (!success) @@ -279,14 +282,8 @@ void FrameDump::AddFrame(const FrameData& frame) if (!IsStarted()) return; - if (IsFirstFrameInCurrentFile()) - { - m_context->first_frame_ticks = frame.state.ticks; - m_context->savestate_index = frame.state.savestate_index; - } - - // Calculate presentation timestamp from current ticks since first frame ticks. - const s64 pts = av_rescale_q(frame.state.ticks - m_context->first_frame_ticks, + // Calculate presentation timestamp from ticks since start. + const s64 pts = av_rescale_q(frame.state.ticks - m_context->start_ticks, AVRational{1, int(SystemTimers::GetTicksPerSecond())}, m_context->codec->time_base); @@ -300,7 +297,7 @@ void FrameDump::AddFrame(const FrameData& frame) else if (pts > m_context->last_pts + 1 && !m_context->gave_vfr_warning) { WARN_LOG_FMT(FRAMEDUMP, "PTS delta > 1. Resulting file will have variable frame rate. " - "Subsequent occurances will not be reported."); + "Subsequent occurrences will not be reported."); m_context->gave_vfr_warning = true; } } @@ -447,14 +444,15 @@ void FrameDump::CheckForConfigChange(const FrameData& frame) { Stop(); ++m_file_index; - PrepareEncoding(frame.width, frame.height); + PrepareEncoding(frame.width, frame.height, frame.state.ticks, frame.state.savestate_index); } } -FrameDump::FrameState FrameDump::FetchState(u64 ticks) const +FrameDump::FrameState FrameDump::FetchState(u64 ticks, int frame_number) const { FrameState state; state.ticks = ticks; + state.frame_number = frame_number; state.savestate_index = m_savestate_index; const auto time_base = GetTimeBaseForCurrentRefreshRate(); diff --git a/Source/Core/VideoCommon/FrameDump.h b/Source/Core/VideoCommon/FrameDump.h index 13c53d8a95..6f225b65d6 100644 --- a/Source/Core/VideoCommon/FrameDump.h +++ b/Source/Core/VideoCommon/FrameDump.h @@ -23,6 +23,7 @@ public: struct FrameState { u64 ticks = 0; + int frame_number = 0; u32 savestate_index = 0; int refresh_rate_num = 0; int refresh_rate_den = 0; @@ -37,16 +38,16 @@ public: FrameState state; }; - bool Start(int w, int h); + bool Start(int w, int h, u64 start_ticks); void AddFrame(const FrameData&); void Stop(); void DoState(PointerWrap&); bool IsStarted() const; - FrameState FetchState(u64 ticks) const; + FrameState FetchState(u64 ticks, int frame_number) const; private: bool IsFirstFrameInCurrentFile() const; - bool PrepareEncoding(int w, int h); + bool PrepareEncoding(int w, int h, u64 start_ticks, u32 savestate_index); bool CreateVideoFile(); void CloseVideoFile(); void CheckForConfigChange(const FrameData&); @@ -68,7 +69,7 @@ private: inline FrameDump::FrameDump() = default; inline FrameDump::~FrameDump() = default; -inline FrameDump::FrameState FrameDump::FetchState(u64 ticks) const +inline FrameDump::FrameState FrameDump::FetchState(u64 ticks, int frame_number) const { return {}; } diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 465bf25099..94379909ec 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -1290,7 +1290,7 @@ void Renderer::Swap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u6 DolphinAnalytics::Instance().ReportPerformanceInfo(std::move(perf_sample)); if (IsFrameDumping()) - DumpCurrentFrame(xfb_entry->texture.get(), xfb_rect, ticks); + DumpCurrentFrame(xfb_entry->texture.get(), xfb_rect, ticks, m_frame_count); // Begin new frame m_frame_count++; @@ -1380,7 +1380,8 @@ bool Renderer::IsFrameDumping() const } void Renderer::DumpCurrentFrame(const AbstractTexture* src_texture, - const MathUtil::Rectangle& src_rect, u64 ticks) + const MathUtil::Rectangle& src_rect, u64 ticks, + int frame_number) { int source_width = src_rect.GetWidth(); int source_height = src_rect.GetHeight(); @@ -1414,7 +1415,7 @@ void Renderer::DumpCurrentFrame(const AbstractTexture* src_texture, m_frame_dump_readback_texture->CopyFromTexture(src_texture, copy_rect, 0, 0, m_frame_dump_readback_texture->GetRect()); - m_last_frame_state = m_frame_dump.FetchState(ticks); + m_last_frame_state = m_frame_dump.FetchState(ticks, frame_number); m_frame_dump_needs_flush = true; } @@ -1619,7 +1620,11 @@ void Renderer::FrameDumpThreadFunc() bool Renderer::StartFrameDumpToFFMPEG(const FrameDump::FrameData& frame) { - return m_frame_dump.Start(frame.width, frame.height); + // If dumping started at boot, the start time must be set to the boot time to maintain audio sync. + // TODO: Perhaps we should care about this when starting dumping in the middle of emulation too, + // but it's less important there since the first frame to dump usually gets delivered quickly. + const u64 start_ticks = frame.state.frame_number == 0 ? 0 : frame.state.ticks; + return m_frame_dump.Start(frame.width, frame.height, start_ticks); } void Renderer::DumpFrameToFFMPEG(const FrameDump::FrameData& frame) diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 553bb7364b..91be0e358c 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -411,7 +411,7 @@ private: // Fills the frame dump staging texture with the current XFB texture. void DumpCurrentFrame(const AbstractTexture* src_texture, - const MathUtil::Rectangle& src_rect, u64 ticks); + const MathUtil::Rectangle& src_rect, u64 ticks, int frame_number); // Asynchronously encodes the specified pointer of frame data to the frame dump. void DumpFrameData(const u8* data, int w, int h, int stride);