mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
150 lines
3.2 KiB
C++
150 lines
3.2 KiB
C++
// DR. ROBOTNIK'S RING RACERS
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 2025 by James Robert Roman
|
|
// Copyright (C) 2025 by Kart Krew
|
|
//
|
|
// This program is free software distributed under the
|
|
// terms of the GNU General Public License, version 2.
|
|
// See the 'LICENSE' file for more details.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include <filesystem>
|
|
#include <sstream>
|
|
|
|
#include <fmt/format.h>
|
|
|
|
#include "../core/string.h"
|
|
#include "../cxxutil.hpp"
|
|
#include "avrecorder_impl.hpp"
|
|
|
|
#include "../v_video.h"
|
|
|
|
using namespace srb2::media;
|
|
|
|
using Impl = AVRecorder::Impl;
|
|
|
|
namespace
|
|
{
|
|
|
|
constexpr float kMb = 1024.f * 1024.f;
|
|
|
|
}; // namespace
|
|
|
|
void Impl::container_dtor_handler(const MediaContainer& container) const
|
|
{
|
|
// Note that because this method is called from
|
|
// container_'s destructor, any member variables declared
|
|
// after Impl::container_ should not be accessed by now
|
|
// (since they would have already destructed).
|
|
|
|
if (max_size_ && container.size() > *max_size_)
|
|
{
|
|
const srb2::String line = srb2::format(
|
|
"Video size has exceeded limit {} > {} ({}%)."
|
|
" This should not happen, please report this bug.\n",
|
|
container.size(),
|
|
*max_size_,
|
|
100.f * (*max_size_ / static_cast<float>(container.size()))
|
|
);
|
|
|
|
CONS_Alert(CONS_WARNING, "%s\n", line.c_str());
|
|
}
|
|
|
|
std::ostringstream msg;
|
|
|
|
msg << "Video saved: " << std::filesystem::path(container.file_name()).filename().string()
|
|
<< fmt::format(" ({:.2f}", container.size() / kMb);
|
|
|
|
if (max_size_)
|
|
{
|
|
msg << fmt::format("/{:.2f}", *max_size_ / kMb);
|
|
}
|
|
|
|
msg << fmt::format(" MB, {:.1f}", container.duration().count());
|
|
|
|
if (max_duration_config_)
|
|
{
|
|
msg << fmt::format("/{:.1f}", max_duration_config_->count());
|
|
}
|
|
|
|
msg << " seconds)";
|
|
|
|
CONS_Printf("%s\n", msg.str().c_str());
|
|
}
|
|
|
|
void AVRecorder::print_configuration() const
|
|
{
|
|
if (impl_->audio_encoder_)
|
|
{
|
|
const auto& a = *impl_->audio_encoder_;
|
|
|
|
CONS_Printf("Audio: %s %dch %d Hz\n", a.name(), a.channels(), a.sample_rate());
|
|
}
|
|
|
|
if (impl_->video_encoder_)
|
|
{
|
|
const auto& v = *impl_->video_encoder_;
|
|
|
|
CONS_Printf(
|
|
"Video: %s %dx%d %d fps %d threads\n",
|
|
v.name(),
|
|
v.width(),
|
|
v.height(),
|
|
v.frame_rate(),
|
|
v.thread_count()
|
|
);
|
|
}
|
|
}
|
|
|
|
void AVRecorder::draw_statistics() const
|
|
{
|
|
SRB2_ASSERT(impl_->video_encoder_ != nullptr);
|
|
|
|
auto draw = [](int x, const srb2::String text, int32_t flags = 0)
|
|
{
|
|
V_DrawThinString(
|
|
x,
|
|
190,
|
|
(V_SNAPTOBOTTOM | V_SNAPTORIGHT) | flags,
|
|
text.c_str()
|
|
);
|
|
};
|
|
|
|
const float fps = impl_->video_frame_rate_avg_;
|
|
const float size = impl_->container_->size();
|
|
|
|
const int32_t fps_color = [&]
|
|
{
|
|
const int cap = impl_->video_encoder_->frame_rate();
|
|
|
|
// red when dropped below 60% of the target
|
|
if (fps > 0.f && fps < (0.6f * cap))
|
|
{
|
|
return V_REDMAP;
|
|
}
|
|
|
|
return 0;
|
|
}();
|
|
|
|
const int32_t mb_color = [&]
|
|
{
|
|
if (!impl_->max_size_)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
const std::size_t cap = *impl_->max_size_;
|
|
|
|
// yellow when within 1 MB of the limit
|
|
if (size >= (cap - kMb))
|
|
{
|
|
return V_YELLOWMAP;
|
|
}
|
|
|
|
return 0;
|
|
}();
|
|
|
|
draw(200, srb2::format("{:.0f}", fps), fps_color);
|
|
draw(230, srb2::format("{:.1f}s", impl_->container_->duration().count()));
|
|
draw(260, srb2::format("{:.1f} MB", size / kMb), mb_color);
|
|
}
|