System: Switch to new capture file on video FPS change
This commit is contained in:
parent
44a12db931
commit
b274bf4d57
|
@ -2150,7 +2150,7 @@ bool GPU::RenderDisplay(GPUTexture* target, const GSVector4i display_rect, const
|
|||
bool GPU::SendDisplayToMediaCapture(MediaCapture* cap)
|
||||
{
|
||||
GPUTexture* target = cap->GetRenderTexture();
|
||||
if (!target)
|
||||
if (!target) [[unlikely]]
|
||||
return false;
|
||||
|
||||
const bool apply_aspect_ratio =
|
||||
|
@ -2163,11 +2163,9 @@ bool GPU::SendDisplayToMediaCapture(MediaCapture* cap)
|
|||
// Not cleared by RenderDisplay().
|
||||
g_gpu_device->ClearRenderTarget(target, GPUDevice::DEFAULT_CLEAR_COLOR);
|
||||
|
||||
if (!RenderDisplay(target, display_rect, draw_rect, postfx))
|
||||
if (!RenderDisplay(target, display_rect, draw_rect, postfx)) [[unlikely]]
|
||||
return false;
|
||||
|
||||
// TODO: Check for frame rate change
|
||||
|
||||
return cap->DeliverVideoFrame(target);
|
||||
}
|
||||
|
||||
|
|
|
@ -2024,8 +2024,24 @@ void System::FrameDone()
|
|||
// Kick off media capture early, might take a while.
|
||||
if (s_media_capture && s_media_capture->IsCapturingVideo()) [[unlikely]]
|
||||
{
|
||||
if (!g_gpu->SendDisplayToMediaCapture(s_media_capture.get())) [[unlikely]]
|
||||
if (s_media_capture->GetVideoFPS() != GetThrottleFrequency()) [[unlikely]]
|
||||
{
|
||||
const std::string next_capture_path = s_media_capture->GetNextCapturePath();
|
||||
INFO_LOG("Video frame rate changed, switching to new capture file {}", Path::GetFileName(next_capture_path));
|
||||
|
||||
const bool was_capturing_audio = s_media_capture->IsCapturingAudio();
|
||||
StopMediaCapture();
|
||||
if (StartMediaCapture(std::move(next_capture_path), true, was_capturing_audio) &&
|
||||
!g_gpu->SendDisplayToMediaCapture(s_media_capture.get())) [[unlikely]]
|
||||
{
|
||||
StopMediaCapture();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!g_gpu->SendDisplayToMediaCapture(s_media_capture.get())) [[unlikely]]
|
||||
StopMediaCapture();
|
||||
}
|
||||
}
|
||||
|
||||
Common::Timer::Value current_time = Common::Timer::GetCurrentValue();
|
||||
|
@ -4991,7 +5007,7 @@ bool System::StartMediaCapture(std::string path, bool capture_video, bool captur
|
|||
u32 capture_height = g_settings.media_capture_video_height;
|
||||
const GPUTexture::Format capture_format =
|
||||
g_gpu_device->HasSurface() ? g_gpu_device->GetWindowFormat() : GPUTexture::Format::RGBA8;
|
||||
const float fps = g_gpu->ComputeVerticalFrequency();
|
||||
const float fps = System::GetThrottleFrequency();
|
||||
if (capture_video)
|
||||
{
|
||||
// TODO: This will be a mess with GPU thread.
|
||||
|
|
|
@ -89,21 +89,23 @@ public:
|
|||
bool BeginCapture(float fps, float aspect, u32 width, u32 height, GPUTexture::Format texture_format, u32 sample_rate,
|
||||
std::string path, bool capture_video, std::string_view video_codec, u32 video_bitrate,
|
||||
std::string_view video_codec_args, bool capture_audio, std::string_view audio_codec,
|
||||
u32 audio_bitrate, std::string_view audio_codec_args, Error* error) override;
|
||||
u32 audio_bitrate, std::string_view audio_codec_args, Error* error) override final;
|
||||
|
||||
const std::string& GetPath() const override;
|
||||
u32 GetVideoWidth() const override;
|
||||
u32 GetVideoHeight() const override;
|
||||
const std::string& GetPath() const override final;
|
||||
std::string GetNextCapturePath() const override final;
|
||||
u32 GetVideoWidth() const override final;
|
||||
u32 GetVideoHeight() const override final;
|
||||
float GetVideoFPS() const override final;
|
||||
|
||||
float GetCaptureThreadUsage() const override;
|
||||
float GetCaptureThreadTime() const override;
|
||||
void UpdateCaptureThreadUsage(double pct_divider, double time_divider) override;
|
||||
float GetCaptureThreadUsage() const override final;
|
||||
float GetCaptureThreadTime() const override final;
|
||||
void UpdateCaptureThreadUsage(double pct_divider, double time_divider) override final;
|
||||
|
||||
GPUTexture* GetRenderTexture() override;
|
||||
bool DeliverVideoFrame(GPUTexture* stex) override;
|
||||
bool DeliverAudioFrames(const s16* frames, u32 num_frames) override;
|
||||
bool EndCapture(Error* error) override;
|
||||
void Flush() override;
|
||||
GPUTexture* GetRenderTexture() override final;
|
||||
bool DeliverVideoFrame(GPUTexture* stex) override final;
|
||||
bool DeliverAudioFrames(const s16* frames, u32 num_frames) override final;
|
||||
bool EndCapture(Error* error) override final;
|
||||
void Flush() override final;
|
||||
|
||||
protected:
|
||||
struct PendingFrame
|
||||
|
@ -147,9 +149,10 @@ protected:
|
|||
std::atomic_bool m_capturing{false};
|
||||
std::atomic_bool m_encoding_error{false};
|
||||
|
||||
GPUTexture::Format m_video_render_texture_format = GPUTexture::Format::Unknown;
|
||||
u32 m_video_width = 0;
|
||||
u32 m_video_height = 0;
|
||||
GPUTexture::Format m_video_render_texture_format = GPUTexture::Format::Unknown;
|
||||
float m_video_fps = 0;
|
||||
s64 m_next_video_pts = 0;
|
||||
std::unique_ptr<GPUTexture> m_render_texture;
|
||||
|
||||
|
@ -185,17 +188,19 @@ bool MediaCaptureBase::BeginCapture(float fps, float aspect, u32 width, u32 heig
|
|||
std::string_view audio_codec, u32 audio_bitrate, std::string_view audio_codec_args,
|
||||
Error* error)
|
||||
{
|
||||
m_video_render_texture_format = texture_format;
|
||||
m_video_width = width;
|
||||
m_video_height = height;
|
||||
m_video_render_texture_format = texture_format;
|
||||
m_video_fps = fps;
|
||||
|
||||
if (path.empty())
|
||||
{
|
||||
Error::SetStringView(error, "No path specified.");
|
||||
return false;
|
||||
}
|
||||
else if (fps == 0.0f || m_video_width == 0 || !Common::IsAlignedPow2(m_video_width, VIDEO_WIDTH_ALIGNMENT) ||
|
||||
m_video_height == 0 || !Common::IsAlignedPow2(m_video_height, VIDEO_HEIGHT_ALIGNMENT))
|
||||
else if (capture_video &&
|
||||
(fps == 0.0f || m_video_width == 0 || !Common::IsAlignedPow2(m_video_width, VIDEO_WIDTH_ALIGNMENT) ||
|
||||
m_video_height == 0 || !Common::IsAlignedPow2(m_video_height, VIDEO_HEIGHT_ALIGNMENT)))
|
||||
{
|
||||
Error::SetStringView(error, "Invalid video dimensions/rate.");
|
||||
return false;
|
||||
|
@ -506,6 +511,34 @@ const std::string& MediaCaptureBase::GetPath() const
|
|||
return m_path;
|
||||
}
|
||||
|
||||
std::string MediaCaptureBase::GetNextCapturePath() const
|
||||
{
|
||||
const std::string_view ext = Path::GetExtension(m_path);
|
||||
std::string_view name = Path::GetFileTitle(m_path);
|
||||
|
||||
// Should end with a number.
|
||||
u32 partnum = 2;
|
||||
std::string_view::size_type pos = name.rfind("_part");
|
||||
if (pos != std::string_view::npos)
|
||||
{
|
||||
std::string_view::size_type cpos = pos + 5;
|
||||
for (; cpos < name.length(); cpos++)
|
||||
{
|
||||
if (name[cpos] < '0' || name[cpos] > '9')
|
||||
break;
|
||||
}
|
||||
if (cpos == name.length())
|
||||
{
|
||||
// Has existing part number, so add to it.
|
||||
partnum = StringUtil::FromChars<u32>(name.substr(pos + 5)).value_or(1) + 1;
|
||||
name = name.substr(0, pos);
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't started a new file previously, add "_part2".
|
||||
return Path::BuildRelativePath(m_path, fmt::format("{}_part{:03d}.{}", name, partnum, ext));
|
||||
}
|
||||
|
||||
u32 MediaCaptureBase::GetVideoWidth() const
|
||||
{
|
||||
return m_video_width;
|
||||
|
@ -516,6 +549,11 @@ u32 MediaCaptureBase::GetVideoHeight() const
|
|||
return m_video_height;
|
||||
}
|
||||
|
||||
float MediaCaptureBase::GetVideoFPS() const
|
||||
{
|
||||
return m_video_fps;
|
||||
}
|
||||
|
||||
float MediaCaptureBase::GetCaptureThreadUsage() const
|
||||
{
|
||||
return m_encoder_thread_usage;
|
||||
|
|
|
@ -56,10 +56,12 @@ public:
|
|||
|
||||
// TODO: make non-virtual?
|
||||
virtual const std::string& GetPath() const = 0;
|
||||
virtual std::string GetNextCapturePath() const = 0;
|
||||
virtual bool IsCapturingAudio() const = 0;
|
||||
virtual bool IsCapturingVideo() const = 0;
|
||||
virtual u32 GetVideoWidth() const = 0;
|
||||
virtual u32 GetVideoHeight() const = 0;
|
||||
virtual float GetVideoFPS() const = 0;
|
||||
|
||||
/// Returns the elapsed time in seconds.
|
||||
virtual time_t GetElapsedTime() const = 0;
|
||||
|
|
Loading…
Reference in New Issue