mirror of
https://github.com/k4yt3x/video2x.git
synced 2024-12-27 14:39:09 +00:00
feat: add frame interpolation math except first frame
Signed-off-by: k4yt3x <i@k4yt3x.com>
This commit is contained in:
parent
498385274d
commit
f41efb3bac
@ -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
|
||||
|
@ -22,6 +22,7 @@ class Encoder {
|
||||
AVFormatContext *ifmt_ctx,
|
||||
AVCodecContext *dec_ctx,
|
||||
EncoderConfig *encoder_config,
|
||||
const ProcessorConfig *processor_config,
|
||||
int in_vstream_idx
|
||||
);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user