]> git.sesse.net Git - nageru/blobdiff - decklink_output.h
Release Nageru 1.7.2.
[nageru] / decklink_output.h
index 0aba5063839502ce77815a8af7c62ba5c138f816..44eb86dea9860e6480c4552aeaf352a5990bf979 100644 (file)
@@ -2,8 +2,10 @@
 #define _DECKLINK_OUTPUT_H 1
 
 #include <epoxy/gl.h>
+#include <movit/image_format.h>
 #include <stdint.h>
 #include <atomic>
+#include <chrono>
 #include <condition_variable>
 #include <memory>
 #include <mutex>
@@ -17,6 +19,7 @@
 
 #include "context.h"
 #include "print_latency.h"
+#include "quittable_sleeper.h"
 #include "ref_counted_frame.h"
 #include "ref_counted_gl_sync.h"
 
@@ -35,17 +38,32 @@ class DeckLinkOutput : public IDeckLinkVideoOutputCallback {
 public:
        DeckLinkOutput(movit::ResourcePool *resource_pool, QSurface *surface, unsigned width, unsigned height, unsigned card_index);
 
-       void set_device(IDeckLink *output);
+       bool set_device(IDeckLink *output);
        void start_output(uint32_t mode, int64_t base_pts);  // Mode comes from get_available_video_modes().
        void end_output();
 
-       void send_frame(GLuint y_tex, GLuint cbcr_tex, const std::vector<RefCountedFrame> &input_frames, int64_t pts, int64_t duration);
+       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);
        void send_audio(int64_t pts, const std::vector<float> &samples);
-       void wait_for_frame(int64_t pts, int *dropped_frames, int64_t *frame_duration);
+
+       // NOTE: The returned timestamp is undefined for preroll.
+       // Otherwise, it is the timestamp of the output frame as it should have been,
+       // even if we're overshooting. E.g. at 50 fps (0.02 spf), assuming the
+       // last frame was at t=0.980:
+       //
+       //   If we're at t=0.999, we wait until t=1.000 and return that.
+       //   If we're at t=1.001, we return t=1.000 immediately (small overshoot).
+       //   If we're at t=1.055, we drop two frames and return t=1.040 immediately.
+       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);
 
        // Analogous to CaptureInterface. Will only return modes that have the right width/height.
        std::map<uint32_t, bmusb::VideoMode> get_available_video_modes() const { return video_modes; }
 
+       // If the given mode is supported, return it. If not, pick some “best” valid mode.
+       uint32_t pick_video_mode(uint32_t mode) const;
+
+       // Desired Y'CbCr coefficients for the current mode. Undefined before start_output().
+       movit::YCbCrLumaCoefficients preferred_ycbcr_coefficients() const;
+
        // IUnknown.
        HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) override;
        ULONG STDMETHODCALLTYPE AddRef() override;
@@ -85,7 +103,7 @@ private:
                movit::ResourcePool *resource_pool;
 
                // These members are persistently allocated, and reused when the frame object is.
-               GLuint uyvy_tex;  // Owned by <resource_pool>.
+               GLuint uyvy_tex;  // Owned by <resource_pool>. Can also hold v210 data.
                GLuint pbo;
                uint8_t *uyvy_ptr;  // Persistent mapping into the PBO.
 
@@ -110,18 +128,21 @@ private:
        std::map<uint32_t, bmusb::VideoMode> video_modes;
 
        std::thread present_thread;
-       std::atomic<bool> should_quit{false};
+       QuittableSleeper should_quit;
 
        std::mutex frame_queue_mutex;
        std::queue<std::unique_ptr<Frame>> pending_video_frames;  // Under <frame_queue_mutex>.
        std::queue<std::unique_ptr<Frame>> frame_freelist;  // Under <frame_queue_mutex>.
        int num_frames_in_flight = 0;  // Number of frames allocated but not on the freelist. Under <frame_queue_mutex>.
        std::condition_variable frame_queues_changed;
-       bool playback_started = false;
+       bool playback_initiated = false, playback_started = false;
        int64_t base_pts, frame_duration;
+       BMDDisplayModeFlags current_mode_flags = 0;
+       bool last_frame_had_mode_mismatch = false;
 
        movit::ResourcePool *resource_pool;
        IDeckLinkOutput *output = nullptr;
+       BMDVideoConnection video_connection;
        QSurface *surface;
        unsigned width, height;
        unsigned card_index;