]> git.sesse.net Git - nageru/blob - disk_space_estimator.cpp
Fix an issue where the mixer lagging too much behind CEF would cause us to display...
[nageru] / disk_space_estimator.cpp
1 #include "disk_space_estimator.h"
2
3 #include <stdio.h>
4 #include <sys/stat.h>
5 #include <sys/statfs.h>
6 #include <memory>
7
8 #include "metrics.h"
9 #include "timebase.h"
10
11 DiskSpaceEstimator::DiskSpaceEstimator(DiskSpaceEstimator::callback_t callback)
12         : callback(callback)
13 {
14         global_metrics.add("disk_free_bytes", &metric_disk_free_bytes, Metrics::TYPE_GAUGE);
15 }
16
17 void DiskSpaceEstimator::report_write(const std::string &filename, uint64_t pts)
18 {
19         if (filename != last_filename) {
20                 last_filename = filename;
21                 measure_points.clear();
22         }
23
24         // Reject points that are out-of-order (happens with B-frames).
25         if (!measure_points.empty() && pts < measure_points.back().pts) {
26                 return;
27         }
28
29         // Remove too old points.
30         while (measure_points.size() > 1 && measure_points.front().pts + window_length < pts) {
31                 measure_points.pop_front();
32         }
33
34         struct stat st;
35         if (stat(filename.c_str(), &st) == -1) {
36                 perror(filename.c_str());
37                 return;
38         }
39
40         struct statfs fst;
41         if (statfs(filename.c_str(), &fst) == -1) {
42                 perror(filename.c_str());
43                 return;
44         }
45
46         off_t free_bytes = off_t(fst.f_bavail) * fst.f_frsize;
47         metric_disk_free_bytes = free_bytes;
48
49         if (!measure_points.empty()) {
50                 double bytes_per_second = double(st.st_size - measure_points.front().size) /
51                         (pts - measure_points.front().pts) * TIMEBASE;
52                 double seconds_left = free_bytes / bytes_per_second;
53
54                 // Only report every second, since updating the UI can be expensive.
55                 if (last_pts_reported == 0 || pts - last_pts_reported >= TIMEBASE) {
56                         callback(free_bytes, seconds_left);
57                         last_pts_reported = pts;
58                 }
59         }
60
61         measure_points.push_back({ pts, st.st_size });
62 }
63
64 DiskSpaceEstimator *global_disk_space_estimator = nullptr;  // Created in MainWindow::MainWindow().