refactor(streamer): adopt proxy backends and typed statuses
This commit is contained in:
@@ -123,6 +123,20 @@ std::expected<RtmpMode, std::string> parse_rtmp_mode(std::string_view raw) {
|
||||
return std::unexpected("invalid rtmp mode: '" + std::string(raw) + "' (expected: enhanced|domestic)");
|
||||
}
|
||||
|
||||
std::expected<RtmpTransportType, std::string> parse_rtmp_transport(std::string_view raw) {
|
||||
if (raw == "libavformat") {
|
||||
return RtmpTransportType::Libavformat;
|
||||
}
|
||||
if (raw == "ffmpeg_process" || raw == "ffmpeg-process") {
|
||||
return RtmpTransportType::FfmpegProcess;
|
||||
}
|
||||
if (raw == "legacy_custom" || raw == "legacy-custom") {
|
||||
return RtmpTransportType::LegacyCustom;
|
||||
}
|
||||
return std::unexpected(
|
||||
"invalid rtmp transport: '" + std::string(raw) + "' (expected: libavformat|ffmpeg_process|legacy_custom)");
|
||||
}
|
||||
|
||||
std::expected<EncoderBackendType, std::string> parse_encoder_backend(std::string_view raw) {
|
||||
if (raw == "auto") {
|
||||
return EncoderBackendType::Auto;
|
||||
@@ -328,6 +342,16 @@ std::expected<void, std::string> apply_toml_file(RuntimeConfig &config, const st
|
||||
config.outputs.rtmp.enabled = true;
|
||||
config.outputs.rtmp.urls = std::move(*values);
|
||||
}
|
||||
if (auto value = toml_value<std::string>(table, "outputs.rtmp.transport")) {
|
||||
auto parsed = parse_rtmp_transport(*value);
|
||||
if (!parsed) {
|
||||
return std::unexpected(parsed.error());
|
||||
}
|
||||
config.outputs.rtmp.transport = *parsed;
|
||||
}
|
||||
if (auto value = toml_value<std::string>(table, "outputs.rtmp.ffmpeg_path")) {
|
||||
config.outputs.rtmp.ffmpeg_path = *value;
|
||||
}
|
||||
if (auto value = toml_value<std::string>(table, "outputs.rtmp.mode")) {
|
||||
auto parsed = parse_rtmp_mode(*value);
|
||||
if (!parsed) {
|
||||
@@ -484,6 +508,18 @@ std::string_view to_string(RtmpMode mode) {
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
std::string_view to_string(RtmpTransportType transport) {
|
||||
switch (transport) {
|
||||
case RtmpTransportType::Libavformat:
|
||||
return "libavformat";
|
||||
case RtmpTransportType::FfmpegProcess:
|
||||
return "ffmpeg_process";
|
||||
case RtmpTransportType::LegacyCustom:
|
||||
return "legacy_custom";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
std::string_view to_string(EncoderBackendType backend) {
|
||||
switch (backend) {
|
||||
case EncoderBackendType::Auto:
|
||||
@@ -530,6 +566,8 @@ std::expected<RuntimeConfig, std::string> parse_runtime_config(int argc, char **
|
||||
std::string encoder_backend_raw{};
|
||||
std::string encoder_device_raw{};
|
||||
std::string rtmp_mode_raw{};
|
||||
std::string rtmp_transport_raw{};
|
||||
std::string rtmp_ffmpeg_path_raw{};
|
||||
std::vector<std::string> rtmp_urls_raw{};
|
||||
std::string rtp_endpoint_raw{};
|
||||
std::string rtp_payload_type_raw{};
|
||||
@@ -565,6 +603,8 @@ std::expected<RuntimeConfig, std::string> parse_runtime_config(int argc, char **
|
||||
app.add_option("--encoder-device", encoder_device_raw);
|
||||
app.add_flag("--rtmp", rtmp_enabled);
|
||||
app.add_option("--rtmp-url", rtmp_urls_raw);
|
||||
app.add_option("--rtmp-transport", rtmp_transport_raw);
|
||||
app.add_option("--rtmp-ffmpeg", rtmp_ffmpeg_path_raw);
|
||||
app.add_option("--rtmp-mode", rtmp_mode_raw);
|
||||
app.add_flag("--rtp", rtp_enabled);
|
||||
app.add_option("--rtp-endpoint", rtp_endpoint_raw);
|
||||
@@ -642,6 +682,16 @@ std::expected<RuntimeConfig, std::string> parse_runtime_config(int argc, char **
|
||||
config.outputs.rtmp.enabled = true;
|
||||
config.outputs.rtmp.urls = std::move(rtmp_urls_raw);
|
||||
}
|
||||
if (!rtmp_transport_raw.empty()) {
|
||||
auto parsed = parse_rtmp_transport(rtmp_transport_raw);
|
||||
if (!parsed) {
|
||||
return std::unexpected(parsed.error());
|
||||
}
|
||||
config.outputs.rtmp.transport = *parsed;
|
||||
}
|
||||
if (!rtmp_ffmpeg_path_raw.empty()) {
|
||||
config.outputs.rtmp.ffmpeg_path = rtmp_ffmpeg_path_raw;
|
||||
}
|
||||
if (!rtmp_mode_raw.empty()) {
|
||||
auto parsed = parse_rtmp_mode(rtmp_mode_raw);
|
||||
if (!parsed) {
|
||||
@@ -781,15 +831,29 @@ std::expected<void, std::string> validate_runtime_config(const RuntimeConfig &co
|
||||
return std::unexpected("invalid RTMP config: URL must not be empty");
|
||||
}
|
||||
}
|
||||
if (config.outputs.rtmp.mode == RtmpMode::Domestic && config.encoder.codec != CodecType::H265) {
|
||||
return std::unexpected("invalid mode matrix: domestic RTMP mode requires codec h265");
|
||||
}
|
||||
if (config.encoder.backend == EncoderBackendType::FFmpeg && config.outputs.rtmp.enabled) {
|
||||
return std::unexpected("invalid backend/output matrix: RTMP is only supported by gstreamer_legacy in this build");
|
||||
}
|
||||
if (config.encoder.backend == EncoderBackendType::GStreamerLegacy && config.record.mcap.enabled) {
|
||||
return std::unexpected("invalid backend/output matrix: MCAP recording requires the ffmpeg encoded access-unit path");
|
||||
}
|
||||
if (config.outputs.rtmp.enabled) {
|
||||
if (config.outputs.rtmp.transport == RtmpTransportType::LegacyCustom) {
|
||||
if (config.outputs.rtmp.mode == RtmpMode::Domestic && config.encoder.codec != CodecType::H265) {
|
||||
return std::unexpected("invalid mode matrix: domestic RTMP mode requires codec h265");
|
||||
}
|
||||
if (config.encoder.backend != EncoderBackendType::GStreamerLegacy) {
|
||||
return std::unexpected("invalid backend/output matrix: legacy_custom RTMP requires encoder.backend=gstreamer_legacy");
|
||||
}
|
||||
} else {
|
||||
if (config.outputs.rtmp.mode != RtmpMode::Enhanced) {
|
||||
return std::unexpected("invalid RTMP config: non-legacy RTMP transports only support rtmp.mode=enhanced");
|
||||
}
|
||||
if (config.encoder.backend != EncoderBackendType::FFmpeg) {
|
||||
return std::unexpected("invalid backend/output matrix: RTMP transports libavformat and ffmpeg_process require encoder.backend=ffmpeg");
|
||||
}
|
||||
if (config.outputs.rtmp.transport == RtmpTransportType::FfmpegProcess && config.outputs.rtmp.ffmpeg_path.empty()) {
|
||||
return std::unexpected("invalid RTMP config: ffmpeg_process transport requires a non-empty ffmpeg path");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.outputs.rtp.enabled) {
|
||||
if (!config.outputs.rtp.endpoint || config.outputs.rtp.endpoint->empty()) {
|
||||
@@ -831,8 +895,8 @@ std::expected<void, std::string> validate_runtime_config(const RuntimeConfig &co
|
||||
if (config.encoder.backend == EncoderBackendType::GStreamerLegacy) {
|
||||
return std::unexpected("invalid backend config: gstreamer_legacy backend requested but GStreamer support is not compiled");
|
||||
}
|
||||
if (config.outputs.rtmp.enabled) {
|
||||
return std::unexpected("invalid output config: RTMP requires GStreamer legacy support, which is not compiled");
|
||||
if (config.outputs.rtmp.enabled && config.outputs.rtmp.transport == RtmpTransportType::LegacyCustom) {
|
||||
return std::unexpected("invalid output config: legacy_custom RTMP requires GStreamer support, which is not compiled");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -849,6 +913,7 @@ std::string summarize_runtime_config(const RuntimeConfig &config) {
|
||||
ss << ", encoder.gop=" << config.encoder.gop;
|
||||
ss << ", encoder.b_frames=" << config.encoder.b_frames;
|
||||
ss << ", rtmp.enabled=" << (config.outputs.rtmp.enabled ? "true" : "false");
|
||||
ss << ", rtmp.transport=" << to_string(config.outputs.rtmp.transport);
|
||||
ss << ", rtmp.mode=" << to_string(config.outputs.rtmp.mode);
|
||||
ss << ", rtmp.urls=" << config.outputs.rtmp.urls.size();
|
||||
ss << ", rtp.enabled=" << (config.outputs.rtp.enabled ? "true" : "false");
|
||||
|
||||
Reference in New Issue
Block a user