From 003279669e86ecb58670decc8a49b1a7b74d635d Mon Sep 17 00:00:00 2001 From: Johanness Date: Sat, 30 May 2026 23:07:15 +0300 Subject: [PATCH] fix output res&frame rate --- nodes/decklink-out/src/decklink_out_node.cpp | 53 +++++++++++++------- nodes/decklink-out/src/decklink_out_node.hpp | 6 ++- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/nodes/decklink-out/src/decklink_out_node.cpp b/nodes/decklink-out/src/decklink_out_node.cpp index a437666..4278194 100644 --- a/nodes/decklink-out/src/decklink_out_node.cpp +++ b/nodes/decklink-out/src/decklink_out_node.cpp @@ -54,13 +54,13 @@ void DeckLinkOutNode::on_add_reader(const std::string& port_id, mxlFlowReader re mxlFlowConfigInfo config{}; mxlFlowReaderGetConfigInfo(*reader_, &config); - grain_rate_ = config.common.grainRate; + flow_rate_ = config.common.grainRate; auto now = mxlGetTime(); - auto current_index = mxlTimestampToIndex(&grain_rate_, now); + auto current_index = mxlTimestampToIndex(&flow_rate_, now); read_index_ = current_index - 2; - spdlog::info("DeckLink-out: reader added, grain_rate={}/{}", grain_rate_.numerator, grain_rate_.denominator); + spdlog::info("DeckLink-out: reader added, flow_rate={}/{}", flow_rate_.numerator, flow_rate_.denominator); if (!open_device()) { spdlog::error("DeckLink-out: failed to open device"); @@ -133,12 +133,28 @@ bool DeckLinkOutNode::open_device() { IDeckLinkDisplayMode* mode = nullptr; if (output_->GetDisplayMode(display_mode_, &mode) == S_OK) { + out_width_ = mode->GetWidth(); + out_height_ = mode->GetHeight(); BMDTimeValue duration = 0; BMDTimeScale scale = 0; mode->GetFrameRate(&duration, &scale); frame_duration_ = duration; time_scale_ = scale; mode->Release(); + + output_rate_.numerator = static_cast(scale); + output_rate_.denominator = static_cast(duration); + auto g = std::__gcd(output_rate_.numerator, output_rate_.denominator); + output_rate_.numerator /= g; + output_rate_.denominator /= g; + + is_interlaced_ = (display_mode_ == bmdModeHD1080i50 || + display_mode_ == bmdModeHD1080i5994); + + spdlog::info("DeckLink-out: {}x{} @ {}/{} fps, interlaced={}", + out_width_, out_height_, + output_rate_.numerator, output_rate_.denominator, + is_interlaced_); } if (output_->StartScheduledPlayback(0, time_scale_, 1.0) != S_OK) { @@ -210,19 +226,22 @@ void DeckLinkOutNode::process() { return; } - auto deadline = mxlIndexToTimestamp(&grain_rate_, read_index_ + 1); + auto deadline = mxlIndexToTimestamp(&output_rate_, grains_read_ + 1); mxlSleepUntil(deadline); + auto out_timestamp = mxlIndexToTimestamp(&output_rate_, grains_read_); + auto source_index = mxlTimestampToIndex(&flow_rate_, out_timestamp); + mxlGrainInfo grain_info{}; uint8_t* payload = nullptr; - auto status = mxlFlowReaderGetGrain(*reader_, read_index_, 5000000ULL, &grain_info, &payload); + auto status = mxlFlowReaderGetGrain(*reader_, source_index, 5000000ULL, &grain_info, &payload); if (status != MXL_STATUS_OK) { if (status == MXL_ERR_OUT_OF_RANGE_TOO_LATE || status == MXL_ERR_OUT_OF_RANGE_TOO_EARLY) { auto now = mxlGetTime(); - auto current_index = mxlTimestampToIndex(&grain_rate_, now); + auto current_index = mxlTimestampToIndex(&flow_rate_, now); read_index_ = current_index - 2; if (grains_read_ == 0) { - spdlog::warn("DeckLink-out: realigned to index {}", read_index_); + spdlog::warn("DeckLink-out: realigned to source index {}", read_index_); } } return; @@ -232,20 +251,17 @@ void DeckLinkOutNode::process() { mxlFlowReaderGetConfigInfo(*reader_, &config); auto grain_size = grain_info.grainSize; - long height = 1080; - if (config.discrete.sliceSizes[0] > 0) { - height = grain_size / config.discrete.sliceSizes[0]; - } - long row_bytes = (config.discrete.sliceSizes[0] > 0) ? static_cast(config.discrete.sliceSizes[0]) : (grain_size / height); - long width = (row_bytes * 3) / 8; + long src_row_bytes = (config.discrete.sliceSizes[0] > 0) ? static_cast(config.discrete.sliceSizes[0]) : (grain_size / out_height_); + long src_height = (src_row_bytes > 0) ? (grain_size / src_row_bytes) : out_height_; + long src_width = (src_row_bytes * 3) / 8; - schedule_frame(payload, width, height, row_bytes); + schedule_frame(payload, src_width, src_height, src_row_bytes); - read_index_ = grain_info.index + 1; + read_index_ = source_index + 1; grains_read_++; if (grains_read_ == 1) { - spdlog::info("DeckLink-out: first grain output, index={}", grain_info.index); + spdlog::info("DeckLink-out: first grain output, source_index={}", source_index); } } @@ -256,7 +272,10 @@ nlohmann::json DeckLinkOutNode::status() const { {"read_index", read_index_}, {"playing", playing_.load()}, {"has_reader", reader_.has_value()}, - {"grain_rate", {{"numerator", grain_rate_.numerator}, {"denominator", grain_rate_.denominator}}}, + {"flow_rate", {{"numerator", flow_rate_.numerator}, {"denominator", flow_rate_.denominator}}}, + {"output_rate", {{"numerator", output_rate_.numerator}, {"denominator", output_rate_.denominator}}}, + {"width", out_width_}, + {"height", out_height_}, }; } diff --git a/nodes/decklink-out/src/decklink_out_node.hpp b/nodes/decklink-out/src/decklink_out_node.hpp index 5807088..ea0ec26 100644 --- a/nodes/decklink-out/src/decklink_out_node.hpp +++ b/nodes/decklink-out/src/decklink_out_node.hpp @@ -41,7 +41,8 @@ private: void schedule_frame(void* mxl_payload, long width, long height, long row_bytes); std::optional reader_; - mxlRational grain_rate_{50, 1}; + mxlRational flow_rate_{50, 1}; + mxlRational output_rate_{50, 1}; uint64_t read_index_ = 0; uint64_t grains_read_ = 0; @@ -55,6 +56,9 @@ private: BMDTimeScale time_scale_ = 50000; std::atomic playing_{false}; + bool is_interlaced_ = false; + long out_width_ = 1920; + long out_height_ = 1080; class OutputCallback : public IDeckLinkVideoOutputCallback { public: