From 827606868bf9f1dd16208882f0e3ca424b3e9e0a Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Mon, 3 Dec 2018 20:03:40 +0100 Subject: [PATCH] Unify disk_space_estimator.cpp from Nageru and Futatabi. --- futatabi/disk_space_estimator.cpp | 52 --------------------- futatabi/disk_space_estimator.h | 47 ------------------- futatabi/main.cpp | 2 +- futatabi/mainwindow.cpp | 2 +- futatabi/meson.build | 2 +- nageru/mainwindow.cpp | 2 +- nageru/meson.build | 2 +- nageru/mixer.cpp | 2 +- nageru/quicksync_encoder.cpp | 4 +- {nageru => shared}/disk_space_estimator.cpp | 37 ++++++++++----- {nageru => shared}/disk_space_estimator.h | 26 ++++++++--- shared/meson.build | 2 +- 12 files changed, 54 insertions(+), 126 deletions(-) delete mode 100644 futatabi/disk_space_estimator.cpp delete mode 100644 futatabi/disk_space_estimator.h rename {nageru => shared}/disk_space_estimator.cpp (68%) rename {nageru => shared}/disk_space_estimator.h (65%) diff --git a/futatabi/disk_space_estimator.cpp b/futatabi/disk_space_estimator.cpp deleted file mode 100644 index 073e57e..0000000 --- a/futatabi/disk_space_estimator.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "disk_space_estimator.h" - -#include "shared/timebase.h" - -#include -#include -#include -#include - -DiskSpaceEstimator::DiskSpaceEstimator(DiskSpaceEstimator::callback_t callback) - : callback(callback) -{ -} - -void DiskSpaceEstimator::report_write(const std::string &filename, size_t bytes, uint64_t pts) -{ - // Reject points that are out-of-order (happens with B-frames). - if (!measure_points.empty() && pts <= measure_points.back().pts) { - return; - } - - // Remove too old points. - while (measure_points.size() > 1 && measure_points.front().pts + window_length < pts) { - measure_points.pop_front(); - } - - total_size += bytes; - - struct statfs fst; - if (statfs(filename.c_str(), &fst) == -1) { - perror(filename.c_str()); - return; - } - - off_t free_bytes = off_t(fst.f_bavail) * fst.f_frsize; - - if (!measure_points.empty()) { - double bytes_per_second = double(total_size - measure_points.front().size) / - (pts - measure_points.front().pts) * TIMEBASE; - double seconds_left = free_bytes / bytes_per_second; - - // Only report every second, since updating the UI can be expensive. - if (last_pts_reported == 0 || pts - last_pts_reported >= TIMEBASE) { - callback(free_bytes, seconds_left); - last_pts_reported = pts; - } - } - - measure_points.push_back({ pts, total_size }); -} - -DiskSpaceEstimator *global_disk_space_estimator = nullptr; // Created in MainWindow::MainWindow(). diff --git a/futatabi/disk_space_estimator.h b/futatabi/disk_space_estimator.h deleted file mode 100644 index e4b2c51..0000000 --- a/futatabi/disk_space_estimator.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef _DISK_SPACE_ESTIMATOR_H -#define _DISK_SPACE_ESTIMATOR_H - -// A class responsible for measuring how much disk there is left when we -// store our video to disk, and how much recording time that equates to. -// It gets callbacks from the Mux writing the stream to disk (which also -// knows which filesystem the file is going to), makes its calculations, -// and calls back to the MainWindow, which shows it to the user. -// -// The bitrate is measured over a simple 30-second sliding window. - -#include "shared/timebase.h" - -#include -#include -#include -#include -#include - -class DiskSpaceEstimator { -public: - typedef std::function callback_t; - DiskSpaceEstimator(callback_t callback); - - // Report that a video frame with the given pts and size has just been - // written (possibly appended) to the given file. - // - // is taken to be in TIMEBASE units (see shared/timebase.h). - void report_write(const std::string &filename, size_t bytes, uint64_t pts); - -private: - static constexpr int64_t window_length = 30 * TIMEBASE; - - callback_t callback; - - struct MeasurePoint { - uint64_t pts; - off_t size; - }; - std::deque measure_points; - uint64_t last_pts_reported = 0; - off_t total_size = 0; -}; - -extern DiskSpaceEstimator *global_disk_space_estimator; - -#endif // !defined(_DISK_SPACE_ESTIMATOR_H) diff --git a/futatabi/main.cpp b/futatabi/main.cpp index 46fb200..f6d2ab1 100644 --- a/futatabi/main.cpp +++ b/futatabi/main.cpp @@ -22,7 +22,7 @@ extern "C" { #include "clip_list.h" #include "shared/context.h" #include "defs.h" -#include "disk_space_estimator.h" +#include "shared/disk_space_estimator.h" #include "shared/ffmpeg_raii.h" #include "flags.h" #include "frame_on_disk.h" diff --git a/futatabi/mainwindow.cpp b/futatabi/mainwindow.cpp index 85a86a8..2a05a24 100644 --- a/futatabi/mainwindow.cpp +++ b/futatabi/mainwindow.cpp @@ -1,7 +1,7 @@ #include "mainwindow.h" #include "clip_list.h" -#include "disk_space_estimator.h" +#include "shared/disk_space_estimator.h" #include "flags.h" #include "frame_on_disk.h" #include "player.h" diff --git a/futatabi/meson.build b/futatabi/meson.build index aa58291..55611e8 100644 --- a/futatabi/meson.build +++ b/futatabi/meson.build @@ -34,7 +34,7 @@ srcs = ['flow.cpp', 'gpu_timers.cpp'] # All the other files. srcs += ['main.cpp', 'player.cpp', 'video_stream.cpp', 'chroma_subsampler.cpp'] -srcs += ['vaapi_jpeg_decoder.cpp', 'db.cpp', 'disk_space_estimator.cpp', 'ycbcr_converter.cpp', 'flags.cpp'] +srcs += ['vaapi_jpeg_decoder.cpp', 'db.cpp', 'ycbcr_converter.cpp', 'flags.cpp'] srcs += ['mainwindow.cpp', 'jpeg_frame_view.cpp', 'clip_list.cpp', 'frame_on_disk.cpp'] srcs += moc_files srcs += proto_generated diff --git a/nageru/mainwindow.cpp b/nageru/mainwindow.cpp index 05e41eb..11e6391 100644 --- a/nageru/mainwindow.cpp +++ b/nageru/mainwindow.cpp @@ -50,7 +50,7 @@ #include "clickable_label.h" #include "context_menus.h" #include "correlation_meter.h" -#include "disk_space_estimator.h" +#include "shared/disk_space_estimator.h" #include "ellipsis_label.h" #include "flags.h" #include "glwidget.h" diff --git a/nageru/meson.build b/nageru/meson.build index 737d889..58a8feb 100644 --- a/nageru/meson.build +++ b/nageru/meson.build @@ -161,7 +161,7 @@ nageru_link_with += audio # Mixer objects. srcs += ['chroma_subsampler.cpp', 'v210_converter.cpp', 'mixer.cpp', 'pbo_frame_allocator.cpp', 'theme.cpp', 'image_input.cpp', 'alsa_output.cpp', - 'disk_space_estimator.cpp', 'timecode_renderer.cpp', 'tweaked_inputs.cpp'] + 'timecode_renderer.cpp', 'tweaked_inputs.cpp'] # Streaming and encoding objects (largely the set that is shared between Nageru and Kaeru). stream_srcs = ['quicksync_encoder.cpp', 'x264_encoder.cpp', 'x264_dynamic.cpp', 'x264_speed_control.cpp', 'video_encoder.cpp', diff --git a/nageru/mixer.cpp b/nageru/mixer.cpp index 3a5783b..0d782e8 100644 --- a/nageru/mixer.cpp +++ b/nageru/mixer.cpp @@ -41,7 +41,7 @@ #include "decklink_capture.h" #include "decklink_output.h" #include "defs.h" -#include "disk_space_estimator.h" +#include "shared/disk_space_estimator.h" #include "ffmpeg_capture.h" #include "flags.h" #include "input_mapping.h" diff --git a/nageru/quicksync_encoder.cpp b/nageru/quicksync_encoder.cpp index ded20f6..9723118 100644 --- a/nageru/quicksync_encoder.cpp +++ b/nageru/quicksync_encoder.cpp @@ -47,7 +47,7 @@ extern "C" { #include "audio_encoder.h" #include "shared/context.h" #include "defs.h" -#include "disk_space_estimator.h" +#include "shared/disk_space_estimator.h" #include "shared/ffmpeg_raii.h" #include "flags.h" #include "shared/mux.h" @@ -1814,7 +1814,7 @@ void QuickSyncEncoderImpl::open_output_file(const std::string &filename) lock_guard lock(file_audio_encoder_mutex); AVCodecParametersWithDeleter audio_codecpar = file_audio_encoder->get_codec_parameters(); file_mux.reset(new Mux(avctx, frame_width, frame_height, Mux::CODEC_H264, video_extradata, audio_codecpar.get(), get_color_space(global_flags.ycbcr_rec709_coefficients), Mux::WITH_AUDIO, TIMEBASE, - std::bind(&DiskSpaceEstimator::report_write, disk_space_estimator, filename, _1), + std::bind(&DiskSpaceEstimator::report_append, disk_space_estimator, filename, _1), Mux::WRITE_BACKGROUND, { ¤t_file_mux_metrics, &total_mux_metrics })); } diff --git a/nageru/disk_space_estimator.cpp b/shared/disk_space_estimator.cpp similarity index 68% rename from nageru/disk_space_estimator.cpp rename to shared/disk_space_estimator.cpp index 42fdfc2..da55ee1 100644 --- a/nageru/disk_space_estimator.cpp +++ b/shared/disk_space_estimator.cpp @@ -1,28 +1,47 @@ -#include "disk_space_estimator.h" +#include "shared/disk_space_estimator.h" +#include #include #include #include -#include #include "shared/metrics.h" #include "shared/timebase.h" +using namespace std; + DiskSpaceEstimator::DiskSpaceEstimator(DiskSpaceEstimator::callback_t callback) : callback(callback) { global_metrics.add("disk_free_bytes", &metric_disk_free_bytes, Metrics::TYPE_GAUGE); } -void DiskSpaceEstimator::report_write(const std::string &filename, uint64_t pts) +void DiskSpaceEstimator::report_write(const string &filename, off_t bytes, uint64_t pts) +{ + total_size += bytes; + report_write_internal(filename, total_size, pts); +} + +void DiskSpaceEstimator::report_append(const string &filename, uint64_t pts) { if (filename != last_filename) { last_filename = filename; measure_points.clear(); } + struct stat st; + if (stat(filename.c_str(), &st) == -1) { + perror(filename.c_str()); + return; + } + + report_write_internal(filename, st.st_size, pts); +} + +void DiskSpaceEstimator::report_write_internal(const string &filename, off_t file_size, uint64_t pts) +{ // Reject points that are out-of-order (happens with B-frames). - if (!measure_points.empty() && pts < measure_points.back().pts) { + if (!measure_points.empty() && pts <= measure_points.back().pts) { return; } @@ -31,12 +50,6 @@ void DiskSpaceEstimator::report_write(const std::string &filename, uint64_t pts) measure_points.pop_front(); } - struct stat st; - if (stat(filename.c_str(), &st) == -1) { - perror(filename.c_str()); - return; - } - struct statfs fst; if (statfs(filename.c_str(), &fst) == -1) { perror(filename.c_str()); @@ -47,7 +60,7 @@ void DiskSpaceEstimator::report_write(const std::string &filename, uint64_t pts) metric_disk_free_bytes = free_bytes; if (!measure_points.empty()) { - double bytes_per_second = double(st.st_size - measure_points.front().size) / + double bytes_per_second = double(file_size - measure_points.front().size) / (pts - measure_points.front().pts) * TIMEBASE; double seconds_left = free_bytes / bytes_per_second; @@ -58,7 +71,7 @@ void DiskSpaceEstimator::report_write(const std::string &filename, uint64_t pts) } } - measure_points.push_back({ pts, st.st_size }); + measure_points.push_back({ pts, file_size }); } DiskSpaceEstimator *global_disk_space_estimator = nullptr; // Created in MainWindow::MainWindow(). diff --git a/nageru/disk_space_estimator.h b/shared/disk_space_estimator.h similarity index 65% rename from nageru/disk_space_estimator.h rename to shared/disk_space_estimator.h index ce81321..163b7ef 100644 --- a/nageru/disk_space_estimator.h +++ b/shared/disk_space_estimator.h @@ -9,21 +9,26 @@ // // The bitrate is measured over a simple 30-second sliding window. -#include -#include #include #include #include +#include #include +#include #include "shared/timebase.h" -class DiskSpaceEstimator -{ +class DiskSpaceEstimator { public: typedef std::function callback_t; DiskSpaceEstimator(callback_t callback); + // Report that a video frame with the given pts and size has just been + // written (possibly appended) to the given file. + // + // is taken to be in TIMEBASE units (see shared/timebase.h). + void report_write(const std::string &filename, off_t bytes, uint64_t pts); + // Report that a video frame with the given pts has just been written // to the given file, so the estimator should stat the file and see // by how much it grew since last time. Called by the Mux object @@ -31,13 +36,19 @@ public: // // If the filename changed since last time, the estimation is reset. // is taken to be in TIMEBASE units (see shared/timebase.h). - void report_write(const std::string &filename, uint64_t pts); + // + // You should probably not mix this and report_write() on the same + // object. Really, report_write() matches Futatabi's controlled writes + // to a custom format, and report_append() matches Nageru's use of Mux + // (where we don't see the bytes flowing past). + void report_append(const std::string &filename, uint64_t pts); private: static constexpr int64_t window_length = 30 * TIMEBASE; + void report_write_internal(const std::string &filename, off_t file_size, uint64_t pts); + callback_t callback; - std::string last_filename; struct MeasurePoint { uint64_t pts; @@ -46,6 +57,9 @@ private: std::deque measure_points; uint64_t last_pts_reported = 0; + off_t total_size = 0; // For report_write(). + std::string last_filename; // For report_append(). + // Metrics. std::atomic metric_disk_free_bytes{-1}; }; diff --git a/shared/meson.build b/shared/meson.build index 1bb183b..7ef0b3f 100644 --- a/shared/meson.build +++ b/shared/meson.build @@ -2,7 +2,7 @@ qt5 = import('qt5') qt5deps = dependency('qt5', modules: ['OpenGL']) libmicrohttpddep = dependency('libmicrohttpd') -srcs = ['memcpy_interleaved.cpp', 'metacube2.cpp', 'ffmpeg_raii.cpp', 'mux.cpp', 'metrics.cpp', 'context.cpp', 'httpd.cpp'] +srcs = ['memcpy_interleaved.cpp', 'metacube2.cpp', 'ffmpeg_raii.cpp', 'mux.cpp', 'metrics.cpp', 'context.cpp', 'httpd.cpp', 'disk_space_estimator.cpp'] shared = static_library('shared', srcs, include_directories: top_include, dependencies: [qt5deps, libmicrohttpddep]) shareddep = declare_dependency( include_directories: top_include, -- 2.39.2