From 26febc41d6dded0baa3bb98bae00410c3eda6f4a Mon Sep 17 00:00:00 2001 From: Johanness Date: Sat, 30 May 2026 23:21:13 +0300 Subject: [PATCH] decklink-out: preroll frames before StartScheduledPlayback, detect output format --- nodes/decklink-out/src/decklink_out_node.cpp | 66 +++++++++++++------- nodes/decklink-out/src/decklink_out_node.hpp | 2 + 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/nodes/decklink-out/src/decklink_out_node.cpp b/nodes/decklink-out/src/decklink_out_node.cpp index 1374256..4ff620a 100644 --- a/nodes/decklink-out/src/decklink_out_node.cpp +++ b/nodes/decklink-out/src/decklink_out_node.cpp @@ -126,20 +126,6 @@ bool DeckLinkOutNode::open_device() { callback_ = std::make_unique(*this); output_->SetScheduledFrameCompletionCallback(callback_.get()); - { - BMDDisplayMode actual_mode = bmdModeUnknown; - bool supported = false; - auto hr = output_->DoesSupportVideoMode(bmdVideoConnectionUnspecified, display_mode_, bmdFormat10BitYUV, - bmdNoVideoOutputConversion, bmdSupportedVideoModeDefault, &actual_mode, &supported); - if (hr == S_OK) { - spdlog::info("DeckLink-out: mode 0x{:x} V210 supported={} actual=0x{:x}", - static_cast(display_mode_), supported, static_cast(actual_mode)); - if (!supported) { - spdlog::error("DeckLink-out: display mode not supported for V210 output"); - } - } - } - if (output_->EnableVideoOutput(display_mode_, bmdVideoOutputFlagDefault) != S_OK) { spdlog::error("DeckLink-out: failed to enable video output"); return false; @@ -171,6 +157,39 @@ bool DeckLinkOutNode::open_device() { is_interlaced_); } + preroll_frames_ = 3; + for (int i = 0; i < preroll_frames_; ++i) { + IDeckLinkMutableVideoFrame* frame = nullptr; + int32_t out_row_bytes = out_width_ * 16 / 6; + if (output_->CreateVideoFrame(out_width_, out_height_, out_row_bytes, + bmdFormat10BitYUV, bmdFrameFlagDefault, &frame) != S_OK || !frame) { + out_row_bytes = out_width_ * 2; + if (output_->CreateVideoFrame(out_width_, out_height_, out_row_bytes, + bmdFormat8BitYUV, bmdFrameFlagDefault, &frame) != S_OK || !frame) { + spdlog::error("DeckLink-out: failed to create preroll frame"); + return false; + } + spdlog::info("DeckLink-out: using 8BitYUV output format"); + output_format_ = bmdFormat8BitYUV; + } else { + output_format_ = bmdFormat10BitYUV; + } + IDeckLinkVideoBuffer* buf = nullptr; + if (frame->QueryInterface(IID_IDeckLinkVideoBuffer, (void**)&buf) == S_OK && buf) { + buf->StartAccess(bmdBufferAccessWrite); + void* dst = nullptr; + buf->GetBytes(&dst); + if (dst) { + std::memset(dst, 0, out_row_bytes * out_height_); + } + buf->EndAccess(bmdBufferAccessWrite); + buf->Release(); + } + auto stream_time = i * frame_duration_; + output_->ScheduleVideoFrame(frame, stream_time, frame_duration_, time_scale_); + frame->Release(); + } + if (output_->StartScheduledPlayback(0, time_scale_, 1.0) != S_OK) { spdlog::error("DeckLink-out: failed to start scheduled playback"); return false; @@ -201,24 +220,23 @@ void DeckLinkOutNode::schedule_frame(void* mxl_payload, long width, long height, if (!output_) return; int32_t out_row_bytes = 0; - HRESULT row_hr = output_->RowBytesForPixelFormat(bmdFormat10BitYUV, width, &out_row_bytes); - if (row_hr != S_OK || out_row_bytes <= 0) { - spdlog::warn("DeckLink-out: RowBytesForPixelFormat failed hr=0x{:08x}", static_cast(row_hr)); - out_row_bytes = ((width + 5) / 6) * 16; + if (output_format_ == bmdFormat10BitYUV) { + if (output_->RowBytesForPixelFormat(bmdFormat10BitYUV, width, &out_row_bytes) != S_OK || out_row_bytes <= 0) { + out_row_bytes = ((width + 5) / 6) * 16; + } + } else { + out_row_bytes = width * 2; } IDeckLinkMutableVideoFrame* frame = nullptr; - HRESULT hr = output_->CreateVideoFrame(width, height, out_row_bytes, bmdFormat10BitYUV, + HRESULT hr = output_->CreateVideoFrame(width, height, out_row_bytes, output_format_, bmdFrameFlagDefault, &frame); if (hr != S_OK || !frame) { if (create_fail_count_ < 5) { - spdlog::error("DeckLink-out: CreateVideoFrame {}x{} row_bytes={} fmt=V210 hr=0x{:08x}", - width, height, out_row_bytes, static_cast(hr)); + spdlog::error("DeckLink-out: CreateVideoFrame {}x{} row_bytes={} fmt=0x{:x} hr=0x{:08x}", + width, height, out_row_bytes, static_cast(output_format_), static_cast(hr)); create_fail_count_++; } - if (create_fail_count_ == 5) { - spdlog::error("DeckLink-out: suppressing further CreateVideoFrame errors"); - } return; } diff --git a/nodes/decklink-out/src/decklink_out_node.hpp b/nodes/decklink-out/src/decklink_out_node.hpp index 4a369db..b08b675 100644 --- a/nodes/decklink-out/src/decklink_out_node.hpp +++ b/nodes/decklink-out/src/decklink_out_node.hpp @@ -55,6 +55,8 @@ private: IDeckLinkOutput* output_ = nullptr; BMDTimeValue frame_duration_ = 1000; BMDTimeScale time_scale_ = 50000; + BMDPixelFormat output_format_ = bmdFormat10BitYUV; + int preroll_frames_ = 3; std::atomic playing_{false}; int create_fail_count_ = 0;