#include #include #include #include #include #include "NodeBase.hpp" #include "ST2110Receiver.hpp" #include "V210.hpp" namespace dmf { class ST2110In : public NodeBase { void run() override { ST2110ReceiverConfig cfg; try { cfg = parse_st2110_receiver_config(config()); } catch (const std::exception& e) { log("config error: %s", e.what()); return; } log("SMPTE 2110-20 RX %s:%u from %s on %s local=%s %dx%d @ %d/%d", cfg.mcast_ip.c_str(), cfg.udp_port, cfg.source_ip.c_str(), cfg.ifname.c_str(), cfg.local_ip.c_str(), cfg.width, cfg.height, cfg.fps_num, cfg.fps_den); try { MTLContext mtl(cfg); ST20RxSession rx(mtl.get(), mtl.port_name(), cfg); MXLVideoWriter writer(instance(), cfg, node_id()); const mxlRational video_rate = {cfg.fps_num, cfg.fps_den}; const uint32_t video_stride = writer.config().discrete.sliceSizes[0]; const uint32_t uyvy_stride = static_cast(cfg.width * 2); uint64_t frames_written = 0; while (g_running.load(std::memory_order_relaxed)) { st_frame* frame = st20p_rx_get_frame(rx.get()); if (!frame) { continue; } if (!st_is_frame_complete(frame->status)) { st20p_rx_put_frame(rx.get(), frame); continue; } if (frame->fmt != ST_FRAME_FMT_UYVY) { log("unexpected MTL frame fmt=%d; expected UYVY", frame->fmt); st20p_rx_put_frame(rx.get(), frame); continue; } mxlGrainInfo grain{}; uint8_t* video_buf = nullptr; const uint64_t video_index = mxlGetCurrentIndex(&video_rate); mxlStatus st = mxlFlowWriterOpenGrain(writer.get(), video_index, &grain, &video_buf); if (st != MXL_STATUS_OK) { log("mxlFlowWriterOpenGrain failed (%s) index=%llu", mxl_status_str(st), static_cast(video_index)); st20p_rx_put_frame(rx.get(), frame); continue; } v210::UYVYtoV210(static_cast(frame->addr[0]), video_buf, cfg.width, cfg.height, uyvy_stride, video_stride); grain.flags = 0; grain.validSlices = grain.totalSlices; mxlFlowWriterCommitGrain(writer.get(), &grain); st20p_rx_put_frame(rx.get(), frame); frames_written++; if (frames_written % 100 == 0) { log("received %llu frames", static_cast(frames_written)); } } log("stopped after %llu frames", static_cast(frames_written)); } catch (const std::exception& e) { log("error: %s", e.what()); } } }; } // namespace dmf int main() { dmf::ST2110In node; return node.execute(); }