media/options: refactor cvar factory completely, ensure correct MIN/MAX order

This commit is contained in:
James R 2023-02-13 13:13:43 -08:00
parent 02fe7ec744
commit aefc12e40e
3 changed files with 73 additions and 74 deletions

View file

@ -9,7 +9,7 @@
#include <cstddef>
#include <cstdint>
#include <vector>
#include <type_traits>
#include <fmt/format.h>
@ -49,60 +49,56 @@ float Options::get<float>(const char* option) const
return FixedToFloat(cvar(option).value);
}
static consvar_t range_cvar(const char* default_value, int32_t min, int32_t max, int32_t flags = 0)
template <typename T>
consvar_t Options::values(const char* default_value, const Range<T> range, std::map<std::string_view, T> list)
{
return CVAR_INIT(
nullptr,
default_value,
CV_SAVE | flags,
new CV_PossibleValue_t[] {{min, "MIN"}, {max, "MAX"}, {}},
nullptr
);
}
constexpr bool is_float = std::is_floating_point_v<T>;
template <>
consvar_t Options::range<float>(const char* default_value, float min, float max)
{
return range_cvar(default_value, FloatToFixed(min), FloatToFixed(max), CV_FLOAT);
}
const std::size_t min_max_size = (range.min || range.max) ? 2 : 0;
auto* arr = new CV_PossibleValue_t[list.size() + min_max_size + 1];
template <>
consvar_t Options::range_min<float>(const char* default_value, float min)
{
return range_cvar(default_value, FloatToFixed(min), INT32_MAX);
}
template <>
consvar_t Options::range<int>(const char* default_value, int min, int max)
{
return range_cvar(default_value, min, max);
}
template <>
consvar_t Options::range_min<int>(const char* default_value, int min)
{
return range_cvar(default_value, min, INT32_MAX);
}
template <>
consvar_t Options::value_map<int>(const char* default_value, std::map<const char*, int> values)
{
auto* arr = new CV_PossibleValue_t[values.size() + 1];
std::size_t i = 0;
for (const auto& [k, v] : values)
auto cast = [is_float](T n)
{
arr[i].value = v;
arr[i].strvalue = k;
if constexpr (is_float)
{
return FloatToFixed(n);
}
else
{
return n;
}
};
i++;
if (min_max_size)
{
// Order is very important, MIN then MAX.
arr[0] = {range.min ? cast(*range.min) : INT32_MIN, "MIN"};
arr[1] = {range.max ? cast(*range.max) : INT32_MAX, "MAX"};
}
arr[i].value = 0;
arr[i].strvalue = nullptr;
{
std::size_t i = min_max_size;
return CVAR_INIT(nullptr, default_value, CV_SAVE, arr, nullptr);
for (const auto& [k, v] : list)
{
arr[i].value = cast(v);
arr[i].strvalue = k.data();
i++;
}
arr[i].value = 0;
arr[i].strvalue = nullptr;
}
int32_t flags = CV_SAVE;
if constexpr (is_float)
{
flags |= CV_FLOAT;
}
return CVAR_INIT(nullptr, default_value, flags, arr, nullptr);
}
void Options::register_all()
@ -114,3 +110,8 @@ void Options::register_all()
cvars_ = {};
}
// clang-format off
template consvar_t Options::values(const char* default_value, const Range<int> range, std::map<std::string_view, int> list);
template consvar_t Options::values(const char* default_value, const Range<float> range, std::map<std::string_view, float> list);
// clang-format on

View file

@ -11,7 +11,9 @@
#define __SRB2_MEDIA_OPTIONS_HPP__
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
@ -25,6 +27,12 @@ class Options
public:
using map_t = std::unordered_map<std::string, consvar_t>;
template <typename T>
struct Range
{
std::optional<T> min, max;
};
// Registers all options as cvars.
static void register_all();
@ -34,13 +42,7 @@ public:
T get(const char* option) const;
template <typename T>
static consvar_t range(const char* default_value, T min, T max);
template <typename T>
static consvar_t range_min(const char* default_value, T min);
template <typename T>
static consvar_t value_map(const char* default_value, std::map<const char*, T> values);
static consvar_t values(const char* default_value, const Range<T> range, std::map<std::string_view, T> list = {});
private:
static std::vector<consvar_t*> cvars_;

View file

@ -26,37 +26,33 @@ 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)},
{"quality", Options::values<float>("0", {-0.1f, 1.f})},
{"max_bitrate", Options::values<int>("-1", {.min = -1})},
{"nominal_bitrate", Options::values<int>("-1", {.min = -1})},
{"min_bitrate", Options::values<int>("-1", {.min = -1})},
});
const Options VP8Encoder::options_("vp8", {
{"quality_mode", Options::value_map<int>("q", {
{"quality_mode", Options::values<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", {
{"target_bitrate", Options::values<int>("800", {.min = 1})},
{"min_q", Options::values<int>("4", {4, 63})},
{"max_q", Options::values<int>("55", {4, 63})},
{"kf_min", Options::values<int>("0", {.min = 0})},
{"kf_max", Options::values<int>("auto", {.min = 0}, {
{"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", {
{"cpu_used", Options::values<int>("0", {-16, 16})},
{"cq_level", Options::values<int>("10", {0, 63})},
{"deadline", Options::values<int>("10", { .min = 1}, {
{"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)},
{"sharpness", Options::values<int>("7", {0, 7})},
{"token_parts", Options::values<int>("0", {0, 3})},
{"threads", Options::values<int>("1", {.min = 1})},
});
// clang-format on