]> git.sesse.net Git - nageru/commitdiff
Use std::chrono for (almost) all time keeping.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 10 Sep 2016 11:01:04 +0000 (13:01 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 10 Sep 2016 11:03:54 +0000 (13:03 +0200)
It is annoyingly verbose at times, but overall it's much less
fiddly and low-level than timespec and friends, especially when
doing arithmetic.

mainwindow.cpp
mainwindow.h
mixer.cpp
mixer.h
x264_speed_control.cpp
x264_speed_control.h

index 9ed7d3e4ca7a3ea97cb084b5bb53a7d1077fb4c6..fec26f22fbf19544e4cf9dc921a3a002a696dbe6 100644 (file)
@@ -4,6 +4,7 @@
 #include <stdio.h>
 #include <signal.h>
 #include <algorithm>
+#include <chrono>
 #include <string>
 #include <vector>
 #include <QBoxLayout>
@@ -30,6 +31,7 @@
 class QResizeEvent;
 
 using namespace std;
+using namespace std::chrono;
 using namespace std::placeholders;
 
 Q_DECLARE_METATYPE(std::string);
@@ -121,6 +123,8 @@ MainWindow::MainWindow()
        qRegisterMetaType<vector<string>>("std::vector<std::string>");
        connect(ui->me_live, &GLWidget::transition_names_updated, this, &MainWindow::set_transition_names);
        qRegisterMetaType<Mixer::Output>("Mixer::Output");
+
+       last_audio_level_callback = steady_clock::now() - seconds(1);
 }
 
 void MainWindow::resizeEvent(QResizeEvent* event)
@@ -311,13 +315,11 @@ void MainWindow::audio_level_callback(float level_lufs, float peak_db, float glo
                                       float gain_staging_db, float final_makeup_gain_db,
                                       float correlation)
 {
-       timespec now;
-       clock_gettime(CLOCK_MONOTONIC, &now);
+       steady_clock::time_point now = steady_clock::now();
 
        // The meters are somewhat inefficient to update. Only update them
        // every 100 ms or so (we get updates every 5–20 ms).
-       double last_update_age = now.tv_sec - last_audio_level_callback.tv_sec +
-               1e-9 * (now.tv_nsec - last_audio_level_callback.tv_nsec);
+       double last_update_age = duration<double>(now - last_audio_level_callback).count();
        if (last_update_age < 0.100) {
                return;
        }
index 6b791f9d4c0095da97e304353b3d862f800180fd..31a204857910beb3f734b834a73e7053ee3745db 100644 (file)
@@ -2,6 +2,7 @@
 #define MAINWINDOW_H
 
 #include <QMainWindow>
+#include <chrono>
 #include <string>
 #include <vector>
 #include <sys/time.h>
@@ -56,7 +57,7 @@ private:
 
        // Called from the mixer.
        void audio_level_callback(float level_lufs, float peak_db, float global_level_lufs, float range_low_lufs, float range_high_lufs, float gain_staging_db, float final_makeup_gain_db, float correlation);
-       timespec last_audio_level_callback{0, 0};
+       std::chrono::steady_clock::time_point last_audio_level_callback;
 
        Ui::MainWindow *ui;
        QPushButton *transition_btn1, *transition_btn2, *transition_btn3;
index 05b7c51dcb78110f5bb94dcf910dbd3feeecef81..9e281cbdf72583470a1289b8030cdac7d042effa 100644 (file)
--- a/mixer.cpp
+++ b/mixer.cpp
@@ -18,6 +18,7 @@
 #include <sys/time.h>
 #include <time.h>
 #include <algorithm>
+#include <chrono>
 #include <cmath>
 #include <condition_variable>
 #include <cstddef>
@@ -46,6 +47,7 @@ class QOpenGLContext;
 
 using namespace movit;
 using namespace std;
+using namespace std::chrono;
 using namespace std::placeholders;
 using namespace bmusb;
 
@@ -380,10 +382,8 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
                        is_mode_scanning[card_index] = false;
                } else {
                        static constexpr double switch_time_s = 0.5;  // Should be enough time for the signal to stabilize.
-                       timespec now;
-                       clock_gettime(CLOCK_MONOTONIC, &now);
-                       double sec_since_last_switch = (now.tv_sec - last_mode_scan_change[card_index].tv_sec) +
-                               1e-9 * (now.tv_nsec - last_mode_scan_change[card_index].tv_nsec);
+                       steady_clock::time_point now = steady_clock::now();
+                       double sec_since_last_switch = duration<double>(steady_clock::now() - last_mode_scan_change[card_index]).count();
                        if (sec_since_last_switch > switch_time_s) {
                                // It isn't this mode; try the next one.
                                mode_scanlist_index[card_index]++;
@@ -505,7 +505,7 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
        PBOFrameAllocator::Userdata *userdata = (PBOFrameAllocator::Userdata *)video_frame.userdata;
 
        unsigned num_fields = video_format.interlaced ? 2 : 1;
-       timespec frame_upload_start;
+       steady_clock::time_point frame_upload_start;
        if (video_format.interlaced) {
                // Send the two fields along as separate frames; the other side will need to add
                // a deinterlacer to actually get this right.
@@ -514,7 +514,7 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
                assert(frame_length % 2 == 0);
                frame_length /= 2;
                num_fields = 2;
-               clock_gettime(CLOCK_MONOTONIC, &frame_upload_start);
+               frame_upload_start = steady_clock::now();
        }
        userdata->last_interlaced = video_format.interlaced;
        userdata->last_has_signal = video_format.has_signal;
@@ -595,16 +595,9 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
                        // against the video display, although the latter is not as critical.)
                        // This requires our system clock to be reasonably close to the
                        // video clock, but that's not an unreasonable assumption.
-                       timespec second_field_start;
-                       second_field_start.tv_nsec = frame_upload_start.tv_nsec +
-                               frame_length * 1000000000 / TIMEBASE;
-                       second_field_start.tv_sec = frame_upload_start.tv_sec +
-                               second_field_start.tv_nsec / 1000000000;
-                       second_field_start.tv_nsec %= 1000000000;
-
-                       while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
-                                              &second_field_start, nullptr) == -1 &&
-                              errno == EINTR) ;
+                       steady_clock::time_point second_field_start = frame_upload_start +
+                               nanoseconds(frame_length * 1000000000 / TIMEBASE);
+                       this_thread::sleep_until(second_field_start);
                }
 
                {
@@ -642,8 +635,8 @@ void Mixer::thread_func()
                exit(1);
        }
 
-       struct timespec start, now;
-       clock_gettime(CLOCK_MONOTONIC, &start);
+       steady_clock::time_point start, now;
+       start = steady_clock::now();
 
        int frame = 0;
        int stats_dropped_frames = 0;
@@ -700,14 +693,13 @@ void Mixer::thread_func()
                        }
                }
 
-               int64_t duration = new_frames[master_card_index].length;
-               render_one_frame(duration);
+               int64_t frame_duration = new_frames[master_card_index].length;
+               render_one_frame(frame_duration);
                ++frame;
-               pts_int += duration;
+               pts_int += frame_duration;
 
-               clock_gettime(CLOCK_MONOTONIC, &now);
-               double elapsed = now.tv_sec - start.tv_sec +
-                       1e-9 * (now.tv_nsec - start.tv_nsec);
+               now = steady_clock::now();
+               double elapsed = duration<double>(now - start).count();
                if (frame % 100 == 0) {
                        printf("%d frames (%d dropped) in %.3f seconds = %.1f fps (%.1f ms/frame)",
                                frame, stats_dropped_frames, elapsed, frame / elapsed,
@@ -1250,7 +1242,7 @@ void Mixer::start_mode_scanning(unsigned card_index)
        assert(!mode_scanlist[card_index].empty());
        mode_scanlist_index[card_index] = 0;
        cards[card_index].capture->set_video_mode(mode_scanlist[card_index][0]);
-       clock_gettime(CLOCK_MONOTONIC, &last_mode_scan_change[card_index]);
+       last_mode_scan_change[card_index] = steady_clock::now();
 }
 
 Mixer::OutputChannel::~OutputChannel()
diff --git a/mixer.h b/mixer.h
index 05471d6d61ae550af47a8ceb03faebfbc29697ca..560827ae26a96b80ca0150131d551bb758043fb1 100644 (file)
--- a/mixer.h
+++ b/mixer.h
@@ -12,6 +12,7 @@
 #include <movit/flat_input.h>
 #include <zita-resampler/resampler.h>
 #include <atomic>
+#include <chrono>
 #include <condition_variable>
 #include <cstddef>
 #include <functional>
@@ -561,7 +562,7 @@ private:
        bool is_mode_scanning[MAX_CARDS]{ false };
        std::vector<uint32_t> mode_scanlist[MAX_CARDS];
        unsigned mode_scanlist_index[MAX_CARDS]{ 0 };
-       timespec last_mode_scan_change[MAX_CARDS];
+       std::chrono::steady_clock::time_point last_mode_scan_change[MAX_CARDS];
 };
 
 extern Mixer *global_mixer;
index 7eca74d1550e72ed9dcb7a9d5a73a78f881149e4..f201f80066fab4d9c048af9399d3df668c84fae6 100644 (file)
@@ -5,8 +5,10 @@
 #include <time.h>
 
 #include <algorithm>
+#include <chrono>
 
 using namespace std;
+using namespace std::chrono;
 
 X264SpeedControl::X264SpeedControl(x264_t *x264, float f_speed, int i_buffer_size, float f_buffer_init)
        : x264(x264), f_speed(f_speed)
@@ -20,7 +22,7 @@ X264SpeedControl::X264SpeedControl(x264_t *x264, float f_speed, int i_buffer_siz
        buffer_fill = buffer_size * f_buffer_init;
        buffer_fill = max<int64_t>(buffer_fill, uspf);
        buffer_fill = min(buffer_fill, buffer_size);
-       timestamp = mdate();
+       timestamp = steady_clock::now();
        preset = -1;
        cplx_num = 3e3; //FIXME estimate initial complexity
        cplx_den = .1;
@@ -164,22 +166,22 @@ void X264SpeedControl::before_frame(float new_buffer_fill, int new_buffer_size,
        }
        buffer_fill = buffer_size * new_buffer_fill;
 
-       int64_t t, delta_t;
+       steady_clock::time_point t;
 
        // update buffer state after encoding and outputting the previous frame(s)
        if (first) {
-               t = timestamp = mdate();
+               t = timestamp = steady_clock::now();
                first = false;
        } else {
-               t = mdate();
+               t = steady_clock::now();
        }
 
-       delta_t = t - timestamp;
+       auto delta_t = t - timestamp;
        timestamp = t;
 
        // update the time predictor
        if (preset >= 0) {
-               int cpu_time = cpu_time_last_frame;
+               int cpu_time = duration_cast<microseconds>(cpu_time_last_frame).count();
                cplx_num *= cplx_decay;
                cplx_den *= cplx_decay;
                cplx_num += cpu_time / presets[preset].time;
@@ -194,12 +196,15 @@ void X264SpeedControl::before_frame(float new_buffer_fill, int new_buffer_size,
 
        if (buffer_fill >= buffer_size) { // oops, cpu was idle
                // not really an error, but we'll warn for debugging purposes
-               static int64_t idle_t = 0, print_interval = 0;
+               static int64_t idle_t = 0;
+               static steady_clock::time_point print_interval;
+               static bool first = false;
                idle_t += buffer_fill - buffer_size;
-               if (t - print_interval > 1e6) {
+               if (first || duration<double>(t - print_interval).count() > 0.1) {
                        //fprintf(stderr, "speedcontrol idle (%.6f sec)\n", idle_t/1e6);
                        print_interval = t;
                        idle_t = 0;
+                       first = false;
                }
                buffer_fill = buffer_size;
        } else if (buffer_fill <= 0) {  // oops, we're late
@@ -247,8 +252,8 @@ void X264SpeedControl::before_frame(float new_buffer_fill, int new_buffer_size,
                if (global_flags.x264_speedcontrol_verbose) {
                        static float cpu, wall, tgt, den;
                        const float decay = 1-1/100.;
-                       cpu = cpu*decay + cpu_time_last_frame;
-                       wall = wall*decay + delta_t;
+                       cpu = cpu*decay + duration_cast<microseconds>(cpu_time_last_frame).count();
+                       wall = wall*decay + duration_cast<microseconds>(delta_t).count();
                        tgt = tgt*decay + target;
                        den = den*decay + 1;
                        fprintf(stderr, "speed: %.2f+%.2f %d[%.5f] (t/c/w: %6.0f/%6.0f/%6.0f = %.4f) fps=%.2f\r",
@@ -261,7 +266,7 @@ void X264SpeedControl::before_frame(float new_buffer_fill, int new_buffer_size,
 
 void X264SpeedControl::after_frame()
 {
-       cpu_time_last_frame = mdate() - timestamp;
+       cpu_time_last_frame = steady_clock::now() - timestamp;
 }
 
 void X264SpeedControl::set_buffer_size(int new_buffer_size)
@@ -311,10 +316,3 @@ void X264SpeedControl::apply_preset(int new_preset)
        x264_encoder_reconfig(x264, &p);
        preset = new_preset;
 }
-
-int64_t X264SpeedControl::mdate()
-{
-       timespec now;
-       clock_gettime(CLOCK_MONOTONIC, &now);
-       return now.tv_sec * 1000000 + now.tv_nsec / 1000;
-}
index 7add8fdd4c2c2a3c9386d74a0854aa2389bc9e41..af4513ea5a037ab596e7a016ed98fee1e1acf73b 100644 (file)
@@ -47,6 +47,7 @@
 #include <stdint.h>
 #include <string.h>
 #include <math.h>
+#include <chrono>
 #include <functional>
 
 extern "C" {
@@ -96,16 +97,15 @@ private:
        void set_buffer_size(int new_buffer_size);
        int dither_preset(float f);
        void apply_preset(int new_preset);
-       int64_t mdate();  // Current time in microseconds.
 
        // Not owned by us.
        x264_t *x264;
 
        float f_speed;
 
-       // all times are in usec
-       int64_t timestamp;   // when was speedcontrol last invoked
-       int64_t cpu_time_last_frame = 0;    // time spent encoding the previous frame
+       // all times that are not std::chrono::* are in usec
+       std::chrono::steady_clock::time_point timestamp;   // when was speedcontrol last invoked
+       std::chrono::steady_clock::duration cpu_time_last_frame{std::chrono::seconds{0}};   // time spent encoding the previous frame
        int64_t buffer_size; // assumed application-side buffer of frames to be streamed (measured in microseconds),
        int64_t buffer_fill; //   where full = we don't have to hurry
        int64_t compensation_period; // how quickly we try to return to the target buffer fullness