diff options
| author | JMC47 <JMC4789@gmail.com> | 2025-05-12 13:36:55 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-12 13:36:55 -0400 |
| commit | cf3702cbc8be1a1bd353b4766e50687719d2a20c (patch) | |
| tree | 68560be7647f77ed90055bf659f8b9725fd498c6 /Source/Core | |
| parent | f19a33340a1a27a7964b52474ff80f0eee014d9e (diff) | |
| parent | c720211542c2741b1b768a25a4a00ad3511be856 (diff) | |
Merge pull request #13046 from SuperSamus/vi-overclock
Add VBI Frequency Override
Diffstat (limited to 'Source/Core')
| -rw-r--r-- | Source/Core/Core/Config/MainSettings.cpp | 2 | ||||
| -rw-r--r-- | Source/Core/Core/Config/MainSettings.h | 2 | ||||
| -rw-r--r-- | Source/Core/Core/ConfigLoaders/NetPlayConfigLoader.cpp | 2 | ||||
| -rw-r--r-- | Source/Core/Core/CoreTiming.cpp | 9 | ||||
| -rw-r--r-- | Source/Core/Core/CoreTiming.h | 2 | ||||
| -rw-r--r-- | Source/Core/Core/DolphinAnalytics.cpp | 2 | ||||
| -rw-r--r-- | Source/Core/Core/HW/VideoInterface.cpp | 34 | ||||
| -rw-r--r-- | Source/Core/Core/HW/VideoInterface.h | 7 | ||||
| -rw-r--r-- | Source/Core/Core/IOS/DolphinDevice.cpp | 4 | ||||
| -rw-r--r-- | Source/Core/Core/NetPlayClient.cpp | 2 | ||||
| -rw-r--r-- | Source/Core/Core/NetPlayProto.h | 2 | ||||
| -rw-r--r-- | Source/Core/Core/NetPlayServer.cpp | 4 | ||||
| -rw-r--r-- | Source/Core/DolphinQt/Settings/AdvancedPane.cpp | 79 | ||||
| -rw-r--r-- | Source/Core/DolphinQt/Settings/AdvancedPane.h | 4 | ||||
| -rw-r--r-- | Source/Core/VideoCommon/FrameDumpFFMpeg.cpp | 13 | ||||
| -rw-r--r-- | Source/Core/VideoCommon/FrameDumpFFMpeg.h | 4 |
16 files changed, 156 insertions, 16 deletions
diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 9f4d1cce17..0b6a2fd6c1 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -222,6 +222,8 @@ const Info<bool> MAIN_PRECISION_FRAME_TIMING{{System::Main, "Core", "PrecisionFr DEFAULT_PRECISION_FRAME_TIMING}; const Info<float> MAIN_OVERCLOCK{{System::Main, "Core", "Overclock"}, 1.0f}; const Info<bool> MAIN_OVERCLOCK_ENABLE{{System::Main, "Core", "OverclockEnable"}, false}; +const Info<float> MAIN_VI_OVERCLOCK{{System::Main, "Core", "VIOverclock"}, 1.0f}; +const Info<bool> MAIN_VI_OVERCLOCK_ENABLE{{System::Main, "Core", "VIOverclockEnable"}, false}; const Info<bool> MAIN_RAM_OVERRIDE_ENABLE{{System::Main, "Core", "RAMOverrideEnable"}, false}; const Info<u32> MAIN_MEM1_SIZE{{System::Main, "Core", "MEM1Size"}, Memory::MEM1_SIZE_RETAIL}; const Info<u32> MAIN_MEM2_SIZE{{System::Main, "Core", "MEM2Size"}, Memory::MEM2_SIZE_RETAIL}; diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index 28a044d253..774824e450 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -128,6 +128,8 @@ extern const Info<float> MAIN_EMULATION_SPEED; extern const Info<bool> MAIN_PRECISION_FRAME_TIMING; extern const Info<float> MAIN_OVERCLOCK; extern const Info<bool> MAIN_OVERCLOCK_ENABLE; +extern const Info<float> MAIN_VI_OVERCLOCK; +extern const Info<bool> MAIN_VI_OVERCLOCK_ENABLE; extern const Info<bool> MAIN_RAM_OVERRIDE_ENABLE; extern const Info<u32> MAIN_MEM1_SIZE; extern const Info<u32> MAIN_MEM2_SIZE; diff --git a/Source/Core/Core/ConfigLoaders/NetPlayConfigLoader.cpp b/Source/Core/Core/ConfigLoaders/NetPlayConfigLoader.cpp index 5f772fd0e3..855cc181b9 100644 --- a/Source/Core/Core/ConfigLoaders/NetPlayConfigLoader.cpp +++ b/Source/Core/Core/ConfigLoaders/NetPlayConfigLoader.cpp @@ -42,6 +42,8 @@ public: layer->Set(Config::MAIN_DSP_HLE, m_settings.dsp_hle); layer->Set(Config::MAIN_OVERCLOCK_ENABLE, m_settings.oc_enable); layer->Set(Config::MAIN_OVERCLOCK, m_settings.oc_factor); + layer->Set(Config::MAIN_VI_OVERCLOCK_ENABLE, m_settings.vi_oc_enable); + layer->Set(Config::MAIN_VI_OVERCLOCK, m_settings.vi_oc_factor); for (ExpansionInterface::Slot slot : ExpansionInterface::SLOTS) layer->Set(Config::GetInfoForEXIDevice(slot), m_settings.exi_device[slot]); layer->Set(Config::MAIN_MEMORY_CARD_SIZE, m_settings.memcard_size_override); diff --git a/Source/Core/Core/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp index 0de77f4446..f4c7d13fc0 100644 --- a/Source/Core/Core/CoreTiming.cpp +++ b/Source/Core/Core/CoreTiming.cpp @@ -119,7 +119,9 @@ void CoreTimingManager::Shutdown() void CoreTimingManager::RefreshConfig() { m_config_oc_factor = - Config::Get(Config::MAIN_OVERCLOCK_ENABLE) ? Config::Get(Config::MAIN_OVERCLOCK) : 1.0f; + (Config::Get(Config::MAIN_OVERCLOCK_ENABLE) ? Config::Get(Config::MAIN_OVERCLOCK) : 1.0f) * + (Config::Get(Config::MAIN_VI_OVERCLOCK_ENABLE) ? Config::Get(Config::MAIN_VI_OVERCLOCK) : + 1.0f); m_config_oc_inv_factor = 1.0f / m_config_oc_factor; m_config_sync_on_skip_idle = Config::Get(Config::MAIN_SYNC_ON_SKIP_IDLE); @@ -482,6 +484,11 @@ bool CoreTimingManager::GetVISkip() const return m_throttle_disable_vi_int && g_ActiveConfig.bVISkip && !Core::WantsDeterminism(); } +float CoreTimingManager::GetOverclock() const +{ + return m_config_oc_factor; +} + bool CoreTimingManager::UseSyncOnSkipIdle() const { return m_config_sync_on_skip_idle; diff --git a/Source/Core/Core/CoreTiming.h b/Source/Core/Core/CoreTiming.h index d6f652c35a..ae0dccd38c 100644 --- a/Source/Core/Core/CoreTiming.h +++ b/Source/Core/Core/CoreTiming.h @@ -165,6 +165,8 @@ public: // Used by VideoInterface bool GetVISkip() const; + float GetOverclock() const; + bool UseSyncOnSkipIdle() const; private: diff --git a/Source/Core/Core/DolphinAnalytics.cpp b/Source/Core/Core/DolphinAnalytics.cpp index 5613e3fea4..3551321e6f 100644 --- a/Source/Core/Core/DolphinAnalytics.cpp +++ b/Source/Core/Core/DolphinAnalytics.cpp @@ -365,6 +365,8 @@ void DolphinAnalytics::MakePerGameBuilder() builder.AddData("cfg-audio-backend", Config::Get(Config::MAIN_AUDIO_BACKEND)); builder.AddData("cfg-oc-enable", Config::Get(Config::MAIN_OVERCLOCK_ENABLE)); builder.AddData("cfg-oc-factor", Config::Get(Config::MAIN_OVERCLOCK)); + builder.AddData("cfg-vi-oc-enable", Config::Get(Config::MAIN_VI_OVERCLOCK_ENABLE)); + builder.AddData("cfg-vi-oc-factor", Config::Get(Config::MAIN_VI_OVERCLOCK)); builder.AddData("cfg-render-to-main", Config::Get(Config::MAIN_RENDER_TO_MAIN)); if (g_video_backend) { diff --git a/Source/Core/Core/HW/VideoInterface.cpp b/Source/Core/Core/HW/VideoInterface.cpp index b03a8c5988..e1e822f08e 100644 --- a/Source/Core/Core/HW/VideoInterface.cpp +++ b/Source/Core/Core/HW/VideoInterface.cpp @@ -13,8 +13,10 @@ #include "Common/Config/Config.h" #include "Common/Logging/Log.h" +#include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/PerformanceMetrics.h" +#include "Core/AchievementManager.h" #include "Core/Config/GraphicsSettings.h" #include "Core/Config/MainSettings.h" #include "Core/Config/SYSCONFSettings.h" @@ -41,7 +43,10 @@ VideoInterfaceManager::VideoInterfaceManager(Core::System& system) : m_system(sy { } -VideoInterfaceManager::~VideoInterfaceManager() = default; +VideoInterfaceManager::~VideoInterfaceManager() +{ + Config::RemoveConfigChangedCallback(m_config_changed_callback_id); +} static constexpr std::array<u32, 2> CLOCK_FREQUENCIES{{ 27000000, @@ -173,6 +178,22 @@ void VideoInterfaceManager::Preset(bool _bNTSC) void VideoInterfaceManager::Init() { Preset(true); + + m_config_changed_callback_id = Config::AddConfigChangedCallback([this] { RefreshConfig(); }); + RefreshConfig(); +} + +void VideoInterfaceManager::RefreshConfig() +{ + m_config_vi_oc_factor = + Config::Get(Config::MAIN_VI_OVERCLOCK_ENABLE) ? Config::Get(Config::MAIN_VI_OVERCLOCK) : 1.0f; + if (AchievementManager::GetInstance().IsHardcoreModeActive() && m_config_vi_oc_factor < 1.0f) + { + Config::SetCurrent(Config::MAIN_VI_OVERCLOCK, 1.0f); + m_config_vi_oc_factor = 1.0f; + OSD::AddMessage("Minimum VBI frequency is 100% in Hardcore Mode"); + } + UpdateRefreshRate(); } void VideoInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base) @@ -488,7 +509,8 @@ float VideoInterfaceManager::GetAspectRatio() const float vertical_period = tick_length * GetTicksPerField(); float horizontal_period = tick_length * GetTicksPerHalfLine() * 2; float vertical_active_area = active_lines * horizontal_period; - float horizontal_active_area = tick_length * GetTicksPerSample() * active_width_samples; + float horizontal_active_area = + tick_length * GetTicksPerSample() * active_width_samples / m_config_vi_oc_factor; // We are approximating the horizontal/vertical flyback transformers that control the // position of the electron beam on the screen. Our flyback transformers create a @@ -707,7 +729,11 @@ void VideoInterfaceManager::UpdateParameters() m_vblank_timing_even.PRB - odd_even_psb_diff; m_even_field_last_hl = m_even_field_first_hl + acv_hl - 1; - // Refresh rate: + UpdateRefreshRate(); +} + +void VideoInterfaceManager::UpdateRefreshRate() +{ m_target_refresh_rate_numerator = m_system.GetSystemTimers().GetTicksPerSecond() * 2; m_target_refresh_rate_denominator = GetTicksPerEvenField() + GetTicksPerOddField(); m_target_refresh_rate = @@ -736,7 +762,7 @@ u32 VideoInterfaceManager::GetTicksPerSample() const u32 VideoInterfaceManager::GetTicksPerHalfLine() const { - return GetTicksPerSample() * m_h_timing_0.HLW; + return GetTicksPerSample() * m_h_timing_0.HLW / m_config_vi_oc_factor; } u32 VideoInterfaceManager::GetTicksPerField() const diff --git a/Source/Core/Core/HW/VideoInterface.h b/Source/Core/Core/HW/VideoInterface.h index 8bb1e23405..e35bc42427 100644 --- a/Source/Core/Core/HW/VideoInterface.h +++ b/Source/Core/Core/HW/VideoInterface.h @@ -7,6 +7,7 @@ #include <memory> #include "Common/CommonTypes.h" +#include "Common/Config/Config.h" enum class FieldType; class PointerWrap; @@ -407,6 +408,9 @@ private: void BeginField(FieldType field, u64 ticks); void EndField(FieldType field, u64 ticks); + void RefreshConfig(); + void UpdateRefreshRate(); + // Registers listed in order: UVIVerticalTimingRegister m_vertical_timing_register; UVIDisplayControlRegister m_display_control_register; @@ -447,6 +451,9 @@ private: u32 m_even_field_last_hl = 0; // index last halfline of the even field u32 m_odd_field_last_hl = 0; // index last halfline of the odd field + float m_config_vi_oc_factor = 0.0f; + + Config::ConfigChangedCallbackID m_config_changed_callback_id; Core::System& m_system; }; } // namespace VideoInterface diff --git a/Source/Core/Core/IOS/DolphinDevice.cpp b/Source/Core/Core/IOS/DolphinDevice.cpp index 944bec41b2..c240b922b7 100644 --- a/Source/Core/Core/IOS/DolphinDevice.cpp +++ b/Source/Core/Core/IOS/DolphinDevice.cpp @@ -68,9 +68,7 @@ IPCReply GetCPUSpeed(Core::System& system, const IOCtlVRequest& request) return IPCReply(IPC_EINVAL); } - const bool overclock_enabled = Config::Get(Config::MAIN_OVERCLOCK_ENABLE); - const float oc = overclock_enabled ? Config::Get(Config::MAIN_OVERCLOCK) : 1.0f; - + const bool oc = system.GetCoreTiming().GetOverclock(); const u32 core_clock = u32(float(system.GetSystemTimers().GetTicksPerSecond()) * oc); auto& memory = system.GetMemory(); diff --git a/Source/Core/Core/NetPlayClient.cpp b/Source/Core/Core/NetPlayClient.cpp index aee89cbc1c..d3568ae2d1 100644 --- a/Source/Core/Core/NetPlayClient.cpp +++ b/Source/Core/Core/NetPlayClient.cpp @@ -862,6 +862,8 @@ void NetPlayClient::OnStartGame(sf::Packet& packet) packet >> m_net_settings.allow_sd_writes; packet >> m_net_settings.oc_enable; packet >> m_net_settings.oc_factor; + packet >> m_net_settings.vi_oc_enable; + packet >> m_net_settings.vi_oc_factor; for (auto slot : ExpansionInterface::SLOTS) packet >> m_net_settings.exi_device[slot]; diff --git a/Source/Core/Core/NetPlayProto.h b/Source/Core/Core/NetPlayProto.h index c97d04c2b2..62a9aba9a4 100644 --- a/Source/Core/Core/NetPlayProto.h +++ b/Source/Core/Core/NetPlayProto.h @@ -47,6 +47,8 @@ struct NetSettings bool allow_sd_writes = false; bool oc_enable = false; float oc_factor = 0; + bool vi_oc_enable = false; + float vi_oc_factor = 0; Common::EnumMap<ExpansionInterface::EXIDeviceType, ExpansionInterface::MAX_SLOT> exi_device{}; int memcard_size_override = -1; diff --git a/Source/Core/Core/NetPlayServer.cpp b/Source/Core/Core/NetPlayServer.cpp index 4cff258e9b..51b3f1916b 100644 --- a/Source/Core/Core/NetPlayServer.cpp +++ b/Source/Core/Core/NetPlayServer.cpp @@ -1376,6 +1376,8 @@ bool NetPlayServer::SetupNetSettings() settings.allow_sd_writes = Config::Get(Config::MAIN_ALLOW_SD_WRITES); settings.oc_enable = Config::Get(Config::MAIN_OVERCLOCK_ENABLE); settings.oc_factor = Config::Get(Config::MAIN_OVERCLOCK); + settings.vi_oc_enable = Config::Get(Config::MAIN_VI_OVERCLOCK_ENABLE); + settings.vi_oc_factor = Config::Get(Config::MAIN_VI_OVERCLOCK); for (ExpansionInterface::Slot slot : ExpansionInterface::SLOTS) { @@ -1603,6 +1605,8 @@ bool NetPlayServer::StartGame() spac << m_settings.allow_sd_writes; spac << m_settings.oc_enable; spac << m_settings.oc_factor; + spac << m_settings.vi_oc_enable; + spac << m_settings.vi_oc_factor; for (auto slot : ExpansionInterface::SLOTS) spac << static_cast<int>(m_settings.exi_device[slot]); diff --git a/Source/Core/DolphinQt/Settings/AdvancedPane.cpp b/Source/Core/DolphinQt/Settings/AdvancedPane.cpp index 917e7e898c..31e73a5b34 100644 --- a/Source/Core/DolphinQt/Settings/AdvancedPane.cpp +++ b/Source/Core/DolphinQt/Settings/AdvancedPane.cpp @@ -20,6 +20,7 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/HW/SystemTimers.h" +#include "Core/HW/VideoInterface.h" #include "Core/PowerPC/PowerPC.h" #include "Core/System.h" @@ -111,14 +112,47 @@ void AdvancedPane::CreateLayout() m_cpu_clock_override_checkbox->SetDescription( tr("Adjusts the emulated CPU's clock rate.<br><br>" - "Higher values may make variable-framerate games run at a higher framerate, " - "at the expense of performance. Lower values may activate a game's " - "internal frameskip, potentially improving performance.<br><br>" - "<b>WARNING</b>: Changing this from the default (100%) can and will " + "On games that have an unstable frame rate despite full emulation speed, " + "higher values can improve their performance, requiring a powerful device. " + "Lower values reduce the emulated console's performance, but improve the " + "emulation speed.<br><br>" + "WARNING: Changing this from the default (100%) can and will " "break games and cause glitches. Do so at your own risk. " "Please do not report bugs that occur with a non-default clock." "<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>")); + auto* vi_rate_override = new QGroupBox(tr("VBI Frequency Override")); + auto* vi_rate_override_layout = new QVBoxLayout(); + vi_rate_override->setLayout(vi_rate_override_layout); + main_layout->addWidget(vi_rate_override); + + m_vi_rate_override_checkbox = + new ConfigBool(tr("Enable VBI Frequency Override"), Config::MAIN_VI_OVERCLOCK_ENABLE); + vi_rate_override_layout->addWidget(m_vi_rate_override_checkbox); + connect(m_vi_rate_override_checkbox, &QCheckBox::toggled, this, &AdvancedPane::Update); + + auto* vi_rate_override_slider_layout = new QHBoxLayout(); + vi_rate_override_slider_layout->setContentsMargins(0, 0, 0, 0); + vi_rate_override_layout->addLayout(vi_rate_override_slider_layout); + + m_vi_rate_override_slider = new QSlider(Qt::Horizontal); + m_vi_rate_override_slider->setRange(1, 500); + vi_rate_override_slider_layout->addWidget(m_vi_rate_override_slider); + + m_vi_rate_override_slider_label = new QLabel(); + vi_rate_override_slider_layout->addWidget(m_vi_rate_override_slider_label); + + m_vi_rate_override_checkbox->SetDescription( + tr("Adjusts the VBI frequency. Also adjusts the emulated CPU's " + "clock rate, to keep it relatively the same.<br><br>" + "Makes games run at a different frame rate, making the emulation less " + "demanding when lowered, or improving smoothness when increased. This may " + "affect gameplay speed, as it is often tied to the frame rate.<br><br>" + "WARNING: Changing this from the default (100%) can and will " + "break games and cause glitches. Do so at your own risk. " + "Please do not report bugs that occur with a non-default frequency." + "<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>")); + auto* ram_override = new QGroupBox(tr("Memory Override")); auto* ram_override_layout = new QVBoxLayout(); ram_override->setLayout(ram_override_layout); @@ -199,6 +233,18 @@ void AdvancedPane::ConnectLayout() Update(); }); + connect(m_vi_rate_override_slider, &QSlider::valueChanged, [this](int oc_factor) { + const float factor = m_vi_rate_override_slider->value() / 100.f; + Config::SetBaseOrCurrent(Config::MAIN_VI_OVERCLOCK, factor); + Update(); + }); + + m_ram_override_checkbox->setChecked(Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE)); + connect(m_ram_override_checkbox, &QCheckBox::toggled, [this](bool enable_ram_override) { + Config::SetBaseOrCurrent(Config::MAIN_RAM_OVERRIDE_ENABLE, enable_ram_override); + Update(); + }); + connect(m_mem1_override_slider, &QSlider::valueChanged, [this](int slider_value) { const u32 mem1_size = m_mem1_override_slider->value() * 0x100000; Config::SetBaseOrCurrent(Config::MAIN_MEM1_SIZE, mem1_size); @@ -222,6 +268,7 @@ void AdvancedPane::Update() { const bool is_uninitialized = Core::IsUninitialized(Core::System::GetInstance()); const bool enable_cpu_clock_override_widgets = Config::Get(Config::MAIN_OVERCLOCK_ENABLE); + const bool enable_vi_rate_override_widgets = Config::Get(Config::MAIN_VI_OVERCLOCK_ENABLE); const bool enable_ram_override_widgets = Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE); const bool enable_custom_rtc_widgets = Config::Get(Config::MAIN_CUSTOM_RTC_ENABLE) && is_uninitialized; @@ -264,6 +311,30 @@ void AdvancedPane::Update() return tr("%1% (%2 MHz)").arg(QString::number(percent), QString::number(clock)); }()); + QFont vi_bf = font(); + vi_bf.setBold(Config::GetActiveLayerForConfig(Config::MAIN_VI_OVERCLOCK_ENABLE) != + Config::LayerType::Base); + m_vi_rate_override_checkbox->setFont(vi_bf); + m_vi_rate_override_checkbox->setChecked(enable_vi_rate_override_widgets); + + m_vi_rate_override_slider->setEnabled(enable_vi_rate_override_widgets); + m_vi_rate_override_slider_label->setEnabled(enable_vi_rate_override_widgets); + + { + const QSignalBlocker blocker(m_vi_rate_override_slider); + m_vi_rate_override_slider->setValue( + static_cast<int>(std::round(Config::Get(Config::MAIN_VI_OVERCLOCK) * 100.f))); + } + + m_vi_rate_override_slider_label->setText([] { + int percent = static_cast<int>(std::round(Config::Get(Config::MAIN_VI_OVERCLOCK) * 100.f)); + float vps = + static_cast<float>(Core::System::GetInstance().GetVideoInterface().GetTargetRefreshRate()); + if (vps == 0.0f || !Config::Get(Config::MAIN_VI_OVERCLOCK_ENABLE)) + vps = 59.94f * Config::Get(Config::MAIN_VI_OVERCLOCK); + return tr("%1% (%2 VPS)").arg(QString::number(percent), QString::number(vps, 'f', 2)); + }()); + m_ram_override_checkbox->setEnabled(is_uninitialized); SignalBlocking(m_ram_override_checkbox)->setChecked(enable_ram_override_widgets); diff --git a/Source/Core/DolphinQt/Settings/AdvancedPane.h b/Source/Core/DolphinQt/Settings/AdvancedPane.h index ff449aca65..6493e71a73 100644 --- a/Source/Core/DolphinQt/Settings/AdvancedPane.h +++ b/Source/Core/DolphinQt/Settings/AdvancedPane.h @@ -39,6 +39,10 @@ private: QSlider* m_cpu_clock_override_slider; QLabel* m_cpu_clock_override_slider_label; + ConfigBool* m_vi_rate_override_checkbox; + QSlider* m_vi_rate_override_slider; + QLabel* m_vi_rate_override_slider_label; + ConfigBool* m_custom_rtc_checkbox; QDateTimeEdit* m_custom_rtc_datetime; diff --git a/Source/Core/VideoCommon/FrameDumpFFMpeg.cpp b/Source/Core/VideoCommon/FrameDumpFFMpeg.cpp index ea8bda7893..44ec0a6a27 100644 --- a/Source/Core/VideoCommon/FrameDumpFFMpeg.cpp +++ b/Source/Core/VideoCommon/FrameDumpFFMpeg.cpp @@ -62,13 +62,13 @@ struct FrameDumpContext namespace { -AVRational GetTimeBaseForCurrentRefreshRate() +AVRational GetTimeBaseForCurrentRefreshRate(s64 max_denominator) { auto& vi = Core::System::GetInstance().GetVideoInterface(); int num; int den; av_reduce(&num, &den, int(vi.GetTargetRefreshRateDenominator()), - int(vi.GetTargetRefreshRateNumerator()), std::numeric_limits<int>::max()); + int(vi.GetTargetRefreshRateNumerator()), max_denominator); return AVRational{num, den}; } @@ -248,11 +248,16 @@ bool FFMpegFrameDump::CreateVideoFile() return false; } + m_max_denominator = std::numeric_limits<s64>::max(); + // Force XVID FourCC for better compatibility when using H.263 if (codec->id == AV_CODEC_ID_MPEG4) + { m_context->codec->codec_tag = MKTAG('X', 'V', 'I', 'D'); + m_max_denominator = std::numeric_limits<unsigned short>::max(); + } - const auto time_base = GetTimeBaseForCurrentRefreshRate(); + const auto time_base = GetTimeBaseForCurrentRefreshRate(m_max_denominator); INFO_LOG_FMT(FRAMEDUMP, "Creating video file: {} x {} @ {}/{} fps", m_context->width, m_context->height, time_base.den, time_base.num); @@ -535,7 +540,7 @@ FrameState FFMpegFrameDump::FetchState(u64 ticks, int frame_number) const state.frame_number = frame_number; state.savestate_index = m_savestate_index; - const auto time_base = GetTimeBaseForCurrentRefreshRate(); + const auto time_base = GetTimeBaseForCurrentRefreshRate(m_max_denominator); state.refresh_rate_num = time_base.den; state.refresh_rate_den = time_base.num; return state; diff --git a/Source/Core/VideoCommon/FrameDumpFFMpeg.h b/Source/Core/VideoCommon/FrameDumpFFMpeg.h index 8431e24274..87387b3e41 100644 --- a/Source/Core/VideoCommon/FrameDumpFFMpeg.h +++ b/Source/Core/VideoCommon/FrameDumpFFMpeg.h @@ -4,6 +4,7 @@ #pragma once #include <ctime> +#include <limits> #include <memory> #include "Common/CommonTypes.h" @@ -62,6 +63,9 @@ private: // Used for filename generation. std::time_t m_start_time = {}; u32 m_file_index = 0; + + // Some codecs (like MPEG4) have a limit to this + int64_t m_max_denominator = std::numeric_limits<s64>::max(); }; #if !defined(HAVE_FFMPEG) |
