#pragma once #include #include #include #include #include #include #include #include namespace dmf_node { class DeckLinkOutNode : public Node { public: DeckLinkOutNode() = default; ~DeckLinkOutNode(); std::string type() const override { return "decklink-out"; } std::vector input_ports() const override { return {{"video_in", PortDirection::Input, MediaType::VideoV210}}; } std::vector output_ports() const override { return {}; } void configure(const nlohmann::json& params) override; void on_add_writer(const std::string& port_id, mxlFlowWriter writer) override {} void on_add_reader(const std::string& port_id, mxlFlowReader reader) override; void on_remove_writer(const std::string& port_id) override {} void on_remove_reader(const std::string& port_id) override; void process() override; nlohmann::json status() const override; private: bool open_device(); void close_device(); void schedule_frame(void* mxl_payload, long width, long height, long row_bytes); std::optional reader_; mxlRational grain_rate_{50, 1}; uint64_t read_index_ = 0; uint64_t grains_read_ = 0; int device_index_ = 0; BMDDisplayMode display_mode_ = bmdModeHD1080i50; IDeckLink* decklink_ = nullptr; IDeckLinkOutput* output_ = nullptr; BMDTimeValue frame_duration_ = 1000; BMDTimeScale time_scale_ = 50000; std::atomic playing_{false}; class OutputCallback : public IDeckLinkVideoOutputCallback { public: OutputCallback(DeckLinkOutNode& owner) : owner_(owner) {} HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**) override { return E_NOINTERFACE; } ULONG STDMETHODCALLTYPE AddRef() override { return 1; } ULONG STDMETHODCALLTYPE Release() override { return 1; } HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted( IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result) override; HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped() override; private: DeckLinkOutNode& owner_; }; std::unique_ptr callback_; IDeckLinkMutableVideoFrame* scheduled_frame_ = nullptr; }; } // namespace dmf_node