]> git.sesse.net Git - nageru/blobdiff - nageru/mixer.cpp
WIP patch for async output.
[nageru] / nageru / mixer.cpp
index 191ddb7a50c64d5fd621d986dd452fbc2b0d9aec..22867422858e0913eb6dcd52fcb2ddac5767b09f 100644 (file)
@@ -232,11 +232,34 @@ void JitterHistory::unregister_metrics(const vector<pair<string, string>> &label
        global_metrics.remove("input_estimated_max_jitter_seconds", labels);
 }
 
-void JitterHistory::frame_arrived(steady_clock::time_point now, int64_t frame_duration, size_t dropped_frames)
+void JitterHistory::frame_arrived(steady_clock::time_point now, int64_t frame_duration, size_t dropped_frames, bool verbose)
 {
+       if (frame_duration != last_duration) {
+               // If the frame rate changed, the input clock is also going to change,
+               // so our historical data doesn't make much sense anymore.
+               // Also, format changes typically introduce blips that are not representative
+               // of the typical frame stream. (We make the assumption that format changes
+               // don't happen all the time in regular use; if they did, we should probably
+               // rather keep the history so that we take jitter they may introduce into account.)
+               clear();
+               last_duration = frame_duration;
+               if (verbose) {
+                       fprintf(stderr, "JITTER %p: clearing due to format change\n", this);
+               }
+       }
        if (expected_timestamp > steady_clock::time_point::min()) {
                expected_timestamp += dropped_frames * nanoseconds(frame_duration * 1000000000 / TIMEBASE);
                double jitter_seconds = fabs(duration<double>(expected_timestamp - now).count());
+               if (verbose) {
+                       fprintf(stderr, "JITTER %p: expected_ts=%.6f (after adding %.1f ms for %zu dropped frames, duration=%ld), now=%.6f => %.1f ms late\n",
+                               this,
+                               duration<double>(expected_timestamp.time_since_epoch()).count(),
+                               1e3 * dropped_frames * duration<double>(nanoseconds(frame_duration * 1000000000 / TIMEBASE)).count(),
+                               dropped_frames,
+                               frame_duration,
+                               duration<double>(now.time_since_epoch()).count(),
+                               1e3 * duration<double>(now - expected_timestamp).count());
+               }
                history.push_back(orders.insert(jitter_seconds));
                if (jitter_seconds > estimate_max_jitter()) {
                        ++metric_input_underestimated_jitter_frames;
@@ -249,6 +272,12 @@ void JitterHistory::frame_arrived(steady_clock::time_point now, int64_t frame_du
                        history.pop_front();
                }
                assert(history.size() <= history_length);
+       } else if (verbose) {
+               fprintf(stderr, "JITTER %p: now=%.6f, expected=%.6f duration=%ld [initial]\n",
+                       this,
+                       duration<double>(now.time_since_epoch()).count(),
+                       duration<double>((now + nanoseconds(frame_duration * 1000000000 / TIMEBASE)).time_since_epoch()).count(),
+                       frame_duration);
        }
        expected_timestamp = now + nanoseconds(frame_duration * 1000000000 / TIMEBASE);
 }
@@ -277,18 +306,18 @@ void QueueLengthPolicy::unregister_metrics(const vector<pair<string, string>> &l
 }
 
 void QueueLengthPolicy::update_policy(steady_clock::time_point now,
-                                      steady_clock::time_point expected_next_frame,
+                                      steady_clock::time_point expected_next_input_frame,
                                       int64_t input_frame_duration,
                                       int64_t master_frame_duration,
                                       double max_input_card_jitter_seconds,
-                                      double max_master_card_jitter_seconds)
+                                      double max_master_card_jitter_seconds, bool verbose)
 {
        double input_frame_duration_seconds = input_frame_duration / double(TIMEBASE);
        double master_frame_duration_seconds = master_frame_duration / double(TIMEBASE);
 
        // Figure out when we can expect the next frame for this card, assuming
        // worst-case jitter (ie., the frame is maximally late).
-       double seconds_until_next_frame = max(duration<double>(expected_next_frame - now).count() + max_input_card_jitter_seconds, 0.0);
+       double seconds_until_next_frame = max(duration<double>(expected_next_input_frame - now).count() + max_input_card_jitter_seconds, 0.0);
 
        // How many times are the master card expected to tick in that time?
        // We assume the master clock has worst-case jitter but not any rate
@@ -308,6 +337,13 @@ void QueueLengthPolicy::update_policy(steady_clock::time_point now,
        } else {
                frames_allowed = frames_needed;
        }
+       if (verbose) {
+               fprintf(stderr, "secs_until_next_frame = %.1f ms, input jitter = %.1f ms, master jitter = %.1f ms, frames_allowed = %.3f\n",
+                       1e3 * duration<double>(expected_next_input_frame - now).count(),
+                       1e3 * max_input_card_jitter_seconds,
+                       1e3 * max_master_card_jitter_seconds,
+                       frames_allowed);
+       }
 
        safe_queue_length = max<int>(floor(frames_allowed), 0);
        metric_input_queue_safe_length_frames = safe_queue_length;
@@ -889,7 +925,7 @@ void Mixer::set_output_card_internal(int card_index)
                card->jitter_history.clear();
                card->capture->start_bm_capture();
                desired_output_video_mode = output_video_mode = card->output->pick_video_mode(desired_output_video_mode);
-               card->output->start_output(desired_output_video_mode, pts_int);
+               card->output->start_output(desired_output_video_mode, pts_int, /*is_master_card=*/slave_to_output);
        }
        output_card_index = card_index;
        output_jitter_history.clear();
@@ -1276,7 +1312,7 @@ void Mixer::thread_func()
                        DeckLinkOutput *output = cards[output_card_index].output.get();
                        output->end_output();
                        desired_output_video_mode = output_video_mode = output->pick_video_mode(desired_output_video_mode);
-                       output->start_output(desired_output_video_mode, pts_int);
+                       output->start_output(desired_output_video_mode, pts_int, /*is_master_card=*/slave_to_output);
                }
 
                {
@@ -1289,7 +1325,7 @@ void Mixer::thread_func()
 
                bool master_card_is_output;
                unsigned master_card_index;
-               if (output_card_index != -1) {
+               if (output_card_index != -1 && slave_to_output) {
                        master_card_is_output = true;
                        master_card_index = output_card_index;
                } else {
@@ -1396,7 +1432,7 @@ void Mixer::thread_func()
 
 bool Mixer::input_card_is_master_clock(unsigned card_index, unsigned master_card_index) const
 {
-       if (output_card_index != -1) {
+       if (output_card_index != -1 && slave_to_output) {
                // The output card (ie., cards[output_card_index].output) is the master clock,
                // so no input card (ie., cards[card_index].capture) is.
                return false;
@@ -1976,7 +2012,7 @@ void Mixer::quit()
        if (global_flags.srt_port >= 0) {
                // There's seemingly no other reasonable way to wake up the thread
                // (libsrt's epoll equivalent is busy-waiting).
-               int sock = srt_socket(AF_INET6, 0, 0);
+               int sock = srt_create_socket();
                if (sock != -1) {
                        sockaddr_in6 addr;
                        memset(&addr, 0, sizeof(addr));
@@ -2185,7 +2221,7 @@ void Mixer::OutputChannel::set_color_updated_callback(Mixer::color_updated_callb
 #ifdef HAVE_SRT
 void Mixer::start_srt()
 {
-       SRTSOCKET sock = srt_socket(AF_INET6, 0, 0);
+       SRTSOCKET sock = srt_create_socket();
        sockaddr_in6 addr;
        memset(&addr, 0, sizeof(addr));
        addr.sin6_family = AF_INET6;