#include "video_policy.h" #include #include #include namespace video::policy { namespace { bool equals_case_insensitive(std::string_view left, std::string_view right) { return left.size() == right.size() && std::equal( left.begin(), left.end(), right.begin(), [](const char lhs, const char rhs) { return std::tolower(static_cast(lhs)) == std::tolower(static_cast(rhs)); } ); } } // namespace bool may_apply_process_display_preference(const capture_selection_e selection) { return selection == capture_selection_e::process_preferred; } std::optional select_manual_display_output( const capture_selection_e selection, const int requested_index, const std::span display_names ) { if (selection != capture_selection_e::process_preferred || requested_index < 0 || display_names.empty()) { return std::nullopt; } const auto index = std::clamp(requested_index, 0, static_cast(display_names.size()) - 1); return display_names[static_cast(index)]; } std::optional resolve_display_output( const std::string_view output_identity, const std::span display_names ) { const auto found = std::find_if(display_names.begin(), display_names.end(), [&](const std::string &name) { return equals_case_insensitive(name, output_identity); }); if (found == display_names.end()) { return std::nullopt; } return static_cast(std::distance(display_names.begin(), found)); } std::chrono::milliseconds display_retry_delay(const std::size_t consecutive_failures) { constexpr auto initial_delay = std::chrono::milliseconds {50}; constexpr auto maximum_delay = std::chrono::milliseconds {2000}; constexpr std::size_t maximum_shift = 6; const auto shift = std::min(consecutive_failures, maximum_shift); const auto multiplier = static_cast(std::size_t {1} << shift); return std::min(initial_delay * multiplier, maximum_delay); } bool should_log_display_retry(const std::size_t consecutive_failures) { return consecutive_failures == 0 || (consecutive_failures & (consecutive_failures - 1)) == 0; } rational_t framerate_x100_to_rational(std::int32_t value) { if (value % 2997 == 0) return {(value / 2997) * 30000, 1001}; if (value == 2397 || value == 2398) return {24000, 1001}; const auto divisor = std::gcd(value, 100); return {value / divisor, 100 / divisor}; } std::optional select_encoder( std::span preference, encoder_requirements_t requirements, const encoder_capability_provider_t &provider ) { for (const auto name : preference) { const auto caps = provider.capabilities(name); if (caps.available && (!requirements.hdr || caps.hdr) && (!requirements.yuv444 || caps.yuv444)) { return std::string(name); } } return std::nullopt; } std::optional select_preferred_virtual_output( std::string_view configured_output, std::span active_virtual_outputs, std::span all_virtual_outputs ) { const auto find_configured = [&](std::span outputs) -> std::optional { if (configured_output.empty()) { return std::nullopt; } const auto found = std::find_if(outputs.begin(), outputs.end(), [&](const std::string &output) { return equals_case_insensitive(output, configured_output); }); return found == outputs.end() ? std::nullopt : std::optional {*found}; }; if (auto configured = find_configured(active_virtual_outputs)) { return configured; } if (auto configured = find_configured(all_virtual_outputs)) { return configured; } if (!active_virtual_outputs.empty()) { return active_virtual_outputs.front(); } if (!all_virtual_outputs.empty()) { return all_virtual_outputs.front(); } return std::nullopt; } } // namespace video::policy