From e9f3f2c02ff623eb9e0213cd4eef924a8d699f47 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sat, 24 Dec 2016 11:50:00 +0100 Subject: [PATCH] Prepare get_one_frame_from_each_card() interface for different clocks. This interface is more flexible, and less bound to the idea of having the master clock locked to an input card. --- mixer.cpp | 31 +++++++++++++++++++------------ mixer.h | 15 ++++++++++----- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/mixer.cpp b/mixer.cpp index 85f974b..db7a060 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -330,7 +330,6 @@ void Mixer::configure_card(unsigned card_index, CaptureInterface *capture, bool card->surface = create_surface_with_same_format(mixer_surface); } while (!card->new_frames.empty()) card->new_frames.pop(); - card->fractional_samples = 0; card->last_timecode = -1; card->capture->configure_card(); @@ -606,14 +605,13 @@ void Mixer::thread_func() while (!should_quit) { CaptureCard::NewFrame new_frames[MAX_VIDEO_CARDS]; bool has_new_frame[MAX_VIDEO_CARDS] = { false }; - int num_samples[MAX_VIDEO_CARDS] = { 0 }; unsigned master_card_index = theme->map_signal(master_clock_channel); assert(master_card_index < num_cards); - get_one_frame_from_each_card(master_card_index, new_frames, has_new_frame, num_samples); - schedule_audio_resampling_tasks(new_frames[master_card_index].dropped_frames, num_samples[master_card_index], new_frames[master_card_index].length); - stats_dropped_frames += new_frames[master_card_index].dropped_frames; + OutputFrameInfo output_frame_info = get_one_frame_from_each_card(master_card_index, new_frames, has_new_frame); + schedule_audio_resampling_tasks(output_frame_info.dropped_frames, output_frame_info.num_samples, output_frame_info.frame_duration); + stats_dropped_frames += output_frame_info.dropped_frames; handle_hotplugged_cards(); @@ -654,7 +652,7 @@ void Mixer::thread_func() } } - int64_t frame_duration = new_frames[master_card_index].length; + int64_t frame_duration = output_frame_info.frame_duration; render_one_frame(frame_duration); ++frame; pts_int += frame_duration; @@ -715,8 +713,10 @@ void Mixer::thread_func() resource_pool->clean_context(); } -void Mixer::get_one_frame_from_each_card(unsigned master_card_index, CaptureCard::NewFrame new_frames[MAX_VIDEO_CARDS], bool has_new_frame[MAX_VIDEO_CARDS], int num_samples[MAX_VIDEO_CARDS]) +Mixer::OutputFrameInfo Mixer::get_one_frame_from_each_card(unsigned master_card_index, CaptureCard::NewFrame new_frames[MAX_VIDEO_CARDS], bool has_new_frame[MAX_VIDEO_CARDS]) { + OutputFrameInfo output_frame_info; + start: // The first card is the master timer, so wait for it to have a new frame. // TODO: Add a timeout. @@ -743,11 +743,6 @@ start: card->new_frames.pop(); card->new_frames_changed.notify_all(); - int num_samples_times_timebase = OUTPUT_FREQUENCY * new_frames[card_index].length + card->fractional_samples; - num_samples[card_index] = num_samples_times_timebase / TIMEBASE; - card->fractional_samples = num_samples_times_timebase % TIMEBASE; - assert(num_samples[card_index] >= 0); - if (card_index == master_card_index) { // We don't use the queue length policy for the master card, // but we will if it stops being the master. Thus, clear out @@ -762,6 +757,18 @@ start: } } } + + output_frame_info.dropped_frames = new_frames[master_card_index].dropped_frames; + output_frame_info.frame_duration = new_frames[master_card_index].length; + + // This might get off by a fractional sample when changing master card + // between ones with different frame rates, but that's fine. + int num_samples_times_timebase = OUTPUT_FREQUENCY * output_frame_info.frame_duration + fractional_samples; + output_frame_info.num_samples = num_samples_times_timebase / TIMEBASE; + fractional_samples = num_samples_times_timebase % TIMEBASE; + assert(output_frame_info.num_samples >= 0); + + return output_frame_info; } void Mixer::handle_hotplugged_cards() diff --git a/mixer.h b/mixer.h index 0de6519..28b190b 100644 --- a/mixer.h +++ b/mixer.h @@ -320,6 +320,10 @@ private: int64_t pts_int = 0; // In TIMEBASE units. + // Accumulated errors in number of 1/TIMEBASE audio samples. If OUTPUT_FREQUENCY divided by + // frame rate is integer, will always stay zero. + unsigned fractional_samples = 0; + std::mutex bmusb_mutex; bool has_bmusb_thread = false; struct CaptureCard { @@ -345,15 +349,16 @@ private: QueueLengthPolicy queue_length_policy; // Refers to the "new_frames" queue. - // Accumulated errors in number of 1/TIMEBASE samples. If OUTPUT_FREQUENCY divided by - // frame rate is integer, will always stay zero. - unsigned fractional_samples = 0; - int last_timecode = -1; // Unwrapped. }; CaptureCard cards[MAX_VIDEO_CARDS]; // protected by AudioMixer audio_mixer; // Same as global_audio_mixer (see audio_mixer.h). - void get_one_frame_from_each_card(unsigned master_card_index, CaptureCard::NewFrame new_frames[MAX_VIDEO_CARDS], bool has_new_frame[MAX_VIDEO_CARDS], int num_samples[MAX_VIDEO_CARDS]); + struct OutputFrameInfo { + int dropped_frames; // Since last frame. + int num_samples; // Audio samples needed for this output frame. + int64_t frame_duration; // In TIMEBASE units. + }; + OutputFrameInfo get_one_frame_from_each_card(unsigned master_card_index, CaptureCard::NewFrame new_frames[MAX_VIDEO_CARDS], bool has_new_frame[MAX_VIDEO_CARDS]); InputState input_state; -- 2.39.2