feat(input): add real and dummy FrameSource backends

This commit is contained in:
2026-03-06 08:50:15 +08:00
parent 529de17eea
commit 3e1ee23e42
6 changed files with 584 additions and 16 deletions
+61 -6
View File
@@ -1,12 +1,12 @@
#include "cvmmap_streamer/config/runtime_config.hpp"
#include "cvmmap_streamer/ipc/contracts.hpp"
#include "cvmmap_streamer/metrics/latency_tracker.hpp"
#include "cvmmap_streamer/protocol/rtmp_publisher.hpp"
#include "cvmmap_streamer/protocol/rtp_publisher.hpp"
#include "include/app/cvmmap/cvmmap_client.hpp"
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <exception>
#include <expected>
#include <span>
#include <string>
@@ -22,6 +22,10 @@
#if __has_include(<gst/app/gstappsink.h>) && __has_include(<gst/app/gstappsrc.h>) && __has_include(<gst/gst.h>)
#define CVMMAP_STREAMER_HAS_GSTREAMER 1
#include "cvmmap_streamer/core/frame_source.hpp"
#include "cvmmap_streamer/metrics/latency_tracker.hpp"
#include "cvmmap_streamer/protocol/rtmp_publisher.hpp"
#include "cvmmap_streamer/protocol/rtp_publisher.hpp"
#include <array>
#include <chrono>
#include <mutex>
@@ -47,6 +51,37 @@ namespace {
namespace ipc = cvmmap_streamer::ipc;
struct ResolvedInputEndpoints {
std::string shm_name;
std::string zmq_endpoint;
};
[[nodiscard]]
std::expected<ResolvedInputEndpoints, std::string> resolve_input_endpoints(const RuntimeConfig &config) {
ResolvedInputEndpoints resolved{
.shm_name = config.input.shm_name,
.zmq_endpoint = config.input.zmq_endpoint,
};
if (config.input_mode != InputMode::Real || !config.input.shm_name.starts_with("cvmmap://")) {
return resolved;
}
try {
auto target = app::cvmmap::resolve_cvmmap_target_or_throw(config.input.shm_name);
resolved.shm_name = target.shm_name;
resolved.zmq_endpoint = target.zmq_addr;
spdlog::info(
"pipeline real-input URI resolved: shm_name='{}' zmq_endpoint='{}'",
resolved.shm_name,
resolved.zmq_endpoint);
} catch (const std::exception &e) {
return std::unexpected(std::string("invalid cvmmap uri in --shm-name: ") + e.what());
}
return resolved;
}
struct SharedMemoryView {
SharedMemoryView() = default;
@@ -695,11 +730,31 @@ int run_nvenc_pipeline(const RuntimeConfig &config) {
"GStreamer development/runtime libraries are unavailable; NVENC pipeline core requires gstreamer-1.0, gstreamer-app-1.0, and gstreamer-video-1.0");
return 5;
#else
auto input_endpoints = resolve_input_endpoints(config);
if (!input_endpoints) {
spdlog::error("{}", input_endpoints.error());
return 2;
}
auto source = make_frame_source(config);
if (!source) {
spdlog::error("pipeline input source selection failed: {}", source.error());
return 2;
}
auto source_prepare = (*source)->prepare_runtime();
if (!source_prepare) {
spdlog::error("pipeline source backend '{}' setup failed: {}", (*source)->backend_name(), source_prepare.error());
return 2;
}
spdlog::info("pipeline source backend selected: {}", (*source)->backend_name());
GStreamerPipeline pipeline;
pipeline.configured_codec = config.codec;
ensure_gst_initialized();
auto shm = SharedMemoryView::open_readonly(config.input.shm_name);
auto shm = SharedMemoryView::open_readonly(input_endpoints->shm_name);
if (!shm) {
spdlog::error("pipeline open shared memory failed: {}", shm.error());
return 3;
@@ -719,9 +774,9 @@ int run_nvenc_pipeline(const RuntimeConfig &config) {
try {
subscriber.set(zmq::sockopt::subscribe, "");
subscriber.set(zmq::sockopt::rcvtimeo, 20);
subscriber.connect(config.input.zmq_endpoint);
subscriber.connect(input_endpoints->zmq_endpoint);
} catch (const zmq::error_t &e) {
spdlog::error("pipeline subscribe failed on '{}': {}", config.input.zmq_endpoint, e.what());
spdlog::error("pipeline subscribe failed on '{}': {}", input_endpoints->zmq_endpoint, e.what());
return 4;
}