kunlang_video/include/app_config.hpp

287 lines
11 KiB
C++
Raw Normal View History

2025-09-08 14:55:07 +08:00
#pragma once
2025-11-13 13:21:10 +08:00
#include <limits.h>
#include <unistd.h>
2025-09-08 14:55:07 +08:00
#include <fstream>
#include <map>
2025-09-08 14:55:07 +08:00
#include <nlohmann/json.hpp>
#include <stdexcept>
2025-11-13 13:21:10 +08:00
#include <string>
2026-05-09 10:51:10 +08:00
#include <vector>
2025-11-13 13:21:10 +08:00
2025-09-08 14:55:07 +08:00
#include "logger.hpp"
using json = nlohmann::json;
using ordered_json = nlohmann::ordered_json;
enum class StreamType
{
MAIN,
SUB
};
2025-09-08 14:55:07 +08:00
struct Camera
{
std::string device;
std::string name;
2026-05-09 10:51:10 +08:00
int width = 1280;
int height = 720;
int fps = 30;
int bitrate = 2000000;
bool enabled = false;
StreamType stream_type = StreamType::MAIN;
2025-09-08 14:55:07 +08:00
};
struct VehicleMQTTTopics
{
std::string heartbeat_up;
std::string video_down;
2025-11-14 15:04:12 +08:00
std::string record_query;
std::string record_play;
2025-09-08 14:55:07 +08:00
void fill_with_veh_id(const std::string& vehId, const std::string& profile)
2025-09-08 14:55:07 +08:00
{
if (profile == "legacy")
{
heartbeat_up = "/kun/vehicle/video/status/" + vehId;
video_down = "/kun/vehicle/video/request/" + vehId;
record_query = "/kun/vehicle/video/record/query/" + vehId;
record_play = "/kun/vehicle/video/record/play/" + vehId;
return;
}
heartbeat_up = "/zxwl/sweeper/" + vehId + "/video/status";
video_down = "/zxwl/sweeper/" + vehId + "/video/query";
record_query = "/zxwl/sweeper/" + vehId + "/record/query";
record_play = "/zxwl/sweeper/" + vehId + "/record/play";
2025-09-08 14:55:07 +08:00
}
};
struct MQTTConfig
{
std::string vehicle_id;
std::string server_ip;
2026-05-09 10:51:10 +08:00
int server_port = 1883;
bool need_username_pwd = true;
2025-09-08 14:55:07 +08:00
std::string client_id;
std::string username;
std::string password;
std::string topic_profile = "protocol";
2026-05-09 10:51:10 +08:00
int keep_alive = 2000;
2025-09-08 15:11:52 +08:00
2026-05-09 10:51:10 +08:00
int qos = 1;
bool clean_session = true;
2025-09-08 15:11:52 +08:00
2025-09-08 14:55:07 +08:00
VehicleMQTTTopics topics;
};
2026-05-09 10:51:10 +08:00
struct SRSConfig
{
struct LiveProfile
{
std::string push_host;
int push_rtmp_port = 0;
std::string playback_scheme = "http";
std::string playback_host;
int playback_http_api_port = 0;
std::string playback_rtc_eip;
std::string vhost = "live";
};
2026-05-09 10:51:10 +08:00
std::string root = "/opt/vehicle-video-service/srs";
std::string record_config = "/opt/vehicle-video-service/srs/conf/record.conf";
std::string stream_app = "camera";
2026-05-09 11:36:51 +08:00
bool live_enabled = true;
bool record_enabled = true;
std::string live_push_profile = "wan_194";
std::string live_playback_profile = "wan_194";
2026-05-09 10:51:10 +08:00
std::string live_host = "127.0.0.1";
int live_rtmp_port = 1935;
int live_http_api_port = 1985;
2026-05-09 11:36:51 +08:00
int live_http_server_port = 8080;
int live_rtc_port = 8000;
2026-05-09 10:51:10 +08:00
std::string live_vhost = "live";
std::string record_host = "127.0.0.1";
int record_rtmp_port = 2935;
int record_http_api_port = 2985;
2026-05-09 11:36:51 +08:00
int record_http_server_port = 2980;
2026-05-09 10:51:10 +08:00
std::string record_vhost = "record";
2026-05-09 11:36:51 +08:00
std::string record_path = "/media/record";
int dvr_duration_sec = 60;
int retention_days = 14;
double usage_threshold = 0.90;
2026-05-09 10:51:10 +08:00
std::string public_interface = "enP2p33s0";
std::map<std::string, LiveProfile> live_profiles = {
{"lan_194", {"192.168.4.194", 1935, "http", "192.168.4.194", 11985, "192.168.4.194:8000", "live"}},
{"wan_194", {"36.153.162.171", 19435, "http", "36.153.162.171", 11985, "36.153.162.171:8000", "live"}},
};
2026-05-09 10:51:10 +08:00
};
2026-05-09 11:36:51 +08:00
struct WebConfig
{
bool enabled = true;
std::string bind = "0.0.0.0";
int port = 18080;
std::string username = "admin";
std::string password = "admin123";
};
2025-09-08 14:55:07 +08:00
struct AppConfig
{
std::vector<Camera> cameras;
MQTTConfig mqtt;
2026-05-09 10:51:10 +08:00
SRSConfig srs;
2026-05-09 11:36:51 +08:00
WebConfig web;
2025-09-08 14:55:07 +08:00
2025-11-13 13:21:10 +08:00
static AppConfig load_from_file(const std::string& filepath)
2025-09-08 14:55:07 +08:00
{
AppConfig cfg;
std::ifstream ifs(filepath);
if (!ifs.is_open())
{
LOG_ERROR("[Config] Failed to open config file: " + filepath);
throw std::runtime_error("Failed to open config file: " + filepath);
}
json j;
ifs >> j;
if (j.contains("cameras"))
{
2025-11-13 13:21:10 +08:00
for (auto& c : j["cameras"])
2025-09-08 14:55:07 +08:00
{
Camera cam;
cam.device = c.value("device", "");
cam.name = c.value("name", "");
2026-05-09 10:51:10 +08:00
cam.width = c.value("width", cam.width);
cam.height = c.value("height", cam.height);
cam.fps = c.value("fps", cam.fps);
cam.bitrate = c.value("bitrate", cam.bitrate);
cam.enabled = c.value("enabled", cam.enabled);
2025-09-08 14:55:07 +08:00
cfg.cameras.push_back(cam);
2025-11-13 13:21:10 +08:00
LOG_INFO("[Config] Loaded camera: " + cam.name + " (" + cam.device +
"), enabled=" + std::to_string(cam.enabled) + ", bitrate=" + std::to_string(cam.bitrate));
2025-09-08 14:55:07 +08:00
}
}
if (!j.contains("mqtt_server"))
{
LOG_ERROR("[Config] Missing 'mqtt_server' section");
throw std::runtime_error("Config file missing 'mqtt_server'");
}
2025-11-13 13:21:10 +08:00
auto& m = j["mqtt_server"];
2025-09-08 14:55:07 +08:00
cfg.mqtt.vehicle_id = std::to_string(m.value("veh_id", 0));
cfg.mqtt.server_ip = m.value("address", "");
2026-05-09 10:51:10 +08:00
cfg.mqtt.server_port = m.value("port", cfg.mqtt.server_port);
cfg.mqtt.need_username_pwd = m.value("need_username_pwd", cfg.mqtt.need_username_pwd);
2025-09-08 14:55:07 +08:00
cfg.mqtt.client_id = m.value("client_id", "");
cfg.mqtt.username = m.value("username", "");
cfg.mqtt.password = m.value("password", "");
cfg.mqtt.topic_profile = m.value("topic_profile", cfg.mqtt.topic_profile);
2026-05-09 10:51:10 +08:00
cfg.mqtt.keep_alive = m.value("mqtt_heart_threshold", cfg.mqtt.keep_alive);
cfg.mqtt.topics.fill_with_veh_id(cfg.mqtt.vehicle_id, cfg.mqtt.topic_profile);
2025-09-08 14:55:07 +08:00
2026-05-09 10:51:10 +08:00
if (j.contains("srs"))
{
auto& s = j["srs"];
cfg.srs.root = s.value("root", cfg.srs.root);
cfg.srs.record_config = s.value("record_config", cfg.srs.record_config);
cfg.srs.stream_app = s.value("stream_app", cfg.srs.stream_app);
2026-05-09 11:36:51 +08:00
cfg.srs.live_enabled = s.value("live_enabled", cfg.srs.live_enabled);
cfg.srs.record_enabled = s.value("record_enabled", cfg.srs.record_enabled);
cfg.srs.live_push_profile = s.value("live_push_profile", cfg.srs.live_push_profile);
cfg.srs.live_playback_profile = s.value("live_playback_profile", cfg.srs.live_playback_profile);
2026-05-09 10:51:10 +08:00
cfg.srs.live_host = s.value("live_host", cfg.srs.live_host);
cfg.srs.live_rtmp_port = s.value("live_rtmp_port", cfg.srs.live_rtmp_port);
cfg.srs.live_http_api_port = s.value("live_http_api_port", cfg.srs.live_http_api_port);
2026-05-09 11:36:51 +08:00
cfg.srs.live_http_server_port = s.value("live_http_server_port", cfg.srs.live_http_server_port);
cfg.srs.live_rtc_port = s.value("live_rtc_port", cfg.srs.live_rtc_port);
2026-05-09 10:51:10 +08:00
cfg.srs.live_vhost = s.value("live_vhost", cfg.srs.live_vhost);
cfg.srs.record_host = s.value("record_host", cfg.srs.record_host);
cfg.srs.record_rtmp_port = s.value("record_rtmp_port", cfg.srs.record_rtmp_port);
cfg.srs.record_http_api_port = s.value("record_http_api_port", cfg.srs.record_http_api_port);
2026-05-09 11:36:51 +08:00
cfg.srs.record_http_server_port = s.value("record_http_server_port", cfg.srs.record_http_server_port);
2026-05-09 10:51:10 +08:00
cfg.srs.record_vhost = s.value("record_vhost", cfg.srs.record_vhost);
2026-05-09 11:36:51 +08:00
cfg.srs.record_path = s.value("record_path", cfg.srs.record_path);
cfg.srs.dvr_duration_sec = s.value("dvr_duration_sec", cfg.srs.dvr_duration_sec);
cfg.srs.retention_days = s.value("retention_days", cfg.srs.retention_days);
cfg.srs.usage_threshold = s.value("usage_threshold", cfg.srs.usage_threshold);
2026-05-09 10:51:10 +08:00
cfg.srs.public_interface = s.value("public_interface", cfg.srs.public_interface);
if (s.contains("live_profiles") && s["live_profiles"].is_object())
{
cfg.srs.live_profiles.clear();
for (auto it = s["live_profiles"].begin(); it != s["live_profiles"].end(); ++it)
{
if (!it.value().is_object()) continue;
SRSConfig::LiveProfile profile;
const auto& p = it.value();
profile.push_host = p.value("push_host", profile.push_host);
profile.push_rtmp_port = p.value("push_rtmp_port", profile.push_rtmp_port);
profile.playback_scheme = p.value("playback_scheme", profile.playback_scheme);
profile.playback_host = p.value("playback_host", profile.playback_host);
profile.playback_http_api_port =
p.value("playback_http_api_port", profile.playback_http_api_port);
profile.playback_rtc_eip = p.value("playback_rtc_eip", profile.playback_rtc_eip);
profile.vhost = p.value("vhost", profile.vhost);
cfg.srs.live_profiles[it.key()] = profile;
}
}
2026-05-09 10:51:10 +08:00
}
2026-05-09 11:36:51 +08:00
if (j.contains("web"))
{
auto& w = j["web"];
cfg.web.enabled = w.value("enabled", cfg.web.enabled);
cfg.web.bind = w.value("bind", cfg.web.bind);
cfg.web.port = w.value("port", cfg.web.port);
cfg.web.username = w.value("username", cfg.web.username);
cfg.web.password = w.value("password", cfg.web.password);
}
2025-11-13 13:21:10 +08:00
LOG_INFO("[Config] Loaded MQTT server: " + cfg.mqtt.server_ip + ":" + std::to_string(cfg.mqtt.server_port));
2025-09-08 14:55:07 +08:00
LOG_INFO("[Config] MQTT client ID: " + cfg.mqtt.client_id);
2025-11-13 13:21:10 +08:00
LOG_INFO("[Config] MQTT Credentials - username: " + cfg.mqtt.username + ", password: " + cfg.mqtt.password);
LOG_INFO("[Config] MQTT topic profile: " + cfg.mqtt.topic_profile);
2025-11-13 13:21:10 +08:00
LOG_INFO("[Config] MQTT Topics: " + cfg.mqtt.topics.heartbeat_up + ", " + cfg.mqtt.topics.video_down);
2025-09-09 16:21:06 +08:00
LOG_INFO("[Config] MQTT keepAlive: " + std::to_string(cfg.mqtt.keep_alive));
2026-05-09 10:51:10 +08:00
LOG_INFO("[Config] SRS root: " + cfg.srs.root);
LOG_INFO("[Config] SRS record config: " + cfg.srs.record_config);
2025-09-08 14:55:07 +08:00
return cfg;
}
};
inline std::string get_executable_dir()
{
char result[PATH_MAX] = {0};
ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
if (count == -1)
{
LOG_ERROR("[Config] Failed to read /proc/self/exe");
throw std::runtime_error("Failed to read /proc/self/exe");
}
std::string full_path(result, count);
auto pos = full_path.find_last_of('/');
if (pos == std::string::npos)
{
LOG_ERROR("[Config] Failed to find executable directory");
throw std::runtime_error("Failed to find executable directory");
}
return full_path.substr(0, pos);
}
2025-11-13 13:21:10 +08:00
inline std::string get_executable_dir_file_path(const std::string& filename)
2025-09-08 14:55:07 +08:00
{
std::string dir = get_executable_dir();
2025-11-13 13:21:10 +08:00
if (dir.back() != '/') dir += '/';
2025-09-08 14:55:07 +08:00
return dir + filename;
}
extern AppConfig g_app_config;