Feature/ndi out node #1

Merged
itten merged 15 commits from feature/ndi-out-node into main 2026-07-01 18:22:26 +03:00
Showing only changes of commit aa39a821db - Show all commits
+20 -17
View File
@@ -1,4 +1,3 @@
#include <algorithm>
#include <cstring> #include <cstring>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -75,7 +74,8 @@ class NDIInNode : public dmf::NodeBase {
log("audio mxlCreateFlowWriter failed (status=%d) — continuing without audio", ast); log("audio mxlCreateFlowWriter failed (status=%d) — continuing without audio", ast);
has_audio = false; has_audio = false;
} else { } else {
log("audio grain=%u B", audio_cfg.discrete.sliceSizes[0]); log("audio channels=%u buffer=%u samples",
audio_cfg.continuous.channelCount, audio_cfg.continuous.bufferLength);
} }
} }
@@ -104,22 +104,25 @@ class NDIInNode : public dmf::NodeBase {
if (kind == dmf::NDIReceiver::FrameKind::Video) { if (kind == dmf::NDIReceiver::FrameKind::Video) {
have_video = true; have_video = true;
} else if (kind == dmf::NDIReceiver::FrameKind::Audio && has_audio) { } else if (kind == dmf::NDIReceiver::FrameKind::Audio && has_audio) {
mxlGrainInfo grain{}; mxlMutableWrappedMultiBufferSlice slice{};
uint8_t* buf = nullptr; if (mxlFlowWriterOpenSamples(audio_writer, audio_index,
if (mxlFlowWriterOpenGrain(audio_writer, audio_index, &grain, &buf) == MXL_STATUS_OK) { static_cast<size_t>(audio_info.samples), &slice) == MXL_STATUS_OK) {
// Convert float32 planar → int32 interleaved PCM // MXL audio is float32 planar: each channel occupies its own ring buffer
const int audio_grain_size = audio_cfg.discrete.sliceSizes[0]; // region, accessed at base + c * stride. Fragments handle ring wraparound.
const int capacity = audio_grain_size / (channels * static_cast<int>(sizeof(int32_t))); const size_t frag0 = slice.base.fragments[0].size / sizeof(float);
const int to_write = std::min(audio_info.samples, capacity); const size_t frag1 = slice.base.fragments[1].size / sizeof(float);
auto* out = reinterpret_cast<int32_t*>(buf); for (int c = 0; c < audio_info.channels; ++c) {
for (int s = 0; s < to_write; ++s) const float* src = &audio_buf[c * audio_info.channel_stride];
for (int c = 0; c < audio_info.channels; ++c) { auto* dst0 = reinterpret_cast<float*>(
float f = audio_buf[c * audio_info.channel_stride + s]; static_cast<uint8_t*>(slice.base.fragments[0].pointer) + c * slice.stride);
f = std::max(-1.0f, std::min(1.0f, f)); std::memcpy(dst0, src, frag0 * sizeof(float));
*out++ = static_cast<int32_t>(f * 2147483647.0f); if (frag1 > 0) {
auto* dst1 = reinterpret_cast<float*>(
static_cast<uint8_t*>(slice.base.fragments[1].pointer) + c * slice.stride);
std::memcpy(dst1, src + frag0, frag1 * sizeof(float));
} }
grain.validSlices = grain.totalSlices; }
mxlFlowWriterCommitGrain(audio_writer, &grain); mxlFlowWriterCommitSamples(audio_writer);
} }
audio_index += audio_info.samples; audio_index += audio_info.samples;
} }