#include "passthrough_node.hpp" #include #include #include #include #include namespace dmf_node { void PassthroughNode::on_add_writer(const std::string& port_id, mxlFlowWriter writer) { if (port_id == "video_out") { writer_ = writer; spdlog::info("Passthrough: writer added on video_out"); } } void PassthroughNode::on_add_reader(const std::string& port_id, mxlFlowReader reader) { if (port_id == "video_in") { reader_ = reader; mxlFlowConfigInfo config{}; mxlFlowReaderGetConfigInfo(*reader_, &config); grain_rate_ = config.common.grainRate; auto now = mxlGetTime(); auto current_index = mxlTimestampToIndex(&grain_rate_, now); read_index_ = current_index - READ_DELAY_GRAINS; aligned_ = true; spdlog::info("Passthrough: reader added, grain_rate={}/{}, read_index={}, delay={} grains", grain_rate_.numerator, grain_rate_.denominator, read_index_, READ_DELAY_GRAINS); } } void PassthroughNode::on_remove_writer(const std::string& port_id) { if (port_id == "video_out") { writer_.reset(); spdlog::info("Passthrough: writer removed from video_out"); } } void PassthroughNode::on_remove_reader(const std::string& port_id) { if (port_id == "video_in") { reader_.reset(); spdlog::info("Passthrough: reader removed from video_in"); } } void PassthroughNode::process() { if (!reader_ || !writer_ || !aligned_) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); return; } auto deadline = mxlIndexToTimestamp(&grain_rate_, read_index_ + 1); mxlSleepUntil(deadline); mxlGrainInfo grain_info{}; uint8_t* payload = nullptr; auto status = mxlFlowReaderGetGrain(*reader_, read_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); read_index_ = current_index - READ_DELAY_GRAINS; if (grains_processed_ == 0) { spdlog::warn("Passthrough: realigned to index {}", read_index_); } } return; } mxlGrainInfo out_grain{}; uint8_t* out_payload = nullptr; status = mxlFlowWriterOpenGrain(*writer_, grain_info.index, &out_grain, &out_payload); if (status != MXL_STATUS_OK) { spdlog::warn("Passthrough: failed to open output grain at index {}: {}", grain_info.index, static_cast(status)); read_index_++; return; } auto copy_size = std::min(grain_info.grainSize, out_grain.grainSize); std::memcpy(out_payload, payload, copy_size); out_grain.validSlices = grain_info.validSlices; out_grain.flags = grain_info.flags; mxlFlowWriterCommitGrain(*writer_, &out_grain); read_index_++; grains_processed_++; if (grains_processed_ == 1) { spdlog::info("Passthrough: first grain processed, index={}", grain_info.index); } } nlohmann::json PassthroughNode::status() const { return { {"type", "passthrough"}, {"grains_processed", grains_processed_}, {"read_index", read_index_}, {"has_reader", reader_.has_value()}, {"has_writer", writer_.has_value()}, }; } } // namespace dmf_node