From: Steinar H. Gunderson Date: Sat, 10 Sep 2016 11:01:04 +0000 (+0200) Subject: Use std::chrono for (almost) all time keeping. X-Git-Tag: 1.4.0~138 X-Git-Url: https://git.sesse.net/?p=nageru;a=commitdiff_plain;h=21bd3592c1a692463abd321047c2c612f91cc2ad Use std::chrono for (almost) all time keeping. It is annoyingly verbose at times, but overall it's much less fiddly and low-level than timespec and friends, especially when doing arithmetic. --- diff --git a/mainwindow.cpp b/mainwindow.cpp index 9ed7d3e..fec26f2 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -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>("std::vector"); connect(ui->me_live, &GLWidget::transition_names_updated, this, &MainWindow::set_transition_names); qRegisterMetaType("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(now - last_audio_level_callback).count(); if (last_update_age < 0.100) { return; } diff --git a/mainwindow.h b/mainwindow.h index 6b791f9..31a2048 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -2,6 +2,7 @@ #define MAINWINDOW_H #include +#include #include #include #include @@ -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; diff --git a/mixer.cpp b/mixer.cpp index 05b7c51..9e281cb 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -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(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(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 05471d6..560827a 100644 --- a/mixer.h +++ b/mixer.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -561,7 +562,7 @@ private: bool is_mode_scanning[MAX_CARDS]{ false }; std::vector 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; diff --git a/x264_speed_control.cpp b/x264_speed_control.cpp index 7eca74d..f201f80 100644 --- a/x264_speed_control.cpp +++ b/x264_speed_control.cpp @@ -5,8 +5,10 @@ #include #include +#include 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(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(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(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(cpu_time_last_frame).count(); + wall = wall*decay + duration_cast(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; -} diff --git a/x264_speed_control.h b/x264_speed_control.h index 7add8fd..af4513e 100644 --- a/x264_speed_control.h +++ b/x264_speed_control.h @@ -47,6 +47,7 @@ #include #include #include +#include #include 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