#include <stdio.h>
#include <signal.h>
#include <algorithm>
+#include <chrono>
#include <string>
#include <vector>
#include <QBoxLayout>
class QResizeEvent;
using namespace std;
+using namespace std::chrono;
using namespace std::placeholders;
Q_DECLARE_METATYPE(std::string);
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)
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;
}
#define MAINWINDOW_H
#include <QMainWindow>
+#include <chrono>
#include <string>
#include <vector>
#include <sys/time.h>
// 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;
#include <sys/time.h>
#include <time.h>
#include <algorithm>
+#include <chrono>
#include <cmath>
#include <condition_variable>
#include <cstddef>
using namespace movit;
using namespace std;
+using namespace std::chrono;
using namespace std::placeholders;
using namespace bmusb;
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]++;
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.
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;
// 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);
}
{
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;
}
}
- 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,
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()
#include <movit/flat_input.h>
#include <zita-resampler/resampler.h>
#include <atomic>
+#include <chrono>
#include <condition_variable>
#include <cstddef>
#include <functional>
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;
#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)
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;
}
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;
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
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",
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)
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;
-}
#include <stdint.h>
#include <string.h>
#include <math.h>
+#include <chrono>
#include <functional>
extern "C" {
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