feat(libvideo2x): change the video processor state to an enum
Some checks failed
Build / ubuntu (push) Has been cancelled
Build / windows (push) Has been cancelled
Build / container (push) Has been cancelled

Signed-off-by: k4yt3x <i@k4yt3x.com>
This commit is contained in:
k4yt3x 2024-12-08 00:00:00 +00:00
parent 0400cf51b0
commit 0e00aca401
No known key found for this signature in database
3 changed files with 65 additions and 55 deletions

View File

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

View File

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

View File

@ -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.");
{
video_processor.abort();
newline_required.store(false); newline_required.store(false);
} video_processor.abort();
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 {