1 #ifndef _DECKLINK_OUTPUT_H
2 #define _DECKLINK_OUTPUT_H 1
5 #include <movit/image_format.h>
9 #include <condition_variable>
17 #include "DeckLinkAPI.h"
18 #include "DeckLinkAPITypes.h"
21 #include "shared/context.h"
22 #include "print_latency.h"
23 #include "queue_length_policy.h"
24 #include "quittable_sleeper.h"
25 #include "ref_counted_frame.h"
26 #include "shared/ref_counted_gl_sync.h"
34 class ChromaSubsampler;
36 class IDeckLinkOutput;
39 class DeckLinkOutput : public IDeckLinkVideoOutputCallback {
41 DeckLinkOutput(movit::ResourcePool *resource_pool, QSurface *surface, unsigned width, unsigned height, unsigned card_index);
43 bool set_device(IDeckLink *output);
44 void start_output(uint32_t mode, int64_t base_pts, bool is_master_card); // Mode comes from get_available_video_modes().
47 void send_frame(GLuint y_tex, GLuint cbcr_tex, movit::YCbCrLumaCoefficients ycbcr_coefficients, const std::vector<RefCountedFrame> &input_frames, int64_t pts, int64_t duration);
48 void send_audio(int64_t pts, const std::vector<float> &samples);
50 // Only makes sense if is_master_card is true.
52 // NOTE: The returned timestamp is undefined for preroll.
53 // Otherwise, it is the timestamp of the output frame as it should have been,
54 // even if we're overshooting. E.g. at 50 fps (0.02 spf), assuming the
55 // last frame was at t=0.980:
57 // If we're at t=0.999, we wait until t=1.000 and return that.
58 // If we're at t=1.001, we return t=1.000 immediately (small overshoot).
59 // If we're at t=1.055, we drop two frames and return t=1.040 immediately.
60 void wait_for_frame(int64_t pts, int *dropped_frames, int64_t *frame_duration, bool *is_preroll, std::chrono::steady_clock::time_point *frame_timestamp);
62 // Analogous to CaptureInterface. Will only return modes that have the right width/height.
63 std::map<uint32_t, bmusb::VideoMode> get_available_video_modes() const { return video_modes; }
65 // If the given mode is supported, return it. If not, pick some “best” valid mode.
66 uint32_t pick_video_mode(uint32_t mode) const;
68 // Desired Y'CbCr coefficients for the current mode. Undefined before start_output().
69 movit::YCbCrLumaCoefficients preferred_ycbcr_coefficients() const;
72 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) override;
73 ULONG STDMETHODCALLTYPE AddRef() override;
74 ULONG STDMETHODCALLTYPE Release() override;
76 // IDeckLinkVideoOutputCallback.
77 HRESULT ScheduledFrameCompleted(/* in */ IDeckLinkVideoFrame *completedFrame, /* in */ BMDOutputFrameCompletionResult result) override;
78 HRESULT ScheduledPlaybackHasStopped() override;
81 struct Frame : public IDeckLinkVideoFrame {
86 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) override;
87 ULONG STDMETHODCALLTYPE AddRef() override;
88 ULONG STDMETHODCALLTYPE Release() override;
90 // IDeckLinkVideoFrame.
91 long GetWidth() override;
92 long GetHeight() override;
93 long GetRowBytes() override;
94 BMDPixelFormat GetPixelFormat() override;
95 BMDFrameFlags GetFlags() override;
96 HRESULT GetBytes(/* out */ void **buffer) override;
98 HRESULT GetTimecode(/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode **timecode) override;
99 HRESULT GetAncillaryData(/* out */ IDeckLinkVideoFrameAncillary **ancillary) override;
102 std::atomic<int> refcount{1};
103 RefCountedGLsync fence; // Needs to be waited on before uyvy_ptr can be read from.
104 std::vector<RefCountedFrame> input_frames; // Cannot be released before we are done rendering (ie., <fence> is asserted).
105 ReceivedTimestamps received_ts;
106 int64_t pts, duration;
107 movit::ResourcePool *resource_pool;
109 // These members are persistently allocated, and reused when the frame object is.
110 GLuint uyvy_tex; // Owned by <resource_pool>. Can also hold v210 data.
112 uint8_t *uyvy_ptr; // Persistent mapping into the PBO.
114 // Current Blackmagic drivers (January 2017) have a bug where sending a PBO
115 // pointer to the driver causes a kernel oops. Thus, we do an extra copy into
116 // this pointer before giving the data to the driver. (We don't do a get
117 // directly into this pointer, because e.g. Intel/Mesa hits a slow path when
118 // you do readback into something that's not a PBO.) When Blackmagic fixes
119 // the bug, we should drop this.
120 std::unique_ptr<uint8_t[]> uyvy_ptr_local;
122 friend class DeckLinkOutput;
124 std::unique_ptr<Frame> get_frame();
125 void create_uyvy(GLuint y_tex, GLuint cbcr_tex, GLuint dst_tex);
127 void present_thread_func();
128 double PTSToTime(int64_t pts);
130 std::atomic<int> refcount{1};
132 std::unique_ptr<ChromaSubsampler> chroma_subsampler;
133 std::map<uint32_t, bmusb::VideoMode> video_modes;
135 std::thread present_thread;
136 QuittableSleeper should_quit;
138 std::mutex frame_queue_mutex; // Protects all members in this block.
139 std::queue<std::unique_ptr<Frame>> pending_video_frames;
140 std::queue<std::unique_ptr<Frame>> frame_freelist;
141 std::deque<Frame *> scheduled_frames; // Owned by the driver, so no unique_ptr.
142 unsigned num_safe_frames = 1;
143 int64_t next_output_pts = 0;
144 JitterHistory input_jitter_history, output_jitter_history;
145 QueueLengthPolicy queue_length_policy;
146 // End of variables protected by frame_queue_mutex.
148 std::condition_variable frame_queues_changed;
149 bool playback_initiated = false, playback_started = false;
150 int64_t base_pts, frame_duration;
151 BMDDisplayModeFlags current_mode_flags = 0;
152 bool last_frame_had_mode_mismatch = false;
154 movit::ResourcePool *resource_pool;
155 IDeckLinkInput *input = nullptr;
156 IDeckLinkOutput *output = nullptr;
157 BMDVideoConnection video_connection;
159 unsigned width, height;
162 GLuint uyvy_vbo; // Holds position and texcoord data.
163 GLuint uyvy_program_num; // Owned by <resource_pool>.
164 GLuint uyvy_position_attribute_index, uyvy_texcoord_attribute_index;
167 #endif // !defined(_DECKLINK_OUTPUT_H)