diff --git a/include/libvideo2x/fsutils.h b/include/libvideo2x/fsutils.h index b38894e7a..b31094895 100644 --- a/include/libvideo2x/fsutils.h +++ b/include/libvideo2x/fsutils.h @@ -1,12 +1,41 @@ #ifndef FSUTILS_H #define FSUTILS_H +#ifdef __cplusplus #include +#endif + +#ifdef _WIN32 +#ifdef UNICODE +typedef wchar_t CharType; +#define STR(x) L##x +#else +typedef char CharType; +#define STR(x) x +#endif +#else +typedef char CharType; +#define STR(x) x +#endif + +#ifdef __cplusplus +#include +#ifdef _WIN32 +#ifdef UNICODE +typedef std::wstring StringType; +#else +typedef std::string StringType; +#endif +#else +typedef std::string StringType; +#endif bool filepath_is_readable(const std::filesystem::path &path); std::filesystem::path find_resource_file(const std::filesystem::path &path); -std::string path_to_string(const std::filesystem::path& path); +std::string path_to_string(const std::filesystem::path &path); + +#endif // __cplusplus #endif // FSUTILS_H diff --git a/include/libvideo2x/libvideo2x.h b/include/libvideo2x/libvideo2x.h index 201c8600f..5e491b16c 100644 --- a/include/libvideo2x/libvideo2x.h +++ b/include/libvideo2x/libvideo2x.h @@ -5,6 +5,13 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + #ifdef _WIN32 #ifdef LIBVIDEO2X_EXPORTS #define LIBVIDEO2X_API __declspec(dllexport) @@ -15,13 +22,12 @@ #define LIBVIDEO2X_API #endif -#ifdef __cplusplus -extern "C" { +#ifdef _WIN32 +typedef wchar_t tchar; +#else +typedef char tchar; #endif -#include -#include - // Enum to specify filter type enum FilterType { FILTER_LIBPLACEBO, @@ -43,11 +49,7 @@ enum Libvideo2xLogLevel { struct LibplaceboConfig { int out_width; int out_height; -#ifdef _WIN32 - const wchar_t *shader_path; -#else - const char *shader_path; -#endif + const tchar *shader_path; }; // Configuration for RealESRGAN filter @@ -55,11 +57,7 @@ struct RealESRGANConfig { int gpuid; bool tta_mode; int scaling_factor; -#ifdef _WIN32 - const wchar_t *model_name; -#else - const char *model_name; -#endif + const tchar *model_name; }; // Unified filter configuration @@ -93,15 +91,22 @@ struct VideoProcessingContext { bool completed; }; -// C-compatible process_video function +/** + * @brief Process a video file using the selected filter and encoder settings. + * + * @param[in] in_fname Path to the input video file + * @param[in] out_fname Path to the output video file + * @param[in] log_level Log level + * @param[in] benchmark Flag to enable benchmarking mode + * @param[in] hw_type Hardware device type + * @param[in] filter_config Filter configurations + * @param[in] encoder_config Encoder configurations + * @param[in,out] proc_ctx Video processing context + * @return int 0 on success, non-zero value on error + */ LIBVIDEO2X_API int process_video( -#ifdef _WIN32 - const wchar_t *in_fname, - const wchar_t *out_fname, -#else - const char *in_fname, - const char *out_fname, -#endif + const tchar *in_fname, + const tchar *out_fname, enum Libvideo2xLogLevel log_level, bool benchmark, enum AVHWDeviceType hw_device_type, diff --git a/include/libvideo2x/realesrgan_filter.h b/include/libvideo2x/realesrgan_filter.h index f7089fad4..697e651a8 100644 --- a/include/libvideo2x/realesrgan_filter.h +++ b/include/libvideo2x/realesrgan_filter.h @@ -6,6 +6,7 @@ extern "C" { } #include "filter.h" +#include "fsutils.h" #include "realesrgan.h" // RealesrganFilter class definition @@ -15,11 +16,7 @@ class RealesrganFilter : public Filter { int gpuid; bool tta_mode; int scaling_factor; -#ifdef _WIN32 - const std::wstring model_name; -#else - const std::string model_name; -#endif + const StringType model_name; AVRational in_time_base; AVRational out_time_base; AVPixelFormat out_pix_fmt; @@ -30,11 +27,7 @@ class RealesrganFilter : public Filter { int gpuid = 0, bool tta_mode = false, int scaling_factor = 4, -#ifdef _WIN32 - const std::wstring model_name = L"realesr-animevideov3" -#else - const std::string model_name = "realesr-animevideov3" -#endif + const StringType model_name = STR("realesr-animevideov3") ); // Destructor diff --git a/src/libplacebo_filter.cpp b/src/libplacebo_filter.cpp index 94f800eb5..1f58c746b 100644 --- a/src/libplacebo_filter.cpp +++ b/src/libplacebo_filter.cpp @@ -43,11 +43,8 @@ int LibplaceboFilter::init(AVCodecContext *dec_ctx, AVCodecContext *enc_ctx, AVB } else { // Construct the fallback path using std::filesystem shader_full_path = find_resource_file( -#ifdef _WIN32 - std::filesystem::path("models") / L"libplacebo" / (shader_path.wstring() + L".glsl") -#else - std::filesystem::path("models") / "libplacebo" / (shader_path.string() + ".glsl") -#endif + std::filesystem::path(STR("models")) / STR("libplacebo") / + (path_to_string(shader_path) + STR(".glsl")) ); } diff --git a/src/libvideo2x.cpp b/src/libvideo2x.cpp index 375d6922d..8dc31cea5 100644 --- a/src/libvideo2x.cpp +++ b/src/libvideo2x.cpp @@ -14,24 +14,11 @@ extern "C" { #include "decoder.h" #include "encoder.h" #include "filter.h" +#include "fsutils.h" #include "libplacebo_filter.h" #include "realesrgan_filter.h" -/** - * @brief Process frames using the selected filter. - * - * @param[in] encoder_config Encoder configurations - * @param[in,out] proc_ctx Struct containing the processing context - * @param[in] ifmt_ctx Input format context - * @param[in] ofmt_ctx Output format context - * @param[in] dec_ctx Decoder context - * @param[in] enc_ctx Encoder context - * @param[in] filter Filter instance - * @param[in] vstream_idx Index of the video stream in the input format context - * @param[in] stream_map Array mapping input stream indexes to output stream indexes - * @param[in] benchmark Flag to enable benchmarking mode - * @return int 0 on success, negative value on error - */ +// Process frames using the selected filter. static int process_frames( EncoderConfig *encoder_config, VideoProcessingContext *proc_ctx, @@ -252,27 +239,9 @@ static int process_frames( return ret; } -/** - * @brief Process a video file using the selected filter and encoder settings. - * - * @param[in] in_fname Path to the input video file - * @param[in] out_fname Path to the output video file - * @param[in] log_level Log level - * @param[in] benchmark Flag to enable benchmarking mode - * @param[in] hw_type Hardware device type - * @param[in] filter_config Filter configurations - * @param[in] encoder_config Encoder configurations - * @param[in,out] proc_ctx Video processing context - * @return int 0 on success, non-zero value on error - */ extern "C" int process_video( -#ifdef _WIN32 - const wchar_t *in_fname, - const wchar_t *out_fname, -#else - const char *in_fname, - const char *out_fname, -#endif + const CharType *in_fname, + const CharType *out_fname, Libvideo2xLogLevel log_level, bool benchmark, AVHWDeviceType hw_type, @@ -454,7 +423,7 @@ extern "C" int process_video( return -1; } filter = new RealesrganFilter{ - config.gpuid, config.tta_mode, config.scaling_factor, config.model_name + config.gpuid, config.tta_mode, config.scaling_factor, StringType(config.model_name) }; } else { spdlog::error("Unknown filter type"); diff --git a/src/realesrgan_filter.cpp b/src/realesrgan_filter.cpp index 992be231b..66043a25c 100644 --- a/src/realesrgan_filter.cpp +++ b/src/realesrgan_filter.cpp @@ -8,24 +8,18 @@ #include #include "conversions.h" -#include "fsutils.h" RealesrganFilter::RealesrganFilter( int gpuid, bool tta_mode, int scaling_factor, -#ifdef _WIN32 - const std::wstring model_name -#else - const std::string model_name -#endif + const StringType model_name ) : realesrgan(nullptr), gpuid(gpuid), tta_mode(tta_mode), scaling_factor(scaling_factor), - model_name(std::move(model_name)) { -} + model_name(std::move(model_name)) {} RealesrganFilter::~RealesrganFilter() { if (realesrgan) { @@ -39,17 +33,14 @@ int RealesrganFilter::init(AVCodecContext *dec_ctx, AVCodecContext *enc_ctx, AVB std::filesystem::path model_param_path; std::filesystem::path model_bin_path; -#ifdef _WIN32 - std::wstring param_file_name = model_name + L"-x" + std::to_wstring(scaling_factor) + L".param"; - std::wstring bin_file_name = model_name + L"-x" + std::to_wstring(scaling_factor) + L".bin"; -#else - std::string param_file_name = model_name + "-x" + std::to_string(scaling_factor) + ".param"; - std::string bin_file_name = model_name + "-x" + std::to_string(scaling_factor) + ".bin"; -#endif + std::string param_file_name = + model_name + STR("-x") + std::to_string(scaling_factor) + STR(".param"); + std::string bin_file_name = + model_name + STR("-x") + std::to_string(scaling_factor) + STR(".bin"); // Find the model paths by model name if provided - model_param_path = std::filesystem::path("models") / "realesrgan" / param_file_name; - model_bin_path = std::filesystem::path("models") / "realesrgan" / bin_file_name; + model_param_path = std::filesystem::path(STR("models")) / STR("realesrgan") / param_file_name; + model_bin_path = std::filesystem::path(STR("models")) / STR("realesrgan") / bin_file_name; // Get the full paths using a function that possibly modifies or validates the path std::filesystem::path model_param_full_path = find_resource_file(model_param_path); diff --git a/src/video2x.cpp b/src/video2x.cpp index 219ed5c94..a1ca07168 100644 --- a/src/video2x.cpp +++ b/src/video2x.cpp @@ -36,10 +36,14 @@ extern "C" { #ifdef _WIN32 #define BOOST_PROGRAM_OPTIONS_WCHAR_T +#define PO_STR_VALUE po::wvalue +#else +#define PO_STR_VALUE po::value #endif #include namespace po = boost::program_options; +#include "libvideo2x/fsutils.h" #include "libvideo2x/timer.h" // Indicate if a newline needs to be printed before the next output @@ -48,31 +52,19 @@ std::atomic newline_required = false; // Structure to hold parsed arguments struct Arguments { // General options -#ifdef _WIN32 - std::wstring loglevel = L"info"; - std::wstring filter_type; - std::wstring hwaccel = L"none"; -#else - std::string loglevel = "info"; - std::string filter_type; - std::string hwaccel = "none"; -#endif - bool noprogress = false; std::filesystem::path in_fname; std::filesystem::path out_fname; + StringType filter_type; + StringType hwaccel = STR("none"); bool nocopystreams = false; bool benchmark = false; + StringType loglevel = STR("info"); + bool noprogress = false; // Encoder options -#ifdef _WIN32 - std::wstring codec = L"libx264"; - std::wstring pix_fmt; - std::wstring preset = L"slow"; -#else - std::string codec = "libx264"; - std::string pix_fmt; - std::string preset = "slow"; -#endif + StringType codec = STR("libx264"); + StringType preset = ("slow"); + StringType pix_fmt; int64_t bitrate = 0; float crf = 20.0f; @@ -82,12 +74,8 @@ struct Arguments { int out_height = 0; // RealESRGAN options -#ifdef _WIN32 - std::wstring model_name; -#else - std::string model_name; -#endif int gpuid = 0; + StringType model_name; int scaling_factor = 0; }; @@ -145,27 +133,27 @@ void newline_safe_ffmpeg_log_callback(void *ptr, int level, const char *fmt, va_ av_log_default_callback(ptr, level, fmt, vl); } -bool is_valid_realesrgan_model(const std::string &model) { - static const std::unordered_set valid_realesrgan_models = { - "realesrgan-plus", "realesrgan-plus-anime", "realesr-animevideov3" +bool is_valid_realesrgan_model(const StringType &model) { + static const std::unordered_set valid_realesrgan_models = { + STR("realesrgan-plus"), STR("realesrgan-plus-anime"), STR("realesr-animevideov3") }; return valid_realesrgan_models.count(model) > 0; } -enum Libvideo2xLogLevel parse_log_level(const std::string &level_name) { - if (level_name == "trace") { +enum Libvideo2xLogLevel parse_log_level(const StringType &level_name) { + if (level_name == STR("trace")) { return LIBVIDEO2X_LOG_LEVEL_TRACE; - } else if (level_name == "debug") { + } else if (level_name == STR("debug")) { return LIBVIDEO2X_LOG_LEVEL_DEBUG; - } else if (level_name == "info") { + } else if (level_name == STR("info")) { return LIBVIDEO2X_LOG_LEVEL_INFO; - } else if (level_name == "warning" || level_name == "warn") { + } else if (level_name == STR("warning") || level_name == STR("warn")) { return LIBVIDEO2X_LOG_LEVEL_WARNING; - } else if (level_name == "error") { + } else if (level_name == STR("error")) { return LIBVIDEO2X_LOG_LEVEL_ERROR; - } else if (level_name == "critical") { + } else if (level_name == STR("critical")) { return LIBVIDEO2X_LOG_LEVEL_CRITICAL; - } else if (level_name == "off" || level_name == "none") { + } else if (level_name == STR("off") || level_name == STR("none")) { return LIBVIDEO2X_LOG_LEVEL_OFF; } else { spdlog::warn("Invalid log level specified. Defaulting to 'info'."); @@ -185,15 +173,9 @@ void process_video_thread( EncoderConfig *encoder_config, VideoProcessingContext *proc_ctx ) { - enum Libvideo2xLogLevel log_level = parse_log_level(wstring_to_utf8(arguments->loglevel)); - -#ifdef _WIN32 - const wchar_t *in_fname = arguments->in_fname.c_str(); - const wchar_t *out_fname = arguments->out_fname.c_str(); -#else - const char *in_fname = arguments->in_fname.c_str(); - const char *out_fname = arguments->out_fname.c_str(); -#endif + enum Libvideo2xLogLevel log_level = parse_log_level(arguments->loglevel); + const CharType *in_fname = arguments->in_fname.c_str(); + const CharType *out_fname = arguments->out_fname.c_str(); *proc_ret = process_video( in_fname, @@ -212,12 +194,11 @@ void process_video_thread( } } +int main(int argc, CharType *argv[]) { #ifdef _WIN32 -int wmain(int argc, wchar_t *argv[]) { SetConsoleOutputCP(CP_UTF8); -#else -int main(int argc, char **argv) { #endif + // Initialize arguments structure Arguments arguments; @@ -225,71 +206,37 @@ int main(int argc, char **argv) { try { po::options_description desc("Allowed options"); -#ifdef _WIN32 - desc.add_options() - ("help", "Display this help page") - ("version,v", "Print program version") - ("loglevel", po::wvalue(&arguments.loglevel), "Set log level (trace, debug, info, warn, error, critical, none)") - ("noprogress", po::bool_switch(&arguments.noprogress), "Do not display the progress bar") - - // General Processing Options - ("input,i", po::wvalue(), "Input video file path") - ("output,o", po::wvalue(), "Output video file path") - ("filter,f", po::wvalue(&arguments.filter_type), "Filter to use: 'libplacebo' or 'realesrgan'") - ("hwaccel,a", po::wvalue(&arguments.hwaccel), "Hardware acceleration method (default: none)") - ("nocopystreams", po::bool_switch(&arguments.nocopystreams), "Do not copy audio and subtitle streams") - ("benchmark", po::bool_switch(&arguments.benchmark), "Discard processed frames and calculate average FPS") - - // Encoder options - ("codec,c", po::wvalue(&arguments.codec), "Output codec (default: libx264)") - ("preset,p", po::wvalue(&arguments.preset), "Encoder preset (default: slow)") - ("pixfmt,x", po::wvalue(&arguments.pix_fmt), "Output pixel format (default: auto)") - ("bitrate,b", po::value(&arguments.bitrate)->default_value(0), "Bitrate in bits per second (default: 0 (VBR))") - ("crf,q", po::value(&arguments.crf)->default_value(20.0f), "Constant Rate Factor (default: 20.0)") - - // libplacebo options - ("shader,s", po::wvalue(), "Name or path of the GLSL shader file to use") - ("width,w", po::value(&arguments.out_width), "Output width") - ("height,h", po::value(&arguments.out_height), "Output height") - - // RealESRGAN options - ("gpuid,g", po::value(&arguments.gpuid)->default_value(0), "Vulkan GPU ID (default: 0)") - ("model,m", po::wvalue(&arguments.model_name), "Name of the model to use") - ("scale,r", po::value(&arguments.scaling_factor), "Scaling factor (2, 3, or 4)") - ; -#else desc.add_options() ("help", "Display this help page") ("version,v", "Print program version") - ("loglevel", po::value(&arguments.loglevel)->default_value("info"), "Set log level (trace, debug, info, warn, error, critical, none)") + ("loglevel", PO_STR_VALUE(&arguments.loglevel)->default_value(STR("info")), "Set log level (trace, debug, info, warn, error, critical, none)") ("noprogress", po::bool_switch(&arguments.noprogress), "Do not display the progress bar") // General Processing Options - ("input,i", po::value(), "Input video file path") - ("output,o", po::value(), "Output video file path") - ("filter,f", po::value(&arguments.filter_type), "Filter to use: 'libplacebo' or 'realesrgan'") - ("hwaccel,a", po::value(&arguments.hwaccel)->default_value("none"), "Hardware acceleration method (default: none)") + ("input,i", PO_STR_VALUE(), "Input video file path") + ("output,o", PO_STR_VALUE(), "Output video file path") + ("filter,f", PO_STR_VALUE(&arguments.filter_type), "Filter to use: 'libplacebo' or 'realesrgan'") + ("hwaccel,a", PO_STR_VALUE(&arguments.hwaccel)->default_value(STR("none")), "Hardware acceleration method (default: none)") ("nocopystreams", po::bool_switch(&arguments.nocopystreams), "Do not copy audio and subtitle streams") ("benchmark", po::bool_switch(&arguments.benchmark), "Discard processed frames and calculate average FPS") // Encoder options - ("codec,c", po::value(&arguments.codec)->default_value("libx264"), "Output codec (default: libx264)") - ("preset,p", po::value(&arguments.preset)->default_value("slow"), "Encoder preset (default: slow)") - ("pixfmt,x", po::value(&arguments.pix_fmt), "Output pixel format (default: auto)") + ("codec,c", PO_STR_VALUE(&arguments.codec)->default_value(STR("libx264")), "Output codec (default: libx264)") + ("preset,p", PO_STR_VALUE(&arguments.preset)->default_value(STR("slow")), "Encoder preset (default: slow)") + ("pixfmt,x", PO_STR_VALUE(&arguments.pix_fmt), "Output pixel format (default: auto)") ("bitrate,b", po::value(&arguments.bitrate)->default_value(0), "Bitrate in bits per second (default: 0 (VBR))") ("crf,q", po::value(&arguments.crf)->default_value(20.0f), "Constant Rate Factor (default: 20.0)") // libplacebo options - ("shader,s", po::value(), "Name or path of the GLSL shader file to use (built-in: 'anime4k-a', 'anime4k-b', 'anime4k-c', 'anime4k-a+a', 'anime4k-b+b', 'anime4k-c+a')") + ("shader,s", PO_STR_VALUE(), "Name or path of the GLSL shader file to use") ("width,w", po::value(&arguments.out_width), "Output width") ("height,h", po::value(&arguments.out_height), "Output height") // RealESRGAN options ("gpuid,g", po::value(&arguments.gpuid)->default_value(0), "Vulkan GPU ID (default: 0)") - ("model,m", po::value(&arguments.model_name), "Name of the model to use") + ("model,m", PO_STR_VALUE(&arguments.model_name), "Name of the model to use") ("scale,r", po::value(&arguments.scaling_factor), "Scaling factor (2, 3, or 4)") ; -#endif // Positional arguments po::positional_options_description p; @@ -332,22 +279,14 @@ int main(int argc, char **argv) { // Assign positional arguments if (vm.count("input")) { -#ifdef _WIN32 - arguments.in_fname = std::filesystem::path(vm["input"].as()); -#else - arguments.in_fname = std::filesystem::path(vm["input"].as()); -#endif + arguments.in_fname = std::filesystem::path(vm["input"].as()); } else { spdlog::error("Error: Input file path is required."); return 1; } if (vm.count("output")) { -#ifdef _WIN32 - arguments.out_fname = std::filesystem::path(vm["output"].as()); -#else - arguments.out_fname = std::filesystem::path(vm["output"].as()); -#endif + arguments.out_fname = std::filesystem::path(vm["output"].as()); } else if (!arguments.benchmark) { spdlog::error("Error: Output file path is required."); return 1; @@ -359,21 +298,11 @@ int main(int argc, char **argv) { } if (vm.count("shader")) { -#ifdef _WIN32 - arguments.shader_path = std::filesystem::path(vm["shader"].as()); -#else - arguments.shader_path = std::filesystem::path(vm["shader"].as()); -#endif + arguments.shader_path = std::filesystem::path(vm["shader"].as()); } if (vm.count("model")) { -#ifdef _WIN32 - bool is_valid_model = - is_valid_realesrgan_model(wstring_to_utf8(vm["model"].as())); -#else - bool is_valid_model = is_valid_realesrgan_model(vm["model"].as()); -#endif - if (!is_valid_model) { + if (!is_valid_realesrgan_model(vm["model"].as())) { spdlog::error( "Error: Invalid model specified. Must be 'realesrgan-plus', " "'realesrgan-plus-anime', or 'realesr-animevideov3'." @@ -389,12 +318,8 @@ int main(int argc, char **argv) { return 1; } -// Additional validations -#ifdef _WIN32 - if (arguments.filter_type == L"libplacebo") { -#else - if (arguments.filter_type == "libplacebo") { -#endif + // Additional validations + if (arguments.filter_type == STR("libplacebo")) { if (arguments.shader_path.empty() || arguments.out_width == 0 || arguments.out_height == 0) { spdlog::error( @@ -403,11 +328,7 @@ int main(int argc, char **argv) { ); return 1; } -#ifdef _WIN32 - } else if (arguments.filter_type == L"realesrgan") { -#else - } else if (arguments.filter_type == "realesrgan") { -#endif + } else if (arguments.filter_type == STR("realesrgan")) { if (arguments.scaling_factor == 0 || arguments.model_name.empty()) { spdlog::error("Error: For realesrgan, scaling factor (-r) and model (-m) are required." ); @@ -454,7 +375,7 @@ int main(int argc, char **argv) { } // Set spdlog log level - auto log_level = parse_log_level(wstring_to_utf8(arguments.loglevel)); + auto log_level = parse_log_level(arguments.loglevel); switch (log_level) { case LIBVIDEO2X_LOG_LEVEL_TRACE: spdlog::set_level(spdlog::level::trace); @@ -484,38 +405,19 @@ int main(int argc, char **argv) { // Setup filter configurations based on the parsed arguments FilterConfig filter_config; -#ifdef _WIN32 - if (arguments.filter_type == L"libplacebo") { -#else - if (arguments.filter_type == "libplacebo") { -#endif + if (arguments.filter_type == STR("libplacebo")) { filter_config.filter_type = FILTER_LIBPLACEBO; filter_config.config.libplacebo.out_width = arguments.out_width; filter_config.config.libplacebo.out_height = arguments.out_height; -#ifdef _WIN32 filter_config.config.libplacebo.shader_path = arguments.shader_path.c_str(); -#else - filter_config.config.libplacebo.shader_path = arguments.shader_path.c_str(); -#endif -#ifdef _WIN32 - } else if (arguments.filter_type == L"realesrgan") { -#else - } else if (arguments.filter_type == "realesrgan") { -#endif + } else if (arguments.filter_type == STR("realesrgan")) { filter_config.filter_type = FILTER_REALESRGAN; filter_config.config.realesrgan.gpuid = arguments.gpuid; filter_config.config.realesrgan.tta_mode = false; filter_config.config.realesrgan.scaling_factor = arguments.scaling_factor; -#ifdef _WIN32 filter_config.config.realesrgan.model_name = arguments.model_name.c_str(); -#else - filter_config.config.realesrgan.model_name = arguments.model_name.c_str(); -#endif } - // Convert arguments to UTF-8 encoded strings - std::string preset_str = wstring_to_utf8(arguments.preset); - // Setup encoder configuration EncoderConfig encoder_config; encoder_config.out_width = 0; @@ -523,17 +425,13 @@ int main(int argc, char **argv) { encoder_config.copy_streams = !arguments.nocopystreams; encoder_config.codec = codec->id; encoder_config.pix_fmt = pix_fmt; - encoder_config.preset = preset_str.c_str(); + encoder_config.preset = wstring_to_utf8(arguments.preset).c_str(); encoder_config.bit_rate = arguments.bitrate; encoder_config.crf = arguments.crf; // Parse hardware acceleration method enum AVHWDeviceType hw_device_type = AV_HWDEVICE_TYPE_NONE; -#ifdef _WIN32 - if (arguments.hwaccel != L"none") { -#else - if (arguments.hwaccel != "none") { -#endif + if (arguments.hwaccel != STR("none")) { hw_device_type = av_hwdevice_find_type_by_name(wstring_to_utf8(arguments.hwaccel).c_str()); if (hw_device_type == AV_HWDEVICE_TYPE_NONE) { spdlog::error(