fix ndi->decklinkout slowdown
This commit is contained in:
@@ -114,8 +114,9 @@ class DeckLinkOutNode : public dmf::NodeBase {
|
|||||||
uint64_t frame_count = 0;
|
uint64_t frame_count = 0;
|
||||||
uint64_t invalid_count = 0;
|
uint64_t invalid_count = 0;
|
||||||
uint64_t late_count = 0;
|
uint64_t late_count = 0;
|
||||||
auto wall_start = std::chrono::steady_clock::now();
|
std::chrono::steady_clock::time_point wall_start;
|
||||||
auto last_log_time = wall_start;
|
bool timing_started = false;
|
||||||
|
auto last_log_time = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
// --- Main loop ---
|
// --- Main loop ---
|
||||||
while (dmf::g_running.load(std::memory_order_relaxed)) {
|
while (dmf::g_running.load(std::memory_order_relaxed)) {
|
||||||
@@ -169,6 +170,11 @@ class DeckLinkOutNode : public dmf::NodeBase {
|
|||||||
video_reader, video_index, &video_grain, &video_buf);
|
video_reader, video_index, &video_grain, &video_buf);
|
||||||
|
|
||||||
if (vst == MXL_STATUS_OK) {
|
if (vst == MXL_STATUS_OK) {
|
||||||
|
if (!timing_started) {
|
||||||
|
wall_start = std::chrono::steady_clock::now();
|
||||||
|
last_log_time = wall_start;
|
||||||
|
timing_started = true;
|
||||||
|
}
|
||||||
if (video_grain.flags & MXL_GRAIN_FLAG_INVALID) invalid_count++;
|
if (video_grain.flags & MXL_GRAIN_FLAG_INVALID) invalid_count++;
|
||||||
sender.submit_frame(video_buf, video_stride);
|
sender.submit_frame(video_buf, video_stride);
|
||||||
frame_count++;
|
frame_count++;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <chrono>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -96,19 +97,23 @@ class NDIInNode : public dmf::NodeBase {
|
|||||||
dmf::NDIReceiver::AudioInfo audio_info;
|
dmf::NDIReceiver::AudioInfo audio_info;
|
||||||
|
|
||||||
while (dmf::g_running.load(std::memory_order_relaxed)) {
|
while (dmf::g_running.load(std::memory_order_relaxed)) {
|
||||||
// Drain all queued NDI frames before writing one MXL grain.
|
// Drain available NDI frames before writing one MXL grain.
|
||||||
// With audio enabled, many audio packets may be queued ahead of a video frame.
|
// With audio enabled, many audio packets may be queued ahead of a video frame.
|
||||||
// Calling capture() once per grain window would starve video reception.
|
// Budget: drain for at most half a frame period so the grain clock stays on time
|
||||||
// Strategy: blocking first call (5ms), then non-blocking drain of remainder.
|
// even when catching up from a startup audio backlog.
|
||||||
try {
|
try {
|
||||||
|
const auto drain_deadline =
|
||||||
|
std::chrono::steady_clock::now() + std::chrono::milliseconds(20);
|
||||||
bool first = true;
|
bool first = true;
|
||||||
while (dmf::g_running.load(std::memory_order_relaxed)) {
|
while (dmf::g_running.load(std::memory_order_relaxed) &&
|
||||||
|
std::chrono::steady_clock::now() < drain_deadline) {
|
||||||
auto kind = ndi.capture(latest_video.data(), video_stride,
|
auto kind = ndi.capture(latest_video.data(), video_stride,
|
||||||
audio_buf, audio_info, has_audio,
|
audio_buf, audio_info, has_audio,
|
||||||
first ? 5 : 0);
|
first ? 5 : 0);
|
||||||
first = false;
|
first = false;
|
||||||
if (kind == dmf::NDIReceiver::FrameKind::Video) {
|
if (kind == dmf::NDIReceiver::FrameKind::Video) {
|
||||||
have_video = true;
|
have_video = true;
|
||||||
|
break; // got video — write grain now, remaining audio deferred to next window
|
||||||
} else if (kind == dmf::NDIReceiver::FrameKind::Audio && has_audio) {
|
} else if (kind == dmf::NDIReceiver::FrameKind::Audio && has_audio) {
|
||||||
mxlMutableWrappedMultiBufferSlice slice{};
|
mxlMutableWrappedMultiBufferSlice slice{};
|
||||||
if (mxlFlowWriterOpenSamples(audio_writer, audio_index,
|
if (mxlFlowWriterOpenSamples(audio_writer, audio_index,
|
||||||
|
|||||||
Reference in New Issue
Block a user