feat: add frame interpolation math except first frame

Signed-off-by: k4yt3x <i@k4yt3x.com>
This commit is contained in:
k4yt3x 2024-11-30 00:00:00 +00:00
parent 498385274d
commit f41efb3bac
No known key found for this signature in database
7 changed files with 268 additions and 123 deletions

View File

@ -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

View File

@ -22,6 +22,7 @@ class Encoder {
AVFormatContext *ifmt_ctx,
AVCodecContext *dec_ctx,
EncoderConfig *encoder_config,
const ProcessorConfig *processor_config,
int in_vstream_idx
);

View File

@ -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;

View File

@ -7,6 +7,23 @@ extern "C" {
#include <spdlog/spdlog.h>
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;

View File

@ -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

View File

@ -1,5 +1,6 @@
#include "libvideo2x.h"
#include <libavutil/frame.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -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<AVFrame, decltype(av_frame_deleter)> 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<AVFrame, decltype(av_frame_deleter_prev)> 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<AVPacket, decltype(av_packet_deleter)> 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<Filter *>(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<AVFrame, decltype(av_frame_deleter)>(
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<Interpolator *>(processor);
// TODO: replace the nullptr
ret = interpolator->interpolate(
nullptr, frame.get(), &raw_processed_frame, 0.5
);
float time_step =
1.0f / static_cast<float>(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<AVFrame, decltype(av_frame_deleter)>(
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<AVFrame, decltype(av_frame_deleter)>(
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<FilterLibplacebo>(
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<FilterRealesrgan>(
static_cast<int>(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);

View File

@ -2,6 +2,7 @@
#include <chrono>
#include <csignal>
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
@ -85,14 +86,21 @@ struct Arguments {
int delay = 0;
std::vector<std::pair<StringType, StringType>> 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<StringType> 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<StringType>(), "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<int>(&arguments.width), "Output width")
("height,h", po::value<int>(&arguments.height), "Output height")
("scaling-factor,s", po::value<int>(&arguments.scaling_factor), "Scaling factor")
("frame-rate-multiplier,r",
po::value<int>(&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<StringType>(),
"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<StringType>(&arguments.model_name), "Name of the model to use")
("scale,r", po::value<int>(&arguments.scaling_factor), "Scaling factor (2, 3, or 4)")
("realesrgan-model", PO_STR_VALUE<StringType>(&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<StringType>(&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<std::vector<StringType>>()) {
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<StringType>());
if (vm.count("libplacebo-shader")) {
arguments.libplacebo_shader_path =
std::filesystem::path(vm["libplacebo-shader"].as<StringType>());
}
if (vm.count("model")) {
if (!is_valid_realesrgan_model(vm["model"].as<StringType>())) {
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<StringType>())) {
spdlog::critical("Invalid model specified.");
return 1;
}
}
if (vm.count("rife-model")) {
if (!is_valid_rife_model(vm["rife-model"].as<StringType>())) {
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;