+ if (card_index < num_cards) {
+ // SRT inputs are more like regular inputs than FFmpeg inputs,
+ // so show them as such. (This allows the user to right-click
+ // to select a different input.)
+ return false;
+ }
- void configure_card(unsigned card_index, bmusb::CaptureInterface *capture, CardType card_type, DeckLinkOutput *output);
+ void configure_card(unsigned card_index, bmusb::CaptureInterface *capture, CardType card_type, DeckLinkOutput *output, bool override_ffmpeg_to_live = false);
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,
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,
void render_one_frame(int64_t duration);
void audio_thread_func();
void release_display_frame(DisplayFrame *frame);
void render_one_frame(int64_t duration);
void audio_thread_func();
void release_display_frame(DisplayFrame *frame);
double pts() { return double(pts_int) / TIMEBASE; }
void trim_queue(CaptureCard *card, size_t safe_queue_length);
std::pair<std::string, std::string> get_channels_json();
double pts() { return double(pts_int) / TIMEBASE; }
void trim_queue(CaptureCard *card, size_t safe_queue_length);
std::pair<std::string, std::string> get_channels_json();
std::function<void()> upload_func; // Needs to be called to actually upload the texture to OpenGL.
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::function<void()> upload_func; // Needs to be called to actually upload the texture to OpenGL.
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();
// Used for MJPEG encoding. (upload_func packs everything it needs
// into the functor, but would otherwise also use these.)
// Used for MJPEG encoding. (upload_func packs everything it needs
// into the functor, but would otherwise also use these.)
JitterHistory output_jitter_history;
CaptureCard cards[MAX_VIDEO_CARDS]; // Protected by <card_mutex>.
YCbCrInterpretation ycbcr_interpretation[MAX_VIDEO_CARDS]; // Protected by <card_mutex>.
JitterHistory output_jitter_history;
CaptureCard cards[MAX_VIDEO_CARDS]; // Protected by <card_mutex>.
YCbCrInterpretation ycbcr_interpretation[MAX_VIDEO_CARDS]; // Protected by <card_mutex>.
std::unique_ptr<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 {
std::unique_ptr<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 {
// Protected by its own mutex.
std::mutex hotplug_mutex;
std::vector<libusb_device *> hotplugged_cards;
// Protected by its own mutex.
std::mutex hotplug_mutex;
std::vector<libusb_device *> hotplugged_cards;