X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=mixer.h;h=8504d5eb4bb9d6a56d8b68dd2ab04464b0bcecfd;hb=96cb6414f85e0ef4d660b7bd56267303e80fcd05;hp=7837b3568641edb415444427655d03f30510bf5b;hpb=336009fd7baf47b4ad71adf8d7ead8a526045788;p=nageru diff --git a/mixer.h b/mixer.h index 7837b35..8504d5e 100644 --- a/mixer.h +++ b/mixer.h @@ -23,6 +23,8 @@ #include #include +#include + #include "audio_mixer.h" #include "bmusb/bmusb.h" #include "defs.h" @@ -35,6 +37,7 @@ #include "theme.h" #include "timebase.h" #include "video_encoder.h" +#include "ycbcr_interpretation.h" class ALSAOutput; class ChromaSubsampler; @@ -85,6 +88,8 @@ public: been_at_safe_point_since_last_starvation = false; } + void register_metrics(const std::vector> &labels); + void update_policy(unsigned queue_length); // Call before picking out a frame, so 0 means starvation. unsigned get_safe_queue_length() const { return safe_queue_length; } @@ -93,6 +98,11 @@ private: unsigned safe_queue_length = 1; // Called N in the comments. Can never go below 1. unsigned frames_with_at_least_one = 0; bool been_at_safe_point_since_last_starvation = false; + + // Metrics. + std::atomic metric_input_queue_length_frames{0}; + std::atomic metric_input_queue_safe_length_frames{1}; + std::atomic metric_input_duped_frames{0}; }; class Mixer { @@ -139,10 +149,17 @@ public: return output_channel[output].get_display_frame(frame); } + // NOTE: Callbacks will be called with a mutex held, so you should probably + // not do real work in them. typedef std::function new_frame_ready_callback_t; - void set_frame_ready_callback(Output output, new_frame_ready_callback_t callback) + void add_frame_ready_callback(Output output, void *key, new_frame_ready_callback_t callback) + { + output_channel[output].add_frame_ready_callback(key, callback); + } + + void remove_frame_ready_callback(Output output, void *key) { - output_channel[output].set_frame_ready_callback(callback); + output_channel[output].remove_frame_ready_callback(key); } // TODO: Should this really be per-channel? Shouldn't it just be called for e.g. the live output? @@ -209,6 +226,9 @@ public: return theme->set_signal_mapping(signal, card); } + YCbCrInterpretation get_input_ycbcr_interpretation(unsigned card_index) const; + void set_input_ycbcr_interpretation(unsigned card_index, const YCbCrInterpretation &interpretation); + bool get_supports_set_wb(unsigned channel) const { return theme->get_supports_set_wb(channel); @@ -334,7 +354,12 @@ public: private: struct CaptureCard; - void configure_card(unsigned card_index, bmusb::CaptureInterface *capture, bool is_fake_capture, DeckLinkOutput *output); + enum class CardType { + LIVE_CARD, + FAKE_CAPTURE, + FFMPEG_INPUT + }; + void configure_card(unsigned card_index, bmusb::CaptureInterface *capture, CardType card_type, DeckLinkOutput *output); void set_output_card_internal(int card_index); // Should only be called from the mixer thread. void bm_frame(unsigned card_index, uint16_t timecode, bmusb::FrameAllocator::Frame video_frame, size_t video_offset, bmusb::VideoFormat video_format, @@ -355,7 +380,7 @@ private: void trim_queue(CaptureCard *card, unsigned card_index); HTTPD httpd; - unsigned num_cards; + unsigned num_cards, num_video_inputs; QSurface *mixer_surface, *h264_encoder_surface, *decklink_output_surface; std::unique_ptr resource_pool; @@ -397,6 +422,7 @@ private: struct CaptureCard { std::unique_ptr capture; bool is_fake_capture; + CardType type; std::unique_ptr output; // If this card is used for output (ie., output_card_index points to it), @@ -427,8 +453,23 @@ private: QueueLengthPolicy queue_length_policy; // Refers to the "new_frames" queue. int last_timecode = -1; // Unwrapped. + + // Metrics. + std::atomic metric_input_dropped_frames_jitter{0}; + std::atomic metric_input_dropped_frames_error{0}; + std::atomic metric_input_resets{0}; + + std::atomic metric_input_has_signal_bool{-1}; + std::atomic metric_input_is_connected_bool{-1}; + std::atomic metric_input_interlaced_bool{-1}; + std::atomic metric_input_width_pixels{-1}; + std::atomic metric_input_height_pixels{-1}; + std::atomic metric_input_frame_rate_nom{-1}; + std::atomic metric_input_frame_rate_den{-1}; + std::atomic metric_input_sample_rate_hz{-1}; }; CaptureCard cards[MAX_VIDEO_CARDS]; // Protected by . + YCbCrInterpretation ycbcr_interpretation[MAX_VIDEO_CARDS]; // Protected by . AudioMixer audio_mixer; // Same as global_audio_mixer (see audio_mixer.h). bool input_card_is_master_clock(unsigned card_index, unsigned master_card_index) const; struct OutputFrameInfo { @@ -452,7 +493,8 @@ private: ~OutputChannel(); void output_frame(DisplayFrame frame); bool get_display_frame(DisplayFrame *frame); - void set_frame_ready_callback(new_frame_ready_callback_t callback); + void add_frame_ready_callback(void *key, new_frame_ready_callback_t callback); + void remove_frame_ready_callback(void *key); void set_transition_names_updated_callback(transition_names_updated_callback_t callback); void set_name_updated_callback(name_updated_callback_t callback); void set_color_updated_callback(color_updated_callback_t callback); @@ -465,7 +507,7 @@ private: std::mutex frame_mutex; DisplayFrame current_frame, ready_frame; // protected by bool has_current_frame = false, has_ready_frame = false; // protected by - new_frame_ready_callback_t new_frame_ready_callback; + std::map new_frame_ready_callbacks; // protected by transition_names_updated_callback_t transition_names_updated_callback; name_updated_callback_t name_updated_callback; color_updated_callback_t color_updated_callback; @@ -497,6 +539,13 @@ private: std::vector mode_scanlist[MAX_VIDEO_CARDS]; unsigned mode_scanlist_index[MAX_VIDEO_CARDS]{ 0 }; std::chrono::steady_clock::time_point last_mode_scan_change[MAX_VIDEO_CARDS]; + + // Metrics. + std::atomic metric_frames_output_total{0}; + std::atomic metric_frames_output_dropped{0}; + std::atomic metric_start_time_seconds{0.0 / 0.0}; + std::atomic metrics_memory_used_bytes{0}; + std::atomic metrics_memory_locked_limit_bytes{0.0 / 0.0}; }; extern Mixer *global_mixer;