mirror of
https://github.com/k4yt3x/video2x.git
synced 2024-12-26 22:09:09 +00:00
feat(libvideo2x): change the video processor state to an enum
Signed-off-by: k4yt3x <i@k4yt3x.com>
This commit is contained in:
parent
0400cf51b0
commit
0e00aca401
@ -25,6 +25,15 @@ extern "C" {
|
|||||||
#define LIBVIDEO2X_API
|
#define LIBVIDEO2X_API
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum class VideoProcessorState {
|
||||||
|
Idle,
|
||||||
|
Running,
|
||||||
|
Paused,
|
||||||
|
Failed,
|
||||||
|
Aborted,
|
||||||
|
Completed
|
||||||
|
};
|
||||||
|
|
||||||
class LIBVIDEO2X_API VideoProcessor {
|
class LIBVIDEO2X_API VideoProcessor {
|
||||||
public:
|
public:
|
||||||
VideoProcessor(
|
VideoProcessor(
|
||||||
@ -41,17 +50,14 @@ class LIBVIDEO2X_API VideoProcessor {
|
|||||||
[[nodiscard]] int
|
[[nodiscard]] int
|
||||||
process(const std::filesystem::path in_fname, const std::filesystem::path out_fname);
|
process(const std::filesystem::path in_fname, const std::filesystem::path out_fname);
|
||||||
|
|
||||||
void pause() { paused_.store(true); }
|
void pause() { state_.store(VideoProcessorState::Paused); }
|
||||||
void resume() { paused_.store(false); }
|
void resume() { state_.store(VideoProcessorState::Running); }
|
||||||
void abort() { aborted_.store(true); }
|
void abort() { state_.store(VideoProcessorState::Aborted); }
|
||||||
|
|
||||||
|
VideoProcessorState get_state() const { return state_.load(); }
|
||||||
int64_t get_processed_frames() const { return frame_index_.load(); }
|
int64_t get_processed_frames() const { return frame_index_.load(); }
|
||||||
int64_t get_total_frames() const { return total_frames_.load(); }
|
int64_t get_total_frames() const { return total_frames_.load(); }
|
||||||
|
|
||||||
bool is_paused() const { return paused_.load(); }
|
|
||||||
bool is_aborted() const { return aborted_.load(); }
|
|
||||||
bool is_completed() const { return completed_.load(); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] int
|
[[nodiscard]] int
|
||||||
process_frames(Decoder &decoder, Encoder &encoder, std::unique_ptr<Processor> &processor);
|
process_frames(Decoder &decoder, Encoder &encoder, std::unique_ptr<Processor> &processor);
|
||||||
@ -86,9 +92,7 @@ class LIBVIDEO2X_API VideoProcessor {
|
|||||||
AVHWDeviceType hw_device_type_ = AV_HWDEVICE_TYPE_NONE;
|
AVHWDeviceType hw_device_type_ = AV_HWDEVICE_TYPE_NONE;
|
||||||
bool benchmark_ = false;
|
bool benchmark_ = false;
|
||||||
|
|
||||||
|
std::atomic<VideoProcessorState> state_ = VideoProcessorState::Idle;
|
||||||
std::atomic<int64_t> frame_index_ = 0;
|
std::atomic<int64_t> frame_index_ = 0;
|
||||||
std::atomic<int64_t> total_frames_ = 0;
|
std::atomic<int64_t> total_frames_ = 0;
|
||||||
std::atomic<bool> paused_ = false;
|
|
||||||
std::atomic<bool> aborted_ = false;
|
|
||||||
std::atomic<bool> completed_ = false;
|
|
||||||
};
|
};
|
||||||
|
@ -33,9 +33,23 @@ int VideoProcessor::process(
|
|||||||
const std::filesystem::path in_fname,
|
const std::filesystem::path in_fname,
|
||||||
const std::filesystem::path out_fname
|
const std::filesystem::path out_fname
|
||||||
) {
|
) {
|
||||||
char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
// Helper lambda to handle errors:
|
||||||
|
auto handle_error = [&](int error_code, const std::string &msg) {
|
||||||
|
// Format and log the error message
|
||||||
|
char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
||||||
|
av_strerror(error_code, errbuf, sizeof(errbuf));
|
||||||
|
spdlog::critical("{}: {}", msg, errbuf);
|
||||||
|
|
||||||
|
// Set the video processor state to failed and return the error code
|
||||||
|
state_.store(VideoProcessorState::Failed);
|
||||||
|
return error_code;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set the video processor state to running
|
||||||
|
state_.store(VideoProcessorState::Running);
|
||||||
|
|
||||||
// Create a smart pointer to manage the hardware device context
|
// Create a smart pointer to manage the hardware device context
|
||||||
std::unique_ptr<AVBufferRef, decltype(&av_bufferref_deleter)> hw_ctx(
|
std::unique_ptr<AVBufferRef, decltype(&av_bufferref_deleter)> hw_ctx(
|
||||||
nullptr, &av_bufferref_deleter
|
nullptr, &av_bufferref_deleter
|
||||||
@ -46,9 +60,7 @@ int VideoProcessor::process(
|
|||||||
AVBufferRef *tmp_hw_ctx = nullptr;
|
AVBufferRef *tmp_hw_ctx = nullptr;
|
||||||
ret = av_hwdevice_ctx_create(&tmp_hw_ctx, hw_device_type_, NULL, NULL, 0);
|
ret = av_hwdevice_ctx_create(&tmp_hw_ctx, hw_device_type_, NULL, NULL, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
av_strerror(ret, errbuf, sizeof(errbuf));
|
return handle_error(ret, "Error initializing hardware device context");
|
||||||
spdlog::critical("Error initializing hardware device context: {}", errbuf);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
hw_ctx.reset(tmp_hw_ctx);
|
hw_ctx.reset(tmp_hw_ctx);
|
||||||
}
|
}
|
||||||
@ -57,9 +69,7 @@ int VideoProcessor::process(
|
|||||||
Decoder decoder;
|
Decoder decoder;
|
||||||
ret = decoder.init(hw_device_type_, hw_ctx.get(), in_fname);
|
ret = decoder.init(hw_device_type_, hw_ctx.get(), in_fname);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
av_strerror(ret, errbuf, sizeof(errbuf));
|
return handle_error(ret, "Failed to initialize decoder");
|
||||||
spdlog::critical("Failed to initialize decoder: {}", errbuf);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AVFormatContext *ifmt_ctx = decoder.get_format_context();
|
AVFormatContext *ifmt_ctx = decoder.get_format_context();
|
||||||
@ -71,8 +81,7 @@ int VideoProcessor::process(
|
|||||||
ProcessorFactory::instance().create_processor(proc_cfg_, vk_device_index_)
|
ProcessorFactory::instance().create_processor(proc_cfg_, vk_device_index_)
|
||||||
);
|
);
|
||||||
if (processor == nullptr) {
|
if (processor == nullptr) {
|
||||||
spdlog::critical("Failed to create filter instance");
|
return handle_error(-1, "Failed to create filter instance");
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize output dimensions based on filter configuration
|
// Initialize output dimensions based on filter configuration
|
||||||
@ -81,8 +90,7 @@ int VideoProcessor::process(
|
|||||||
proc_cfg_, dec_ctx->width, dec_ctx->height, output_width, output_height
|
proc_cfg_, dec_ctx->width, dec_ctx->height, output_width, output_height
|
||||||
);
|
);
|
||||||
if (output_width <= 0 || output_height <= 0) {
|
if (output_width <= 0 || output_height <= 0) {
|
||||||
spdlog::critical("Failed to determine the output dimensions");
|
return handle_error(-1, "Failed to determine the output dimensions");
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update encoder frame rate multiplier
|
// Update encoder frame rate multiplier
|
||||||
@ -101,34 +109,34 @@ int VideoProcessor::process(
|
|||||||
in_vstream_idx
|
in_vstream_idx
|
||||||
);
|
);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
av_strerror(ret, errbuf, sizeof(errbuf));
|
return handle_error(ret, "Failed to initialize encoder");
|
||||||
spdlog::critical("Failed to initialize encoder: {}", errbuf);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the filter
|
// Initialize the filter
|
||||||
ret = processor->init(dec_ctx, encoder.get_encoder_context(), hw_ctx.get());
|
ret = processor->init(dec_ctx, encoder.get_encoder_context(), hw_ctx.get());
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
spdlog::critical("Failed to initialize filter");
|
return handle_error(ret, "Failed to initialize filter");
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process frames using the encoder and decoder
|
// Process frames using the encoder and decoder
|
||||||
ret = process_frames(decoder, encoder, processor);
|
ret = process_frames(decoder, encoder, processor);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
av_strerror(ret, errbuf, sizeof(errbuf));
|
return handle_error(ret, "Error processing frames");
|
||||||
spdlog::critical("Error processing frames: {}", errbuf);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the output file trailer
|
// Write the output file trailer
|
||||||
av_write_trailer(encoder.get_format_context());
|
ret = av_write_trailer(encoder.get_format_context());
|
||||||
|
if (ret < 0) {
|
||||||
if (ret < 0 && ret != AVERROR_EOF) {
|
return handle_error(ret, "Error writing output file trailer");
|
||||||
av_strerror(ret, errbuf, sizeof(errbuf));
|
|
||||||
spdlog::critical("Error occurred: {}", errbuf);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if an error occurred during processing
|
||||||
|
if (ret < 0 && ret != AVERROR_EOF) {
|
||||||
|
return handle_error(ret, "Error occurred");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Processing has completed successfully
|
||||||
|
state_.store(VideoProcessorState::Completed);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +195,7 @@ int VideoProcessor::process_frames(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read frames from the input file
|
// Read frames from the input file
|
||||||
while (!aborted_.load()) {
|
while (state_.load() != VideoProcessorState::Aborted) {
|
||||||
ret = av_read_frame(ifmt_ctx, packet.get());
|
ret = av_read_frame(ifmt_ctx, packet.get());
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (ret == AVERROR_EOF) {
|
if (ret == AVERROR_EOF) {
|
||||||
@ -209,9 +217,9 @@ int VideoProcessor::process_frames(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process frames decoded from the packet
|
// Process frames decoded from the packet
|
||||||
while (!aborted_.load()) {
|
while (state_.load() != VideoProcessorState::Aborted) {
|
||||||
// Sleep for 100 ms if processing is paused
|
// Sleep for 100 ms if processing is paused
|
||||||
if (paused_.load()) {
|
if (state_.load() == VideoProcessorState::Paused) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -121,14 +121,16 @@ int main(int argc, char **argv) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ch == ' ' || ch == '\n') {
|
if (ch == ' ' || ch == '\n') {
|
||||||
// Toggle pause state
|
|
||||||
{
|
{
|
||||||
if (video_processor.is_paused()) {
|
// Toggle pause state
|
||||||
|
if (video_processor.get_state() == VideoProcessorState::Paused) {
|
||||||
video_processor.resume();
|
video_processor.resume();
|
||||||
} else {
|
} else {
|
||||||
video_processor.pause();
|
video_processor.pause();
|
||||||
}
|
}
|
||||||
if (video_processor.is_paused()) {
|
|
||||||
|
// Print message based on current state and pause/resume the timer
|
||||||
|
if (video_processor.get_state() == VideoProcessorState::Paused) {
|
||||||
std::cout
|
std::cout
|
||||||
<< "\r\033[KProcessing paused; press [space] to resume, [q] to abort.";
|
<< "\r\033[KProcessing paused; press [space] to resume, [q] to abort.";
|
||||||
std::cout.flush();
|
std::cout.flush();
|
||||||
@ -146,23 +148,19 @@ int main(int argc, char **argv) {
|
|||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
spdlog::warn("Aborting gracefully; press Ctrl+C to terminate forcefully.");
|
spdlog::warn("Aborting gracefully; press Ctrl+C to terminate forcefully.");
|
||||||
{
|
newline_required.store(false);
|
||||||
video_processor.abort();
|
video_processor.abort();
|
||||||
newline_required.store(false);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display progress
|
// Display progress
|
||||||
if (!arguments.no_progress) {
|
if (!arguments.no_progress) {
|
||||||
int64_t processed_frames, total_frames;
|
int64_t processed_frames = video_processor.get_processed_frames();
|
||||||
bool paused;
|
int64_t total_frames = video_processor.get_total_frames();
|
||||||
{
|
|
||||||
processed_frames = video_processor.get_processed_frames();
|
// Print the progress bar if processing is not paused
|
||||||
total_frames = video_processor.get_total_frames();
|
if (video_processor.get_state() != VideoProcessorState::Paused &&
|
||||||
paused = video_processor.is_paused();
|
(total_frames > 0 || processed_frames > 0)) {
|
||||||
}
|
|
||||||
if (!paused && (total_frames > 0 || processed_frames > 0)) {
|
|
||||||
double percentage = total_frames > 0 ? static_cast<double>(processed_frames) *
|
double percentage = total_frames > 0 ? static_cast<double>(processed_frames) *
|
||||||
100.0 / static_cast<double>(total_frames)
|
100.0 / static_cast<double>(total_frames)
|
||||||
: 0.0;
|
: 0.0;
|
||||||
@ -216,10 +214,10 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Print final message based on processing result
|
// Print final message based on processing result
|
||||||
if (video_processor.is_aborted()) {
|
if (video_processor.get_state() == VideoProcessorState::Aborted) {
|
||||||
spdlog::warn("Video processing aborted");
|
spdlog::warn("Video processing aborted");
|
||||||
return 2;
|
return 2;
|
||||||
} else if (proc_ret != 0) {
|
} else if (proc_ret != 0 || video_processor.get_state() == VideoProcessorState::Failed) {
|
||||||
spdlog::critical("Video processing failed with error code {}", proc_ret);
|
spdlog::critical("Video processing failed with error code {}", proc_ret);
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user