]> git.sesse.net Git - nageru/blob - shared/disk_space_estimator.cpp
Make Futatabi fades apply white balance.
[nageru] / shared / disk_space_estimator.cpp
1 #include "shared/disk_space_estimator.h"
2
3 #include <memory>
4 #include <stdio.h>
5 #include <sys/stat.h>
6 #include <sys/statfs.h>
7
8 #include "shared/metrics.h"
9 #include "shared/timebase.h"
10
11 using namespace std;
12
13 DiskSpaceEstimator::DiskSpaceEstimator(DiskSpaceEstimator::callback_t callback)
14         : callback(callback)
15 {
16         global_metrics.add("disk_free_bytes", &metric_disk_free_bytes, Metrics::TYPE_GAUGE);
17 }
18
19 void DiskSpaceEstimator::report_write(const string &filename, off_t bytes, uint64_t pts)
20 {
21         total_size += bytes;
22         report_write_internal(filename, total_size, pts);
23 }
24
25 void DiskSpaceEstimator::report_append(const string &filename, uint64_t pts)
26 {
27         if (filename != last_filename) {
28                 last_filename = filename;
29                 measure_points.clear();
30         }
31
32         struct stat st;
33         if (stat(filename.c_str(), &st) == -1) {
34                 perror(filename.c_str());
35                 return;
36         }
37
38         report_write_internal(filename, st.st_size, pts);
39 }
40
41 void DiskSpaceEstimator::report_write_internal(const string &filename, off_t file_size, uint64_t pts)
42 {
43         if (measure_points.empty()) {
44                 first_pts_this_file = pts;
45         }
46
47         // Reject points that are out-of-order (happens with B-frames).
48         if (!measure_points.empty() && pts <= measure_points.back().pts) {
49                 return;
50         }
51
52         // Remove too old points.
53         while (measure_points.size() > 1 && measure_points.front().pts + window_length < pts) {
54                 measure_points.pop_front();
55         }
56
57         struct statfs fst;
58         if (statfs(filename.c_str(), &fst) == -1) {
59                 perror(filename.c_str());
60                 return;
61         }
62
63         off_t free_bytes = off_t(fst.f_bavail) * fst.f_frsize;
64         metric_disk_free_bytes = free_bytes;
65
66         if (!measure_points.empty()) {
67                 double bytes_per_second = double(file_size - measure_points.front().size) /
68                         (pts - measure_points.front().pts) * TIMEBASE;
69                 double seconds_left = free_bytes / bytes_per_second;
70
71                 // Only report every second, since updating the UI can be expensive.
72                 if (last_pts_reported == 0 || pts - last_pts_reported >= TIMEBASE) {
73                         callback(free_bytes, seconds_left, double(pts - first_pts_this_file) / TIMEBASE);
74                         last_pts_reported = pts;
75                 }
76         }
77
78         measure_points.push_back({ pts, file_size });
79 }
80
81 DiskSpaceEstimator *global_disk_space_estimator = nullptr;  // Created in MainWindow::MainWindow().