X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=mixer.h;h=5fb195ec77793faf0a8e9d3989758caf6650b7de;hb=bcdbb7bdfcfc45b34ccdf36d3950e7e0af6444bd;hp=bf388b1cece6edf6f1b98928ba70c023a784e535;hpb=9aabf53d2ee424e66e3d51039a7a8ecce25f3516;p=nageru diff --git a/mixer.h b/mixer.h index bf388b1..5fb195e 100644 --- a/mixer.h +++ b/mixer.h @@ -41,12 +41,14 @@ class ChromaSubsampler; class DeckLinkOutput; class QSurface; class QSurfaceFormat; +class TimecodeRenderer; +class v210Converter; namespace movit { class Effect; class EffectChain; -class FlatInput; class ResourcePool; +class YCbCrInput; } // namespace movit // For any card that's not the master (where we pick out the frames as they @@ -68,8 +70,7 @@ class ResourcePool; // // N is reduced as follows: If the queue has had at least one spare frame for // at least 50 (master) frames (ie., it's been too conservative for a second), -// we reduce N by 1 and reset the timers. TODO: Only do this if N ever actually -// touched the limit. +// we reduce N by 1 and reset the timers. // // Whenever the queue is starved (we needed a frame but there was none), // and we've been at N since the last starvation, N was obviously too low, @@ -79,17 +80,17 @@ public: QueueLengthPolicy() {} void reset(unsigned card_index) { this->card_index = card_index; - safe_queue_length = 0; + safe_queue_length = 1; frames_with_at_least_one = 0; been_at_safe_point_since_last_starvation = false; } - void update_policy(int queue_length); // Give in -1 for starvation. + 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; } private: unsigned card_index; // For debugging only. - unsigned safe_queue_length = 0; // Called N in the comments. + 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; }; @@ -322,8 +323,23 @@ public: desired_output_video_mode = mode; } + void set_display_timecode_in_stream(bool enable) { + display_timecode_in_stream = enable; + } + + void set_display_timecode_on_stdout(bool enable) { + display_timecode_on_stdout = enable; + } + private: - void configure_card(unsigned card_index, bmusb::CaptureInterface *capture, bool is_fake_capture, DeckLinkOutput *output); + struct CaptureCard; + + 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, @@ -334,13 +350,17 @@ private: void thread_func(); void handle_hotplugged_cards(); void schedule_audio_resampling_tasks(unsigned dropped_frames, int num_samples_per_frame, int length_per_frame, bool is_preroll, std::chrono::steady_clock::time_point frame_timestamp); + std::string get_timecode_text() const; void render_one_frame(int64_t duration); void audio_thread_func(); void release_display_frame(DisplayFrame *frame); double pts() { return double(pts_int) / TIMEBASE; } + // Call this _before_ trying to pull out a frame from a capture card; + // it will update the policy and drop the right amount of frames for you. + 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; @@ -360,12 +380,18 @@ private: std::unique_ptr display_chain; std::unique_ptr chroma_subsampler; + std::unique_ptr v210_converter; std::unique_ptr video_encoder; + std::unique_ptr timecode_renderer; + std::atomic display_timecode_in_stream{false}; + std::atomic display_timecode_on_stdout{false}; + // Effects part of . Owned by . - movit::FlatInput *display_input; + movit::YCbCrInput *display_input; int64_t pts_int = 0; // In TIMEBASE units. + unsigned frame_num = 0; // Accumulated errors in number of 1/TIMEBASE audio samples. If OUTPUT_FREQUENCY divided by // frame rate is integer, will always stay zero. @@ -399,7 +425,7 @@ private: unsigned dropped_frames = 0; // Number of dropped frames before this one. std::chrono::steady_clock::time_point received_timestamp = std::chrono::steady_clock::time_point::min(); }; - std::queue new_frames; + std::deque new_frames; bool should_quit = false; std::condition_variable new_frames_changed; // Set whenever new_frames (or should_quit) is changed.