decklink-out: reuse frames via ScheduledFrameCompleted callback pool

This commit is contained in:
Johanness
2026-05-30 23:23:15 +03:00
parent 26febc41d6
commit bd1f060c73
2 changed files with 29 additions and 8 deletions
+24 -8
View File
@@ -202,7 +202,9 @@ bool DeckLinkOutNode::open_device() {
void DeckLinkOutNode::close_device() { void DeckLinkOutNode::close_device() {
if (output_) { if (output_) {
output_->StopScheduledPlayback(0, nullptr, time_scale_); if (playing_) {
output_->StopScheduledPlayback(0, nullptr, time_scale_);
}
output_->DisableVideoOutput(); output_->DisableVideoOutput();
output_->Release(); output_->Release();
output_ = nullptr; output_ = nullptr;
@@ -213,6 +215,13 @@ void DeckLinkOutNode::close_device() {
} }
playing_ = false; playing_ = false;
callback_.reset(); callback_.reset();
{
std::lock_guard<std::mutex> lock(frame_pool_mutex_);
for (auto* f : frame_pool_) {
f->Release();
}
frame_pool_.clear();
}
spdlog::info("DeckLink-out: device closed"); spdlog::info("DeckLink-out: device closed");
} }
@@ -229,14 +238,15 @@ void DeckLinkOutNode::schedule_frame(void* mxl_payload, long width, long height,
} }
IDeckLinkMutableVideoFrame* frame = nullptr; IDeckLinkMutableVideoFrame* frame = nullptr;
HRESULT hr = output_->CreateVideoFrame(width, height, out_row_bytes, output_format_, {
bmdFrameFlagDefault, &frame); std::unique_lock<std::mutex> lock(frame_pool_mutex_);
if (hr != S_OK || !frame) { if (frame_pool_cv_.wait_for(lock, std::chrono::milliseconds(100), [this] { return !frame_pool_.empty(); })) {
if (create_fail_count_ < 5) { frame = frame_pool_.back();
spdlog::error("DeckLink-out: CreateVideoFrame {}x{} row_bytes={} fmt=0x{:x} hr=0x{:08x}", frame_pool_.pop_back();
width, height, out_row_bytes, static_cast<uint32_t>(output_format_), static_cast<uint32_t>(hr));
create_fail_count_++;
} }
}
if (!frame) {
return; return;
} }
@@ -334,6 +344,12 @@ nlohmann::json DeckLinkOutNode::status() const {
HRESULT DeckLinkOutNode::OutputCallback::ScheduledFrameCompleted( HRESULT DeckLinkOutNode::OutputCallback::ScheduledFrameCompleted(
IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result) { IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result) {
if (completedFrame) {
completedFrame->AddRef();
std::lock_guard<std::mutex> lock(owner_.frame_pool_mutex_);
owner_.frame_pool_.push_back(static_cast<IDeckLinkMutableVideoFrame*>(completedFrame));
owner_.frame_pool_cv_.notify_one();
}
return S_OK; return S_OK;
} }
@@ -7,9 +7,11 @@
#include <DeckLinkAPI.h> #include <DeckLinkAPI.h>
#include <atomic> #include <atomic>
#include <condition_variable>
#include <mutex> #include <mutex>
#include <optional> #include <optional>
#include <thread> #include <thread>
#include <vector>
namespace dmf_node { namespace dmf_node {
@@ -81,6 +83,9 @@ private:
}; };
std::unique_ptr<OutputCallback> callback_; std::unique_ptr<OutputCallback> callback_;
std::vector<IDeckLinkMutableVideoFrame*> frame_pool_;
std::mutex frame_pool_mutex_;
std::condition_variable frame_pool_cv_;
IDeckLinkMutableVideoFrame* scheduled_frame_ = nullptr; IDeckLinkMutableVideoFrame* scheduled_frame_ = nullptr;
}; };