diff --git a/CMakeLists.txt b/CMakeLists.txt index 17d676c..a795e45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -359,7 +359,7 @@ endif() # Create the executable 'video2x' if (BUILD_VIDEO2X_CLI) - add_executable(video2x src/video2x.cpp) + add_executable(video2x src/video2x.cpp src/timer.cpp) set_target_properties(video2x PROPERTIES OUTPUT_NAME video2x) # Include directories for the executable @@ -367,6 +367,7 @@ if (BUILD_VIDEO2X_CLI) ${ALL_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/include + ${PROJECT_SOURCE_DIR}/include/libvideo2x ) # Compile options for the executable diff --git a/include/libvideo2x/timer.h b/include/libvideo2x/timer.h new file mode 100644 index 0000000..2d4907e --- /dev/null +++ b/include/libvideo2x/timer.h @@ -0,0 +1,34 @@ +#ifndef TIMER_H +#define TIMER_H + +#include +#include +#include +#include + +class Timer { + public: + Timer(); + ~Timer(); + + void start(); + void pause(); + void resume(); + void stop(); + + bool is_running() const; + bool is_paused() const; + int64_t get_elapsed_time() const; + + private: + std::atomic running; + std::atomic paused; + std::thread timer_thread; + int64_t elapsed_time; + std::chrono::steady_clock::time_point start_time; + std::chrono::steady_clock::time_point pause_start_time; + + void update_elapsed_time(); +}; + +#endif // TIMER_H diff --git a/src/timer.cpp b/src/timer.cpp new file mode 100644 index 0000000..05398c1 --- /dev/null +++ b/src/timer.cpp @@ -0,0 +1,76 @@ +#include "timer.h" + +#include + +Timer::Timer() : running(false), paused(false), elapsed_time(0) {} + +Timer::~Timer() { + stop(); +} + +void Timer::start() { + if (running) { + return; + } + + running = true; + paused = false; + elapsed_time = 0; + start_time = std::chrono::steady_clock::now(); + + timer_thread = std::thread([this]() { + while (running) { + if (!paused) { + update_elapsed_time(); + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + }); +} + +void Timer::pause() { + if (running && !paused) { + paused = true; + pause_start_time = std::chrono::steady_clock::now(); + } +} + +void Timer::resume() { + if (running && paused) { + paused = false; + auto pause_end_time = std::chrono::steady_clock::now(); + auto pause_duration = + std::chrono::duration_cast(pause_end_time - pause_start_time) + .count(); + start_time += std::chrono::milliseconds(pause_duration); + } +} + +void Timer::stop() { + running = false; + if (timer_thread.joinable()) { + timer_thread.join(); + } + update_elapsed_time(); +} + +bool Timer::is_running() const { + return running; +} + +bool Timer::is_paused() const { + return paused; +} + +int64_t Timer::get_elapsed_time() const { + return elapsed_time; +} + +void Timer::update_elapsed_time() { + if (running && !paused) { + auto current_time = std::chrono::steady_clock::now(); + elapsed_time = + std::chrono::duration_cast(current_time - start_time) + .count(); + } +} diff --git a/src/video2x.cpp b/src/video2x.cpp index 1c3062a..219ed5c 100644 --- a/src/video2x.cpp +++ b/src/video2x.cpp @@ -40,6 +40,8 @@ extern "C" { #include namespace po = boost::program_options; +#include "libvideo2x/timer.h" + // Indicate if a newline needs to be printed before the next output std::atomic newline_required = false; @@ -565,11 +567,9 @@ int main(int argc, char **argv) { ); spdlog::info("Press SPACE to pause/resume, 'q' to abort."); - // Setup variables to track processing time - auto start_time = std::chrono::steady_clock::now(); - auto paused_start = std::chrono::steady_clock::time_point(); - std::chrono::seconds total_paused_duration(0); - long long time_elapsed = 0; + // Setup timer + Timer timer; + timer.start(); // Enable non-blocking input #ifndef _WIN32 @@ -607,12 +607,10 @@ int main(int argc, char **argv) { if (proc_ctx.pause) { putchar('\n'); spdlog::info("Processing paused. Press SPACE to resume, 'q' to abort."); - paused_start = std::chrono::steady_clock::now(); + timer.pause(); } else { spdlog::info("Resuming processing..."); - total_paused_duration += std::chrono::duration_cast( - std::chrono::steady_clock::now() - paused_start - ); + timer.resume(); } } } else if (ch == 'q' || ch == 'Q') { @@ -641,12 +639,7 @@ int main(int argc, char **argv) { double percentage = total_frames > 0 ? static_cast(processed_frames) * 100.0 / static_cast(total_frames) : 0.0; - auto now = std::chrono::steady_clock::now(); - time_elapsed = std::chrono::duration_cast( - now - start_time - total_paused_duration - ) - .count(); - + int64_t time_elapsed = timer.get_elapsed_time() / 1000; std::cout << "\rProcessing frame " << processed_frames << "/" << total_frames << " (" << percentage << "%); time elapsed: " << time_elapsed << "s"; std::cout.flush(); @@ -693,6 +686,7 @@ int main(int argc, char **argv) { std::lock_guard lock(proc_ctx_mutex); processed_frames = proc_ctx.processed_frames; } + int64_t time_elapsed = timer.get_elapsed_time() / 1000; float average_speed_fps = static_cast(processed_frames) / (time_elapsed > 0 ? static_cast(time_elapsed) : 1); @@ -700,7 +694,7 @@ int main(int argc, char **argv) { printf("====== Video2X %s summary ======\n", arguments.benchmark ? "Benchmark" : "Processing"); printf("Video file processed: %s\n", arguments.in_fname.u8string().c_str()); printf("Total frames processed: %ld\n", proc_ctx.processed_frames); - printf("Total time taken: %llds\n", time_elapsed); + printf("Total time taken: %ld s\n", time_elapsed); printf("Average processing speed: %.2f FPS\n", average_speed_fps); // Print additional information if not in benchmark mode