1 #ifndef _DECKLINK_OUTPUT_H
2 #define _DECKLINK_OUTPUT_H 1
7 #include <condition_variable>
14 #include "DeckLinkAPI.h"
15 #include "DeckLinkAPITypes.h"
19 #include "print_latency.h"
20 #include "ref_counted_frame.h"
21 #include "ref_counted_gl_sync.h"
29 class ChromaSubsampler;
31 class IDeckLinkOutput;
34 class DeckLinkOutput : public IDeckLinkVideoOutputCallback {
36 DeckLinkOutput(movit::ResourcePool *resource_pool, QSurface *surface, unsigned width, unsigned height, unsigned card_index);
38 void set_device(IDeckLink *output);
39 void start_output(uint32_t mode, int64_t base_pts); // Mode comes from get_available_video_modes().
42 void send_frame(GLuint y_tex, GLuint cbcr_tex, const std::vector<RefCountedFrame> &input_frames, int64_t pts, int64_t duration);
43 void send_audio(int64_t pts, const std::vector<float> &samples);
44 void wait_for_frame(int64_t pts, int *dropped_frames, int64_t *frame_duration);
46 // Analogous to CaptureInterface. Will only return modes that have the right width/height.
47 std::map<uint32_t, bmusb::VideoMode> get_available_video_modes() const { return video_modes; }
50 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) override;
51 ULONG STDMETHODCALLTYPE AddRef() override;
52 ULONG STDMETHODCALLTYPE Release() override;
54 // IDeckLinkVideoOutputCallback.
55 HRESULT ScheduledFrameCompleted(/* in */ IDeckLinkVideoFrame *completedFrame, /* in */ BMDOutputFrameCompletionResult result) override;
56 HRESULT ScheduledPlaybackHasStopped() override;
59 struct Frame : public IDeckLinkVideoFrame {
64 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) override;
65 ULONG STDMETHODCALLTYPE AddRef() override;
66 ULONG STDMETHODCALLTYPE Release() override;
68 // IDeckLinkVideoFrame.
69 long GetWidth() override;
70 long GetHeight() override;
71 long GetRowBytes() override;
72 BMDPixelFormat GetPixelFormat() override;
73 BMDFrameFlags GetFlags() override;
74 HRESULT GetBytes(/* out */ void **buffer) override;
76 HRESULT GetTimecode(/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode **timecode) override;
77 HRESULT GetAncillaryData(/* out */ IDeckLinkVideoFrameAncillary **ancillary) override;
80 std::atomic<int> refcount{1};
81 RefCountedGLsync fence; // Needs to be waited on before uyvy_ptr can be read from.
82 std::vector<RefCountedFrame> input_frames; // Cannot be released before we are done rendering (ie., <fence> is asserted).
83 ReceivedTimestamps received_ts;
84 int64_t pts, duration;
85 movit::ResourcePool *resource_pool;
87 // These members are persistently allocated, and reused when the frame object is.
88 GLuint uyvy_tex; // Owned by <resource_pool>.
90 uint8_t *uyvy_ptr; // Persistent mapping into the PBO.
92 // Current Blackmagic drivers (January 2017) have a bug where sending a PBO
93 // pointer to the driver causes a kernel oops. Thus, we do an extra copy into
94 // this pointer before giving the data to the driver. (We don't do a get
95 // directly into this pointer, because e.g. Intel/Mesa hits a slow path when
96 // you do readback into something that's not a PBO.) When Blackmagic fixes
97 // the bug, we should drop this.
98 std::unique_ptr<uint8_t[]> uyvy_ptr_local;
100 friend class DeckLinkOutput;
102 std::unique_ptr<Frame> get_frame();
103 void create_uyvy(GLuint y_tex, GLuint cbcr_tex, GLuint dst_tex);
105 void present_thread_func();
107 std::atomic<int> refcount{1};
109 std::unique_ptr<ChromaSubsampler> chroma_subsampler;
110 std::map<uint32_t, bmusb::VideoMode> video_modes;
112 std::thread present_thread;
113 std::atomic<bool> should_quit{false};
115 std::mutex frame_queue_mutex;
116 std::queue<std::unique_ptr<Frame>> pending_video_frames; // Under <frame_queue_mutex>.
117 std::queue<std::unique_ptr<Frame>> frame_freelist; // Under <frame_queue_mutex>.
118 int num_frames_in_flight = 0; // Number of frames allocated but not on the freelist. Under <frame_queue_mutex>.
119 std::condition_variable frame_queues_changed;
120 bool playback_started = false;
121 int64_t base_pts, frame_duration;
123 movit::ResourcePool *resource_pool;
124 IDeckLinkOutput *output = nullptr;
125 BMDVideoConnection video_connection;
127 unsigned width, height;
130 GLuint uyvy_vbo; // Holds position and texcoord data.
131 GLuint uyvy_program_num; // Owned by <resource_pool>.
132 GLuint uyvy_position_attribute_index, uyvy_texcoord_attribute_index;
135 #endif // !defined(_DECKLINK_OUTPUT_H)