mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-12-28 02:32:48 +00:00
media: fix undefined behavior with options initialization order
Cvar vector was not guaranteed to initialize before options for each encoder, potentially leading to no encoder cvars being registered.
This commit is contained in:
parent
860693936f
commit
02fe7ec744
8 changed files with 87 additions and 75 deletions
|
|
@ -89,7 +89,7 @@ void M_AVRecorder_AddCommands(void)
|
|||
CV_RegisterVar(&cv_movie_size);
|
||||
CV_RegisterVar(&cv_movie_sound);
|
||||
|
||||
srb2::media::register_options();
|
||||
srb2::media::Options::register_all();
|
||||
}
|
||||
|
||||
static AVRecorder::Config configure()
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
encoder.hpp
|
||||
options.cpp
|
||||
options.hpp
|
||||
options_values.cpp
|
||||
video_encoder.hpp
|
||||
video_frame.hpp
|
||||
vorbis.cpp
|
||||
|
|
|
|||
|
|
@ -19,14 +19,12 @@
|
|||
|
||||
using namespace srb2::media;
|
||||
|
||||
static std::vector<consvar_t*> g_cvars;
|
||||
|
||||
Options::Options(const char* prefix, map_t map) : prefix_(prefix), map_(map)
|
||||
{
|
||||
for (auto& [suffix, cvar] : map_)
|
||||
{
|
||||
cvar.name = strdup(fmt::format("{}_{}", prefix_, suffix).c_str());
|
||||
g_cvars.emplace_back(&cvar);
|
||||
cvars_.emplace_back(&cvar);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -107,12 +105,12 @@ consvar_t Options::value_map<int>(const char* default_value, std::map<const char
|
|||
return CVAR_INIT(nullptr, default_value, CV_SAVE, arr, nullptr);
|
||||
}
|
||||
|
||||
void srb2::media::register_options()
|
||||
void Options::register_all()
|
||||
{
|
||||
for (auto cvar : g_cvars)
|
||||
for (auto cvar : cvars_)
|
||||
{
|
||||
CV_RegisterVar(cvar);
|
||||
}
|
||||
|
||||
g_cvars = {};
|
||||
cvars_ = {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@
|
|||
#define __SRB2_MEDIA_OPTIONS_HPP__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "../command.h"
|
||||
|
||||
|
|
@ -21,7 +23,10 @@ namespace srb2::media
|
|||
class Options
|
||||
{
|
||||
public:
|
||||
using map_t = std::unordered_map<const char*, consvar_t>;
|
||||
using map_t = std::unordered_map<std::string, consvar_t>;
|
||||
|
||||
// Registers all options as cvars.
|
||||
static void register_all();
|
||||
|
||||
Options(const char* prefix, map_t map);
|
||||
|
||||
|
|
@ -38,14 +43,14 @@ public:
|
|||
static consvar_t value_map(const char* default_value, std::map<const char*, T> values);
|
||||
|
||||
private:
|
||||
static std::vector<consvar_t*> cvars_;
|
||||
|
||||
const char* prefix_;
|
||||
map_t map_;
|
||||
|
||||
const consvar_t& cvar(const char* option) const;
|
||||
};
|
||||
|
||||
void register_options();
|
||||
|
||||
}; // namespace srb2::media
|
||||
|
||||
#endif // __SRB2_MEDIA_OPTIONS_HPP__
|
||||
|
|
|
|||
62
src/media/options_values.cpp
Normal file
62
src/media/options_values.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// 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 <cstdint>
|
||||
|
||||
#include <vpx/vpx_encoder.h>
|
||||
|
||||
#include "options.hpp"
|
||||
#include "vorbis.hpp"
|
||||
#include "vp8.hpp"
|
||||
|
||||
using namespace srb2::media;
|
||||
|
||||
// NOTE: Options::cvars_ MUST be initialized before any
|
||||
// Options instances construct. For static objects, they have
|
||||
// to be defined in the same translation unit as
|
||||
// Options::cvars_ to guarantee initialization order.
|
||||
|
||||
std::vector<consvar_t*> Options::cvars_;
|
||||
|
||||
// clang-format off
|
||||
const Options VorbisEncoder::options_("vorbis", {
|
||||
{"quality", Options::range<float>("0", -0.1f, 1.f)},
|
||||
{"max_bitrate", Options::range_min<int>("-1", -1)},
|
||||
{"nominal_bitrate", Options::range_min<int>("-1", -1)},
|
||||
{"min_bitrate", Options::range_min<int>("-1", -1)},
|
||||
});
|
||||
|
||||
const Options VP8Encoder::options_("vp8", {
|
||||
{"quality_mode", Options::value_map<int>("q", {
|
||||
{"vbr", VPX_VBR},
|
||||
{"cbr", VPX_CBR},
|
||||
{"cq", VPX_CQ},
|
||||
{"q", VPX_Q},
|
||||
})},
|
||||
{"target_bitrate", Options::range_min<int>("800", 1)},
|
||||
{"min_q", Options::range<int>("4", 4, 63)},
|
||||
{"max_q", Options::range<int>("55", 4, 63)},
|
||||
{"kf_min", Options::range_min<int>("0", 0)},
|
||||
{"kf_max", Options::value_map<int>("auto", {
|
||||
{"auto", static_cast<int>(KeyFrameOption::kAuto)},
|
||||
{"MIN", 0},
|
||||
{"MAX", INT32_MAX},
|
||||
})},
|
||||
{"cpu_used", Options::range<int>("0", -16, 16)},
|
||||
{"cq_level", Options::range<int>("10", 0, 63)},
|
||||
{"deadline", Options::value_map<int>("10", {
|
||||
{"infinite", static_cast<int>(DeadlineOption::kInfinite)},
|
||||
{"MIN", 1},
|
||||
{"MAX", INT32_MAX},
|
||||
})},
|
||||
{"sharpness", Options::range<int>("7", 0, 7)},
|
||||
{"token_parts", Options::range<int>("0", 0, 3)},
|
||||
{"threads", Options::range_min<int>("1", 1)},
|
||||
});
|
||||
// clang-format on
|
||||
|
|
@ -20,15 +20,6 @@
|
|||
|
||||
using namespace srb2::media;
|
||||
|
||||
// clang-format off
|
||||
const Options VorbisEncoder::options_("vorbis", {
|
||||
{"quality", Options::range<float>("0", -0.1f, 1.f)},
|
||||
{"max_bitrate", Options::range_min<int>("-1", -1)},
|
||||
{"nominal_bitrate", Options::range_min<int>("-1", -1)},
|
||||
{"min_bitrate", Options::range_min<int>("-1", -1)},
|
||||
});
|
||||
// clang-format on
|
||||
|
||||
VorbisEncoder::VorbisEncoder(Config cfg)
|
||||
{
|
||||
const long max_bitrate = options_.get<int>("max_bitrate");
|
||||
|
|
|
|||
|
|
@ -24,61 +24,6 @@
|
|||
|
||||
using namespace srb2::media;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
namespace KeyFrameOption
|
||||
{
|
||||
|
||||
enum : int
|
||||
{
|
||||
kAuto = -1,
|
||||
};
|
||||
|
||||
}; // namespace KeyFrameOption
|
||||
|
||||
namespace DeadlineOption
|
||||
{
|
||||
|
||||
enum : int
|
||||
{
|
||||
kInfinite = 0,
|
||||
};
|
||||
|
||||
}; // namespace DeadlineOption
|
||||
|
||||
}; // namespace
|
||||
|
||||
// clang-format off
|
||||
const Options VP8Encoder::options_("vp8", {
|
||||
{"quality_mode", Options::value_map<int>("q", {
|
||||
{"vbr", VPX_VBR},
|
||||
{"cbr", VPX_CBR},
|
||||
{"cq", VPX_CQ},
|
||||
{"q", VPX_Q},
|
||||
})},
|
||||
{"target_bitrate", Options::range_min<int>("800", 1)},
|
||||
{"min_q", Options::range<int>("4", 4, 63)},
|
||||
{"max_q", Options::range<int>("55", 4, 63)},
|
||||
{"kf_min", Options::range_min<int>("0", 0)},
|
||||
{"kf_max", Options::value_map<int>("auto", {
|
||||
{"auto", KeyFrameOption::kAuto},
|
||||
{"MIN", 0},
|
||||
{"MAX", INT32_MAX},
|
||||
})},
|
||||
{"cpu_used", Options::range<int>("0", -16, 16)},
|
||||
{"cq_level", Options::range<int>("10", 0, 63)},
|
||||
{"deadline", Options::value_map<int>("10", {
|
||||
{"infinite", DeadlineOption::kInfinite},
|
||||
{"MIN", 1},
|
||||
{"MAX", INT32_MAX},
|
||||
})},
|
||||
{"sharpness", Options::range<int>("7", 0, 7)},
|
||||
{"token_parts", Options::range<int>("0", 0, 3)},
|
||||
{"threads", Options::range_min<int>("1", 1)},
|
||||
});
|
||||
// clang-format on
|
||||
|
||||
vpx_codec_iface_t* VP8Encoder::kCodec = vpx_codec_vp8_cx();
|
||||
|
||||
const vpx_codec_enc_cfg_t VP8Encoder::configure(const Config user)
|
||||
|
|
@ -110,7 +55,7 @@ const vpx_codec_enc_cfg_t VP8Encoder::configure(const Config user)
|
|||
|
||||
int kf_max = options_.get<int>("kf_max");
|
||||
|
||||
if (kf_max == KeyFrameOption::kAuto)
|
||||
if (kf_max == static_cast<int>(KeyFrameOption::kAuto))
|
||||
{
|
||||
// Automatically pick a good rate
|
||||
kf_max = (user.frame_rate / 2); // every .5s
|
||||
|
|
|
|||
|
|
@ -69,6 +69,16 @@ private:
|
|||
vpx_image_t img_;
|
||||
};
|
||||
|
||||
enum class KeyFrameOption : int
|
||||
{
|
||||
kAuto = -1,
|
||||
};
|
||||
|
||||
enum class DeadlineOption : int
|
||||
{
|
||||
kInfinite = 0,
|
||||
};
|
||||
|
||||
static vpx_codec_iface_t* kCodec;
|
||||
|
||||
static const vpx_codec_enc_cfg_t configure(const Config config);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue