diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index aa52ffc4ed..bf0b487276 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -824,8 +824,9 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, D3D11_MAPPED_SUBRESOURCE map; D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ, 0, &map); + AVIDump::Frame state = AVIDump::FetchState(ticks); DumpFrameData(reinterpret_cast(map.pData), source_width, source_height, map.RowPitch, - ticks); + state); FinishFrameData(); D3D::context->Unmap(s_screenshot_texture, 0); diff --git a/Source/Core/VideoBackends/D3D12/Render.cpp b/Source/Core/VideoBackends/D3D12/Render.cpp index 9c1cbdad76..8b3c36651b 100644 --- a/Source/Core/VideoBackends/D3D12/Render.cpp +++ b/Source/Core/VideoBackends/D3D12/Render.cpp @@ -777,8 +777,9 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height D3D12_RANGE read_range = {0, dst_location.PlacedFootprint.Footprint.RowPitch * source_height}; CheckHR(s_screenshot_texture->Map(0, &read_range, &screenshot_texture_map)); + AVIDump::Frame state = AVIDump::FetchState(ticks); DumpFrameData(reinterpret_cast(screenshot_texture_map), source_width, source_height, - dst_location.PlacedFootprint.Footprint.RowPitch, ticks); + dst_location.PlacedFootprint.Footprint.RowPitch, state); FinishFrameData(); D3D12_RANGE write_range = {}; diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index de7dc8fff6..e3d3bea2d5 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -1455,8 +1455,9 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, glReadPixels(flipped_trc.left, flipped_trc.bottom, flipped_trc.GetWidth(), flipped_trc.GetHeight(), GL_RGBA, GL_UNSIGNED_BYTE, image.data()); + AVIDump::Frame state = AVIDump::FetchState(ticks); DumpFrameData(image.data(), flipped_trc.GetWidth(), flipped_trc.GetHeight(), - flipped_trc.GetWidth() * 4, ticks, true); + flipped_trc.GetWidth() * 4, state, true); FinishFrameData(); } // Finish up the current frame, print some stats diff --git a/Source/Core/VideoBackends/Software/SWRenderer.cpp b/Source/Core/VideoBackends/Software/SWRenderer.cpp index 2e7992c705..df77a45466 100644 --- a/Source/Core/VideoBackends/Software/SWRenderer.cpp +++ b/Source/Core/VideoBackends/Software/SWRenderer.cpp @@ -125,7 +125,8 @@ void SWRenderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, // Save screenshot if (IsFrameDumping()) { - DumpFrameData(GetCurrentColorTexture(), fbWidth, fbHeight, fbWidth * 4, ticks); + AVIDump::Frame state = AVIDump::FetchState(ticks); + DumpFrameData(GetCurrentColorTexture(), fbWidth, fbHeight, fbWidth * 4, state); FinishFrameData(); } diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 066f3f512a..0449d49f14 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -747,10 +747,11 @@ bool Renderer::DrawFrameDump(const EFBRectangle& rc, u32 xfb_addr, void Renderer::DumpFrame(u64 ticks) { + AVIDump::Frame state = AVIDump::FetchState(ticks); DumpFrameData(reinterpret_cast(m_frame_dump_readback_texture->GetMapPointer()), static_cast(m_frame_dump_render_texture->GetWidth()), static_cast(m_frame_dump_render_texture->GetHeight()), - static_cast(m_frame_dump_readback_texture->GetRowStride()), ticks); + static_cast(m_frame_dump_readback_texture->GetRowStride()), state); FinishFrameData(); } diff --git a/Source/Core/VideoCommon/AVIDump.cpp b/Source/Core/VideoCommon/AVIDump.cpp index 7b09d10c1e..1756be97a8 100644 --- a/Source/Core/VideoCommon/AVIDump.cpp +++ b/Source/Core/VideoCommon/AVIDump.cpp @@ -166,7 +166,7 @@ static void PreparePacket(AVPacket* pkt) pkt->size = 0; } -void AVIDump::AddFrame(const u8* data, int width, int height, int stride, u64 ticks) +void AVIDump::AddFrame(const u8* data, int width, int height, int stride, const Frame& state) { CheckResolution(width, height); s_src_frame->data[0] = const_cast(data); @@ -196,26 +196,25 @@ void AVIDump::AddFrame(const u8* data, int width, int height, int stride, u64 ti // incorrectly. if (!s_last_frame_is_valid) { - s_last_frame = ticks; + s_last_frame = state.ticks; s_last_frame_is_valid = true; } - if (!s_start_dumping && Movie::GetCurrentFrame() < 1) + if (!s_start_dumping && state.first_frame) { - delta = ticks; + delta = state.ticks; last_pts = AV_NOPTS_VALUE; s_start_dumping = true; } else { - delta = ticks - s_last_frame; - last_pts = (s_last_pts * s_stream->codec->time_base.den) / SystemTimers::GetTicksPerSecond(); + delta = state.ticks - s_last_frame; + last_pts = (s_last_pts * s_stream->codec->time_base.den) / state.ticks_per_second; } u64 pts_in_ticks = s_last_pts + delta; - s_scaled_frame->pts = - (pts_in_ticks * s_stream->codec->time_base.den) / SystemTimers::GetTicksPerSecond(); + s_scaled_frame->pts = (pts_in_ticks * s_stream->codec->time_base.den) / state.ticks_per_second; if (s_scaled_frame->pts != last_pts) { - s_last_frame = ticks; + s_last_frame = state.ticks; s_last_pts = pts_in_ticks; error = avcodec_encode_video2(s_stream->codec, &pkt, s_scaled_frame, &got_packet); } @@ -304,3 +303,12 @@ void AVIDump::CheckResolution(int width, int height) Start(width, height); } } + +AVIDump::Frame AVIDump::FetchState(u64 ticks) +{ + Frame state; + state.ticks = ticks; + state.first_frame = Movie::GetCurrentFrame() < 1; + state.ticks_per_second = SystemTimers::GetTicksPerSecond(); + return state; +} diff --git a/Source/Core/VideoCommon/AVIDump.h b/Source/Core/VideoCommon/AVIDump.h index d4a43a4522..bbea5e2bbf 100644 --- a/Source/Core/VideoCommon/AVIDump.h +++ b/Source/Core/VideoCommon/AVIDump.h @@ -14,8 +14,21 @@ private: static void CheckResolution(int width, int height); public: + struct Frame + { + u64 ticks = 0; + u32 ticks_per_second = 0; + bool first_frame = false; + }; + static bool Start(int w, int h); - static void AddFrame(const u8* data, int width, int height, int stride, u64 ticks); + static void AddFrame(const u8* data, int width, int height, int stride, const Frame& state); static void Stop(); static void DoState(); + +#if defined(HAVE_LIBAV) || defined(_WIN32) + static Frame FetchState(u64 ticks); +#else + static Frame FetchState(u64 ticks) { return {}; } +#endif }; diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 013ee7f07d..65f716ba9e 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -667,7 +667,7 @@ bool Renderer::IsFrameDumping() return false; } -void Renderer::DumpFrameData(const u8* data, int w, int h, int stride, u64 ticks, +void Renderer::DumpFrameData(const u8* data, int w, int h, int stride, const AVIDump::Frame& state, bool swap_upside_down) { if (w == 0 || h == 0) @@ -701,7 +701,7 @@ void Renderer::DumpFrameData(const u8* data, int w, int h, int stride, u64 ticks } if (m_AVI_dumping) { - AVIDump::AddFrame(m_frame_data.data(), w, h, stride, ticks); + AVIDump::AddFrame(m_frame_data.data(), w, h, stride, state); } m_last_frame_dumped = true; diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 8b3495b82e..f3526e8516 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -147,7 +147,7 @@ protected: static void RecordVideoMemory(); bool IsFrameDumping(); - void DumpFrameData(const u8* data, int w, int h, int stride, u64 ticks, + void DumpFrameData(const u8* data, int w, int h, int stride, const AVIDump::Frame& state, bool swap_upside_down = false); void FinishFrameData();