X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=mixer.cpp;h=780bd52573c3380404cd77a36aa1892bfa8642cf;hb=02f65224836f4e7ccecfb89ccd8dc38ee32f319a;hp=b684b3d4d0e4dc404973ae4ef08c6c703599c2ac;hpb=2a30d1f3a428511dab64587bd7615bc528a2573b;p=nageru diff --git a/mixer.cpp b/mixer.cpp index b684b3d..780bd52 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -3,7 +3,6 @@ #include "mixer.h" #include -#include #include #include #include @@ -16,33 +15,37 @@ #include #include #include -#include -#include #include #include -#include #include #include +#include #include #include +#include #include #include #include #include +#include "DeckLinkAPI.h" +#include "LinuxCOM.h" +#include "alsa_output.h" #include "bmusb/bmusb.h" #include "bmusb/fake_capture.h" #include "context.h" -#include "db.h" #include "decklink_capture.h" #include "defs.h" #include "disk_space_estimator.h" #include "flags.h" +#include "input_mapping.h" #include "pbo_frame_allocator.h" #include "ref_counted_gl_sync.h" +#include "resampling_queue.h" #include "timebase.h" #include "video_encoder.h" +class IDeckLink; class QOpenGLContext; using namespace movit; @@ -105,8 +108,7 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards) num_cards(num_cards), mixer_surface(create_surface(format)), h264_encoder_surface(create_surface(format)), - audio_mixer(num_cards), - correlation(OUTPUT_FREQUENCY) + audio_mixer(num_cards) { CHECK(init_movit(MOVIT_SHADER_DIR, MOVIT_DEBUG_OFF)); check_error(); @@ -232,13 +234,6 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards) cbcr_position_attribute_index = glGetAttribLocation(cbcr_program_num, "position"); cbcr_texcoord_attribute_index = glGetAttribLocation(cbcr_program_num, "texcoord"); - r128.init(2, OUTPUT_FREQUENCY); - r128.integr_start(); - - // hlen=16 is pretty low quality, but we use quite a bit of CPU otherwise, - // and there's a limit to how important the peak meter is. - peak_resampler.setup(OUTPUT_FREQUENCY, OUTPUT_FREQUENCY * 4, /*num_channels=*/2, /*hlen=*/16, /*frel=*/1.0); - if (global_flags.enable_alsa_output) { alsa.reset(new ALSAOutput(OUTPUT_FREQUENCY, /*num_channels=*/2)); } @@ -281,11 +276,15 @@ void Mixer::configure_card(unsigned card_index, CaptureInterface *capture, bool if (card->surface == nullptr) { card->surface = create_surface_with_same_format(mixer_surface); } - audio_mixer.reset_card(card_index); while (!card->new_frames.empty()) card->new_frames.pop(); card->fractional_samples = 0; card->last_timecode = -1; card->capture->configure_card(); + + DeviceSpec device{InputSourceType::CAPTURE_CARD, card_index}; + audio_mixer.reset_resampler(device); + audio_mixer.set_display_name(device, card->capture->get_description()); + audio_mixer.trigger_state_changed_callback(); } @@ -301,36 +300,13 @@ int unwrap_timecode(uint16_t current_wrapped, int last) } } -float find_peak(const float *samples, size_t num_samples) -{ - float m = fabs(samples[0]); - for (size_t i = 1; i < num_samples; ++i) { - m = max(m, fabs(samples[i])); - } - return m; -} - -void deinterleave_samples(const vector &in, vector *out_l, vector *out_r) -{ - size_t num_samples = in.size() / 2; - out_l->resize(num_samples); - out_r->resize(num_samples); - - const float *inptr = in.data(); - float *lptr = &(*out_l)[0]; - float *rptr = &(*out_r)[0]; - for (size_t i = 0; i < num_samples; ++i) { - *lptr++ = *inptr++; - *rptr++ = *inptr++; - } -} - } // namespace void Mixer::bm_frame(unsigned card_index, uint16_t timecode, FrameAllocator::Frame video_frame, size_t video_offset, VideoFormat video_format, FrameAllocator::Frame audio_frame, size_t audio_offset, AudioFormat audio_format) { + DeviceSpec device{InputSourceType::CAPTURE_CARD, card_index}; CaptureCard *card = &cards[card_index]; if (is_mode_scanning[card_index]) { @@ -380,17 +356,20 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode, if (dropped_frames > MAX_FPS * 2) { fprintf(stderr, "Card %d lost more than two seconds (or time code jumping around; from 0x%04x to 0x%04x), resetting resampler\n", card_index, card->last_timecode, timecode); - audio_mixer.reset_card(card_index); + audio_mixer.reset_resampler(device); dropped_frames = 0; } else if (dropped_frames > 0) { // Insert silence as needed. fprintf(stderr, "Card %d dropped %d frame(s) (before timecode 0x%04x), inserting silence.\n", card_index, dropped_frames, timecode); - audio_mixer.add_silence(card_index, silence_samples, dropped_frames, frame_length); + bool success; + do { + success = audio_mixer.add_silence(device, silence_samples, dropped_frames, frame_length); + } while (!success); } - audio_mixer.add_audio(card_index, audio_frame.data + audio_offset, num_samples, audio_format, frame_length); + audio_mixer.add_audio(device, audio_frame.data + audio_offset, num_samples, audio_format, frame_length); // Done with the audio, so release it. if (audio_frame.owner) { @@ -565,9 +544,9 @@ void Mixer::thread_func() int stats_dropped_frames = 0; while (!should_quit) { - CaptureCard::NewFrame new_frames[MAX_CARDS]; - bool has_new_frame[MAX_CARDS] = { false }; - int num_samples[MAX_CARDS] = { 0 }; + 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); @@ -575,7 +554,6 @@ void Mixer::thread_func() 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; - send_audio_level_callback(); handle_hotplugged_cards(); @@ -677,7 +655,7 @@ 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_CARDS], bool has_new_frame[MAX_CARDS], int num_samples[MAX_CARDS]) +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]) { start: // The first card is the master timer, so wait for it to have a new frame. @@ -865,25 +843,6 @@ void Mixer::render_one_frame(int64_t duration) } } -void Mixer::send_audio_level_callback() -{ - if (audio_level_callback == nullptr) { - return; - } - - unique_lock lock(audio_measure_mutex); - double loudness_s = r128.loudness_S(); - double loudness_i = r128.integrated(); - double loudness_range_low = r128.range_min(); - double loudness_range_high = r128.range_max(); - - audio_level_callback(loudness_s, to_db(peak), - loudness_i, loudness_range_low, loudness_range_high, - audio_mixer.get_gain_staging_db(), - audio_mixer.get_final_makeup_gain_db(), - correlation.get_correlation()); -} - void Mixer::audio_thread_func() { while (!should_quit) { @@ -901,51 +860,17 @@ void Mixer::audio_thread_func() ResamplingQueue::RateAdjustmentPolicy rate_adjustment_policy = task.adjust_rate ? ResamplingQueue::ADJUST_RATE : ResamplingQueue::DO_NOT_ADJUST_RATE; - process_audio_one_frame(task.pts_int, task.num_samples, rate_adjustment_policy); - } -} - -void Mixer::process_audio_one_frame(int64_t frame_pts_int, int num_samples, ResamplingQueue::RateAdjustmentPolicy rate_adjustment_policy) -{ - vector samples_out = audio_mixer.get_output(double(frame_pts_int) / TIMEBASE, num_samples, rate_adjustment_policy); - - // Upsample 4x to find interpolated peak. - peak_resampler.inp_data = samples_out.data(); - peak_resampler.inp_count = samples_out.size() / 2; - - vector interpolated_samples_out; - interpolated_samples_out.resize(samples_out.size()); - { - unique_lock lock(audio_measure_mutex); - - while (peak_resampler.inp_count > 0) { // About four iterations. - peak_resampler.out_data = &interpolated_samples_out[0]; - peak_resampler.out_count = interpolated_samples_out.size() / 2; - peak_resampler.process(); - size_t out_stereo_samples = interpolated_samples_out.size() / 2 - peak_resampler.out_count; - peak = max(peak, find_peak(interpolated_samples_out.data(), out_stereo_samples * 2)); - peak_resampler.out_data = nullptr; + vector samples_out = audio_mixer.get_output( + double(task.pts_int) / TIMEBASE, + task.num_samples, + rate_adjustment_policy); + + // Send the samples to the sound card, then add them to the output. + if (alsa) { + alsa->write(samples_out); } + video_encoder->add_audio(task.pts_int, move(samples_out)); } - - // Find R128 levels and L/R correlation. - vector left, right; - deinterleave_samples(samples_out, &left, &right); - float *ptrs[] = { left.data(), right.data() }; - { - unique_lock lock(audio_measure_mutex); - r128.process(left.size(), ptrs); - audio_mixer.set_current_loudness(r128.loudness_M()); - correlation.process_samples(samples_out); - } - - // Send the samples to the sound card. - if (alsa) { - alsa->write(samples_out); - } - - // And finally add them to the output. - video_encoder->add_audio(frame_pts_int, move(samples_out)); } void Mixer::subsample_chroma(GLuint src_tex, GLuint dst_tex) @@ -1041,16 +966,6 @@ void Mixer::channel_clicked(int preview_num) theme->channel_clicked(preview_num); } -void Mixer::reset_meters() -{ - unique_lock lock(audio_measure_mutex); - peak_resampler.reset(); - peak = 0.0f; - r128.reset(); - r128.integr_start(); - correlation.reset(); -} - void Mixer::start_mode_scanning(unsigned card_index) { assert(card_index < num_cards);