diff --git a/include/libvideo2x/avutils.h b/include/libvideo2x/avutils.h index 9fd8696..6f256ae 100644 --- a/include/libvideo2x/avutils.h +++ b/include/libvideo2x/avutils.h @@ -7,6 +7,8 @@ extern "C" { #define CALC_FFMPEG_VERSION(a, b, c) (a << 16 | b << 8 | c) +AVRational get_video_frame_rate(AVFormatContext *ifmt_ctx, int in_vstream_idx); + int64_t get_video_frame_count(AVFormatContext *ifmt_ctx, int in_vstream_idx); enum AVPixelFormat diff --git a/include/libvideo2x/encoder.h b/include/libvideo2x/encoder.h index 586e267..9d1de30 100644 --- a/include/libvideo2x/encoder.h +++ b/include/libvideo2x/encoder.h @@ -22,6 +22,7 @@ class Encoder { AVFormatContext *ifmt_ctx, AVCodecContext *dec_ctx, EncoderConfig *encoder_config, + const ProcessorConfig *processor_config, int in_vstream_idx ); diff --git a/include/libvideo2x/libvideo2x.h b/include/libvideo2x/libvideo2x.h index 9440f33..a641724 100644 --- a/include/libvideo2x/libvideo2x.h +++ b/include/libvideo2x/libvideo2x.h @@ -52,14 +52,11 @@ enum Libvideo2xLogLevel { }; struct LibplaceboConfig { - int width; - int height; const CharType *shader_path; }; struct RealESRGANConfig { bool tta_mode; - int scaling_factor; const CharType *model_name; }; @@ -71,12 +68,15 @@ struct RIFEConfig { bool rife_v2; bool rife_v4; const CharType *model_name; - float time_step; }; // Unified filter configuration struct ProcessorConfig { enum ProcessorType processor_type; + int width; + int height; + int scaling_factor; + int frame_rate_multiplier; union { struct LibplaceboConfig libplacebo; struct RealESRGANConfig realesrgan; diff --git a/src/avutils.cpp b/src/avutils.cpp index f73ab18..07f0886 100644 --- a/src/avutils.cpp +++ b/src/avutils.cpp @@ -7,6 +7,23 @@ extern "C" { #include +AVRational get_video_frame_rate(AVFormatContext *ifmt_ctx, int in_vstream_idx) { + AVRational frame_rate = ifmt_ctx->streams[in_vstream_idx]->avg_frame_rate; + if (frame_rate.num == 0 && frame_rate.den == 0) { + frame_rate = ifmt_ctx->streams[in_vstream_idx]->r_frame_rate; + } + if (frame_rate.num == 0 && frame_rate.den == 0) { + frame_rate = av_guess_frame_rate(ifmt_ctx, ifmt_ctx->streams[in_vstream_idx], nullptr); + } + if (frame_rate.num == 0 && frame_rate.den == 0) { + frame_rate = ifmt_ctx->streams[in_vstream_idx]->time_base; + } + if (frame_rate.num == 0 && frame_rate.den == 0) { + spdlog::warn("Unable to determine the video's frame rate"); + } + return frame_rate; +} + int64_t get_video_frame_count(AVFormatContext *ifmt_ctx, int in_vstream_idx) { // Use the 'nb_frames' field if it is available int64_t nb_frames = ifmt_ctx->streams[in_vstream_idx]->nb_frames; @@ -31,19 +48,7 @@ int64_t get_video_frame_count(AVFormatContext *ifmt_ctx, int in_vstream_idx) { spdlog::debug("Video duration: {}s", duration_secs); // Calculate average FPS - double fps = av_q2d(ifmt_ctx->streams[in_vstream_idx]->avg_frame_rate); - if (fps <= 0) { - spdlog::debug("Unable to read the average frame rate from 'avg_frame_rate'"); - fps = av_q2d(ifmt_ctx->streams[in_vstream_idx]->r_frame_rate); - } - if (fps <= 0) { - spdlog::debug("Unable to read the average frame rate from 'r_frame_rate'"); - fps = av_q2d(av_guess_frame_rate(ifmt_ctx, ifmt_ctx->streams[in_vstream_idx], nullptr)); - } - if (fps <= 0) { - spdlog::debug("Unable to estimate the average frame rate with 'av_guess_frame_rate'"); - fps = av_q2d(ifmt_ctx->streams[in_vstream_idx]->time_base); - } + double fps = av_q2d(get_video_frame_rate(ifmt_ctx, in_vstream_idx)); if (fps <= 0) { spdlog::warn("Unable to estimate the video's average frame rate"); return -1; diff --git a/src/encoder.cpp b/src/encoder.cpp index b1d9cd6..bfa5818 100644 --- a/src/encoder.cpp +++ b/src/encoder.cpp @@ -33,6 +33,7 @@ int Encoder::init( AVFormatContext *ifmt_ctx, AVCodecContext *dec_ctx, EncoderConfig *encoder_config, + const ProcessorConfig *processor_config, int in_vstream_idx ) { int ret; @@ -121,18 +122,26 @@ int Encoder::init( spdlog::debug("Auto-selected pixel format: {}", av_get_pix_fmt_name(enc_ctx_->pix_fmt)); } - // Set the output video's time base - if (dec_ctx->time_base.num > 0 && dec_ctx->time_base.den > 0) { - enc_ctx_->time_base = dec_ctx->time_base; + if (processor_config->frame_rate_multiplier > 0) { + AVRational in_frame_rate = get_video_frame_rate(ifmt_ctx, in_vstream_idx); + enc_ctx_->framerate = { + in_frame_rate.num * processor_config->frame_rate_multiplier, in_frame_rate.den + }; + enc_ctx_->time_base = av_inv_q(enc_ctx_->framerate); } else { - enc_ctx_->time_base = av_inv_q(av_guess_frame_rate(ifmt_ctx, out_vstream, nullptr)); - } + // Set the output video's time base + if (dec_ctx->time_base.num > 0 && dec_ctx->time_base.den > 0) { + enc_ctx_->time_base = dec_ctx->time_base; + } else { + enc_ctx_->time_base = av_inv_q(av_guess_frame_rate(ifmt_ctx, out_vstream, nullptr)); + } - // Set the output video's frame rate - if (dec_ctx->framerate.num > 0 && dec_ctx->framerate.den > 0) { - enc_ctx_->framerate = dec_ctx->framerate; - } else { - enc_ctx_->framerate = av_guess_frame_rate(ifmt_ctx, out_vstream, nullptr); + // Set the output video's frame rate + if (dec_ctx->framerate.num > 0 && dec_ctx->framerate.den > 0) { + enc_ctx_->framerate = dec_ctx->framerate; + } else { + enc_ctx_->framerate = av_guess_frame_rate(ifmt_ctx, out_vstream, nullptr); + } } // Set extra AVOptions diff --git a/src/libvideo2x.cpp b/src/libvideo2x.cpp index d92131f..3b6f71a 100644 --- a/src/libvideo2x.cpp +++ b/src/libvideo2x.cpp @@ -1,5 +1,6 @@ #include "libvideo2x.h" +#include #include #include #include @@ -21,7 +22,8 @@ extern "C" { // Process frames using the selected filter. static int process_frames( - EncoderConfig *encoder_config, + const EncoderConfig *encoder_config, + const ProcessorConfig *processor_config, VideoProcessingContext *proc_ctx, Decoder &decoder, Encoder &encoder, @@ -48,7 +50,7 @@ static int process_frames( spdlog::debug("{} frames to process", proc_ctx->total_frames); } - // Allocate frame and packet + // Allocate AVFrame for the current processed frame auto av_frame_deleter = [](AVFrame *frame) { av_frame_free(&frame); }; std::unique_ptr frame(av_frame_alloc(), av_frame_deleter); if (!frame) { @@ -56,7 +58,22 @@ static int process_frames( return ret; } - auto av_packet_deleter = [](AVPacket *packet) { av_packet_free(&packet); }; + // Allocate AVFrame for the previous processed frame + auto av_frame_deleter_prev = [](AVFrame *prev_frame) { + if (prev_frame != nullptr) { + av_frame_unref(prev_frame); + prev_frame = nullptr; + } + }; + std::unique_ptr prev_frame( + nullptr, av_frame_deleter_prev + ); + + // Allocate AVPacket for reading frames + auto av_packet_deleter = [](AVPacket *packet) { + av_packet_unref(packet); + av_packet_free(&packet); + }; std::unique_ptr packet( av_packet_alloc(), av_packet_deleter ); @@ -66,8 +83,6 @@ static int process_frames( } // Read frames from the input file - // TODO: Delete this line - bool delete_this = true; while (!proc_ctx->abort) { ret = av_read_frame(ifmt_ctx, packet.get()); if (ret < 0) { @@ -85,7 +100,6 @@ static int process_frames( if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); spdlog::critical("Error sending packet to decoder: {}", errbuf); - av_packet_unref(packet.get()); return ret; } @@ -102,56 +116,95 @@ static int process_frames( } else if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); spdlog::critical("Error decoding video frame: {}", errbuf); - av_packet_unref(packet.get()); return ret; } - if (delete_this) { - delete_this = false; - continue; - } - AVFrame *raw_processed_frame = nullptr; switch (processor->get_processing_mode()) { case PROCESSING_MODE_FILTER: { Filter *filter = dynamic_cast(processor); ret = filter->filter(frame.get(), &raw_processed_frame); + if (ret < 0 && ret != AVERROR(EAGAIN)) { + av_strerror(ret, errbuf, sizeof(errbuf)); + return ret; + } else if (ret == 0 && raw_processed_frame != nullptr) { + auto processed_frame = + std::unique_ptr( + raw_processed_frame, av_frame_deleter + ); + + if (!benchmark) { + ret = encoder.write_frame( + processed_frame.get(), proc_ctx->processed_frames + ); + if (ret < 0) { + av_strerror(ret, errbuf, sizeof(errbuf)); + spdlog::critical("Error encoding/writing frame: {}", errbuf); + return ret; + } + } + } break; } case PROCESSING_MODE_INTERPOLATE: { Interpolator *interpolator = dynamic_cast(processor); - // TODO: replace the nullptr - ret = interpolator->interpolate( - nullptr, frame.get(), &raw_processed_frame, 0.5 - ); + + float time_step = + 1.0f / static_cast(processor_config->frame_rate_multiplier); + float current_time_step = time_step; + + while (current_time_step < 1.0f) { + ret = interpolator->interpolate( + prev_frame.get(), + frame.get(), + &raw_processed_frame, + current_time_step + ); + if (ret < 0 && ret != AVERROR(EAGAIN)) { + av_strerror(ret, errbuf, sizeof(errbuf)); + return ret; + } else if (ret == 0 && raw_processed_frame != nullptr) { + auto processed_frame = + std::unique_ptr( + raw_processed_frame, av_frame_deleter + ); + + if (!benchmark) { + processed_frame->pts = proc_ctx->processed_frames; + ret = encoder.write_frame( + processed_frame.get(), proc_ctx->processed_frames + ); + if (ret < 0) { + av_strerror(ret, errbuf, sizeof(errbuf)); + spdlog::critical( + "Error encoding/writing frame: {}", errbuf + ); + return ret; + } + } + } + proc_ctx->processed_frames++; + current_time_step += time_step; + } + + if (!benchmark) { + frame->pts = proc_ctx->processed_frames; + ret = encoder.write_frame(frame.get(), proc_ctx->processed_frames); + if (ret < 0) { + av_strerror(ret, errbuf, sizeof(errbuf)); + spdlog::critical("Error encoding/writing frame: {}", errbuf); + return ret; + } + } break; } + default: + spdlog::critical("Unknown processing mode"); + return -1; } - - if (ret < 0 && ret != AVERROR(EAGAIN)) { - av_strerror(ret, errbuf, sizeof(errbuf)); - av_packet_unref(packet.get()); - return ret; - } else if (ret == 0 && raw_processed_frame != nullptr) { - auto processed_frame = std::unique_ptr( - raw_processed_frame, av_frame_deleter - ); - - if (!benchmark) { - ret = - encoder.write_frame(processed_frame.get(), proc_ctx->processed_frames); - if (ret < 0) { - av_strerror(ret, errbuf, sizeof(errbuf)); - spdlog::critical("Error encoding/writing frame: {}", errbuf); - av_packet_unref(packet.get()); - return ret; - } - } - proc_ctx->processed_frames++; - } - av_frame_unref(frame.get()); + proc_ctx->processed_frames++; spdlog::debug( "Processed frame {}/{}", proc_ctx->processed_frames, proc_ctx->total_frames ); @@ -168,11 +221,9 @@ static int process_frames( if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); spdlog::critical("Error muxing audio/subtitle packet: {}", errbuf); - av_packet_unref(packet.get()); return ret; } } - av_packet_unref(packet.get()); } // Flush the filter @@ -302,12 +353,12 @@ extern "C" int process_video( int output_width = 0, output_height = 0; switch (processor_config->processor_type) { case PROCESSOR_LIBPLACEBO: - output_width = processor_config->config.libplacebo.width; - output_height = processor_config->config.libplacebo.height; + output_width = processor_config->width; + output_height = processor_config->height; break; case PROCESSOR_REALESRGAN: - output_width = dec_ctx->width * processor_config->config.realesrgan.scaling_factor; - output_height = dec_ctx->height * processor_config->config.realesrgan.scaling_factor; + output_width = dec_ctx->width * processor_config->scaling_factor; + output_height = dec_ctx->height * processor_config->scaling_factor; break; case PROCESSOR_RIFE: output_width = dec_ctx->width; @@ -325,7 +376,9 @@ extern "C" int process_video( // Initialize the encoder Encoder encoder; - ret = encoder.init(hw_ctx.get(), out_fpath, ifmt_ctx, dec_ctx, encoder_config, in_vstream_idx); + ret = encoder.init( + hw_ctx.get(), out_fpath, ifmt_ctx, dec_ctx, encoder_config, processor_config, in_vstream_idx + ); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); spdlog::critical("Failed to initialize encoder: {}", errbuf); @@ -352,8 +405,8 @@ extern "C" int process_video( processor = std::make_unique( vk_device_index, std::filesystem::path(config.shader_path), - config.width, - config.height + processor_config->width, + processor_config->height ); break; } @@ -366,7 +419,7 @@ extern "C" int process_video( processor = std::make_unique( static_cast(vk_device_index), config.tta_mode, - config.scaling_factor, + processor_config->scaling_factor, config.model_name ); break; @@ -408,7 +461,9 @@ extern "C" int process_video( } // Process frames using the encoder and decoder - ret = process_frames(encoder_config, proc_ctx, decoder, encoder, processor.get(), benchmark); + ret = process_frames( + encoder_config, processor_config, proc_ctx, decoder, encoder, processor.get(), benchmark + ); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); spdlog::critical("Error processing frames: {}", errbuf); diff --git a/tools/video2x/src/video2x.cpp b/tools/video2x/src/video2x.cpp index 4b8a21a..bdfd2a4 100644 --- a/tools/video2x/src/video2x.cpp +++ b/tools/video2x/src/video2x.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -85,14 +86,21 @@ struct Arguments { int delay = 0; std::vector> extra_options; - // libplacebo options - std::filesystem::path shader_path; + // General processing options int width = 0; int height = 0; + int scaling_factor = 0; + int frame_rate_multiplier = 2; + + // libplacebo options + std::filesystem::path libplacebo_shader_path; // RealESRGAN options - StringType model_name; - int scaling_factor = 0; + StringType realesrgan_model_name = STR("realesr-animevideov3"); + + // RIFE options + StringType rife_model_name = STR("rife-v4.6"); + bool rife_uhd_mode = false; }; // Set UNIX terminal input to non-blocking mode @@ -156,6 +164,23 @@ bool is_valid_realesrgan_model(const StringType &model) { return valid_realesrgan_models.count(model) > 0; } +bool is_valid_rife_model(const StringType &model) { + static const std::unordered_set valid_realesrgan_models = { + STR("rife"), + STR("rife-HD"), + STR("rife-UHD"), + STR("rife-anime"), + STR("rife-v2"), + STR("rife-v2.3"), + STR("rife-v2.4"), + STR("rife-v3.0"), + STR("rife-v3.1"), + STR("rife-v4"), + STR("rife-v4.6"), + }; + return valid_realesrgan_models.count(model) > 0; +} + enum Libvideo2xLogLevel parse_log_level(const StringType &level_name) { if (level_name == STR("trace")) { return LIBVIDEO2X_LOG_LEVEL_TRACE; @@ -407,27 +432,49 @@ int main(int argc, char **argv) { "Additional AVOption(s) for the encoder (format: -e key=value)") ; - po::options_description libplacebo_opts("libplacebo options"); - libplacebo_opts.add_options() - ("shader,s", PO_STR_VALUE(), "Name/path of the GLSL shader file to use") + po::options_description common_opts("Common aprocessing options"); + common_opts.add_options() ("width,w", po::value(&arguments.width), "Output width") ("height,h", po::value(&arguments.height), "Output height") + ("scaling-factor,s", po::value(&arguments.scaling_factor), "Scaling factor") + ("frame-rate-multiplier,r", + po::value(&arguments.frame_rate_multiplier)->default_value(0), + "Output frame rate") + ; + + po::options_description libplacebo_opts("libplacebo options"); + libplacebo_opts.add_options() + ("libplacebo-shader", PO_STR_VALUE(), + "Name/path of the GLSL shader file to use") ; // RealESRGAN options po::options_description realesrgan_opts("RealESRGAN options"); realesrgan_opts.add_options() - ("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)") + ("realesrgan-model", PO_STR_VALUE(&arguments.realesrgan_model_name), + "Name of the RealESRGAN model to use") + ; + + // RIFE options + po::options_description rife_opts("RIFE options"); + rife_opts.add_options() + ("rife-model,m", PO_STR_VALUE(&arguments.rife_model_name), + "Name of the RIFE model to use") + ("rife-uhd", po::bool_switch(&arguments.rife_uhd_mode), + "Enable Ultra HD mode") ; // clang-format on // Combine all options - all_opts.add(encoder_opts).add(libplacebo_opts).add(realesrgan_opts); + all_opts.add(encoder_opts) + .add(common_opts) + .add(libplacebo_opts) + .add(realesrgan_opts) + .add(rife_opts); // Positional arguments po::positional_options_description p; - p.add("input", 1).add("output", 1).add("filter", 1); + p.add("input", 1).add("output", 1).add("processor", 1); #ifdef _WIN32 po::variables_map vm; @@ -484,7 +531,7 @@ int main(int argc, char **argv) { return 1; } - // Parse avoptions + // Parse extra AVOptions if (vm.count("extra-encoder-option")) { for (const auto &opt : vm["extra-encoder-option"].as>()) { size_t eq_pos = opt.find('='); @@ -499,16 +546,21 @@ int main(int argc, char **argv) { } } - if (vm.count("shader")) { - arguments.shader_path = std::filesystem::path(vm["shader"].as()); + if (vm.count("libplacebo-shader")) { + arguments.libplacebo_shader_path = + std::filesystem::path(vm["libplacebo-shader"].as()); } - if (vm.count("model")) { - if (!is_valid_realesrgan_model(vm["model"].as())) { - spdlog::critical( - "Invalid model specified. Must be 'realesrgan-plus', " - "'realesrgan-plus-anime', or 'realesr-animevideov3'." - ); + if (vm.count("libplacebo-model")) { + if (!is_valid_realesrgan_model(vm["realesrgan-model"].as())) { + spdlog::critical("Invalid model specified."); + return 1; + } + } + + if (vm.count("rife-model")) { + if (!is_valid_rife_model(vm["rife-model"].as())) { + spdlog::critical("Invalid RIFE model specified."); return 1; } } @@ -521,30 +573,34 @@ int main(int argc, char **argv) { } // Additional validations + if (arguments.width < 0 || arguments.height < 0) { + spdlog::critical("Invalid output resolution specified."); + return 1; + } + if (arguments.scaling_factor < 0) { + spdlog::critical("Invalid scaling factor specified."); + return 1; + } + if (arguments.frame_rate_multiplier < 0) { + spdlog::critical("Invalid target frame rate specified."); + return 1; + } + if (arguments.processor_type == STR("libplacebo")) { - if (arguments.shader_path.empty() || arguments.width == 0 || arguments.height == 0) { - spdlog::critical( - "For libplacebo, shader name/path (-s), width (-w), " - "and height (-h) are required." - ); + if (arguments.libplacebo_shader_path.empty() || arguments.width == 0 || + arguments.height == 0) { + spdlog::critical("Shader name/path, width, and height are required for libplacebo."); return 1; } } else if (arguments.processor_type == STR("realesrgan")) { - if (arguments.scaling_factor == 0 || arguments.model_name.empty()) { - spdlog::critical("For realesrgan, scaling factor (-r) and model (-m) are required."); - return 1; - } if (arguments.scaling_factor != 2 && arguments.scaling_factor != 3 && arguments.scaling_factor != 4) { - spdlog::critical("Scaling factor must be 2, 3, or 4."); + spdlog::critical("Scaling factor must be 2, 3, or 4 for RealESRGAN."); return 1; } - } else if (arguments.processor_type == STR("rife")) { - // TODO: Complete RIFE validation - ; - } else { + } else if (arguments.processor_type != STR("rife")) { spdlog::critical( - "Invalid processor type specified. Must be 'libplacebo', 'realesrgan', or 'rife'." + "Invalid processor specified. Must be 'libplacebo', 'realesrgan', or 'rife'." ); return 1; } @@ -617,38 +673,55 @@ int main(int argc, char **argv) { #ifdef _WIN32 std::wstring shader_path_str = arguments.shader_path.wstring(); #else - std::string shader_path_str = arguments.shader_path.string(); + std::string shader_path_str = arguments.libplacebo_shader_path.string(); #endif // Setup filter configurations based on the parsed arguments ProcessorConfig processor_config; + processor_config.width = arguments.width; + processor_config.height = arguments.height; + processor_config.scaling_factor = arguments.scaling_factor; + processor_config.frame_rate_multiplier = arguments.frame_rate_multiplier; + if (arguments.processor_type == STR("libplacebo")) { processor_config.processor_type = PROCESSOR_LIBPLACEBO; - processor_config.config.libplacebo.width = arguments.width; - processor_config.config.libplacebo.height = arguments.height; processor_config.config.libplacebo.shader_path = shader_path_str.c_str(); } else if (arguments.processor_type == STR("realesrgan")) { processor_config.processor_type = PROCESSOR_REALESRGAN; processor_config.config.realesrgan.tta_mode = false; - processor_config.config.realesrgan.scaling_factor = arguments.scaling_factor; - processor_config.config.realesrgan.model_name = arguments.model_name.c_str(); + processor_config.config.realesrgan.model_name = arguments.realesrgan_model_name.c_str(); } else if (arguments.processor_type == STR("rife")) { processor_config.processor_type = PROCESSOR_RIFE; processor_config.config.rife.tta_mode = false; processor_config.config.rife.tta_temporal_mode = false; - processor_config.config.rife.uhd_mode = false; + processor_config.config.rife.uhd_mode = arguments.rife_uhd_mode; processor_config.config.rife.num_threads = 0; - processor_config.config.rife.rife_v2 = false; - processor_config.config.rife.rife_v4 = true; - processor_config.config.rife.model_name = STR("rife-v4.6"); + processor_config.config.rife.model_name = arguments.rife_model_name.c_str(); + + bool rife_v2 = false; + bool rife_v4 = false; + + if (arguments.rife_model_name.find(STR("rife-v2")) != StringType::npos) { + rife_v2 = true; + } else if (arguments.rife_model_name.find(STR("rife-v3")) != StringType::npos) { + rife_v2 = true; + } else if (arguments.rife_model_name.find(STR("rife-v4")) != StringType::npos) { + rife_v4 = true; + } else if (arguments.rife_model_name.find(STR("rife")) == StringType::npos) { + spdlog::critical("Unknown RIFE model generation."); + return 1; + } + + processor_config.config.rife.rife_v2 = rife_v2; + processor_config.config.rife.rife_v4 = rife_v4; } // Setup encoder configuration EncoderConfig encoder_config; encoder_config.codec = codec->id; encoder_config.copy_streams = !arguments.no_copy_streams; - encoder_config.width = arguments.width; - encoder_config.height = arguments.height; + encoder_config.width = 0; + encoder_config.height = 0; encoder_config.pix_fmt = pix_fmt; encoder_config.bit_rate = arguments.bit_rate; encoder_config.rc_buffer_size = arguments.rc_buffer_size;