diff --git a/src/m_avrecorder.cpp b/src/m_avrecorder.cpp index cfdd22454..7491fb195 100644 --- a/src/m_avrecorder.cpp +++ b/src/m_avrecorder.cpp @@ -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() diff --git a/src/media/CMakeLists.txt b/src/media/CMakeLists.txt index daa0e721a..014264d75 100644 --- a/src/media/CMakeLists.txt +++ b/src/media/CMakeLists.txt @@ -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 diff --git a/src/media/options.cpp b/src/media/options.cpp index b933d9ad0..1a060c847 100644 --- a/src/media/options.cpp +++ b/src/media/options.cpp @@ -19,14 +19,12 @@ using namespace srb2::media; -static std::vector 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(const char* default_value, std::map +#include #include +#include #include "../command.h" @@ -21,7 +23,10 @@ namespace srb2::media class Options { public: - using map_t = std::unordered_map; + using map_t = std::unordered_map; + + // 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 values); private: + static std::vector 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__ diff --git a/src/media/options_values.cpp b/src/media/options_values.cpp new file mode 100644 index 000000000..941958633 --- /dev/null +++ b/src/media/options_values.cpp @@ -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 + +#include + +#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 Options::cvars_; + +// clang-format off +const Options VorbisEncoder::options_("vorbis", { + {"quality", Options::range("0", -0.1f, 1.f)}, + {"max_bitrate", Options::range_min("-1", -1)}, + {"nominal_bitrate", Options::range_min("-1", -1)}, + {"min_bitrate", Options::range_min("-1", -1)}, +}); + +const Options VP8Encoder::options_("vp8", { + {"quality_mode", Options::value_map("q", { + {"vbr", VPX_VBR}, + {"cbr", VPX_CBR}, + {"cq", VPX_CQ}, + {"q", VPX_Q}, + })}, + {"target_bitrate", Options::range_min("800", 1)}, + {"min_q", Options::range("4", 4, 63)}, + {"max_q", Options::range("55", 4, 63)}, + {"kf_min", Options::range_min("0", 0)}, + {"kf_max", Options::value_map("auto", { + {"auto", static_cast(KeyFrameOption::kAuto)}, + {"MIN", 0}, + {"MAX", INT32_MAX}, + })}, + {"cpu_used", Options::range("0", -16, 16)}, + {"cq_level", Options::range("10", 0, 63)}, + {"deadline", Options::value_map("10", { + {"infinite", static_cast(DeadlineOption::kInfinite)}, + {"MIN", 1}, + {"MAX", INT32_MAX}, + })}, + {"sharpness", Options::range("7", 0, 7)}, + {"token_parts", Options::range("0", 0, 3)}, + {"threads", Options::range_min("1", 1)}, +}); +// clang-format on diff --git a/src/media/vorbis.cpp b/src/media/vorbis.cpp index 6b33aa22e..da331e464 100644 --- a/src/media/vorbis.cpp +++ b/src/media/vorbis.cpp @@ -20,15 +20,6 @@ using namespace srb2::media; -// clang-format off -const Options VorbisEncoder::options_("vorbis", { - {"quality", Options::range("0", -0.1f, 1.f)}, - {"max_bitrate", Options::range_min("-1", -1)}, - {"nominal_bitrate", Options::range_min("-1", -1)}, - {"min_bitrate", Options::range_min("-1", -1)}, -}); -// clang-format on - VorbisEncoder::VorbisEncoder(Config cfg) { const long max_bitrate = options_.get("max_bitrate"); diff --git a/src/media/vp8.cpp b/src/media/vp8.cpp index 341b1b932..230721844 100644 --- a/src/media/vp8.cpp +++ b/src/media/vp8.cpp @@ -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("q", { - {"vbr", VPX_VBR}, - {"cbr", VPX_CBR}, - {"cq", VPX_CQ}, - {"q", VPX_Q}, - })}, - {"target_bitrate", Options::range_min("800", 1)}, - {"min_q", Options::range("4", 4, 63)}, - {"max_q", Options::range("55", 4, 63)}, - {"kf_min", Options::range_min("0", 0)}, - {"kf_max", Options::value_map("auto", { - {"auto", KeyFrameOption::kAuto}, - {"MIN", 0}, - {"MAX", INT32_MAX}, - })}, - {"cpu_used", Options::range("0", -16, 16)}, - {"cq_level", Options::range("10", 0, 63)}, - {"deadline", Options::value_map("10", { - {"infinite", DeadlineOption::kInfinite}, - {"MIN", 1}, - {"MAX", INT32_MAX}, - })}, - {"sharpness", Options::range("7", 0, 7)}, - {"token_parts", Options::range("0", 0, 3)}, - {"threads", Options::range_min("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("kf_max"); - if (kf_max == KeyFrameOption::kAuto) + if (kf_max == static_cast(KeyFrameOption::kAuto)) { // Automatically pick a good rate kf_max = (user.frame_rate / 2); // every .5s diff --git a/src/media/vp8.hpp b/src/media/vp8.hpp index b4c68f24d..49502ad9e 100644 --- a/src/media/vp8.hpp +++ b/src/media/vp8.hpp @@ -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);