rtsp_tensorrt/pipeline/common/yaml_config_parser.cpp
sladro e13cb3659c feat: 初始化项目结构
- 创建基本项目结构和目录
- 添加CMake构建系统
- 实现基础的配置解析功能
- 添加YOLO推理框架支持
- 集成RTSP和视频流处理功能
- 添加性能监控和日志系统
2024-12-24 16:25:03 +08:00

467 lines
18 KiB
C++

#include "yaml_config_parser.hpp"
#include "../common/logger.hpp"
#include <filesystem>
#include <iostream>
#include <opencv2/core.hpp>
namespace pipeline {
bool YamlConfigParser::parse(const std::string& config_file) {
try {
Logger::info("Parsing config file: " + config_file);
yaml_config_ = YAML::LoadFile(config_file);
// 解析各个配置部分
if (!parseInputConfig(yaml_config_["input"])) {
Logger::error("Failed to parse input config");
return false;
}
if (!parseModelConfig(yaml_config_["inference"])) {
Logger::error("Failed to parse model config");
return false;
}
if (!parseRenderConfig(yaml_config_["render"])) {
Logger::error("Failed to parse render config");
return false;
}
if (!parseOutputConfig(yaml_config_["output"])) {
Logger::error("Failed to parse output config");
return false;
}
if (!parseLogConfig(yaml_config_["log"])) {
Logger::error("Failed to parse log config");
return false;
}
Logger::info("Successfully parsed all configurations");
return true;
} catch (const YAML::Exception& e) {
Logger::error("YAML parsing error: " + std::string(e.what()));
return false;
} catch (const std::exception& e) {
Logger::error("Error in parse: " + std::string(e.what()));
return false;
}
}
bool YamlConfigParser::validate() {
// 基本验证
if (config_.input.sources.empty()) {
std::cerr << "Error: No input sources configured" << std::endl;
return false;
}
// 验证输入源配置
for (const auto& source : config_.input.sources) {
if (source.type.empty() || source.name.empty()) {
std::cerr << "Error: Input source missing type or name" << std::endl;
return false;
}
if (source.type == "rtsp" && source.url.empty()) {
std::cerr << "Error: RTSP source missing URL" << std::endl;
return false;
}
if (source.buffer_size <= 0) {
std::cerr << "Error: Invalid buffer size for source: " << source.name << std::endl;
return false;
}
}
// 验证推理配置
if (config_.inference.engine_path.empty()) {
std::cerr << "Error: Model engine path not specified" << std::endl;
return false;
}
if (config_.inference.input_shape.empty()) {
std::cerr << "Error: Model input shape not specified" << std::endl;
return false;
}
if (config_.inference.threshold.conf < 0.0f || config_.inference.threshold.conf > 1.0f) {
std::cerr << "Error: Invalid confidence threshold (must be between 0.0 and 1.0)" << std::endl;
return false;
}
if (config_.inference.threshold.nms < 0.0f || config_.inference.threshold.nms > 1.0f) {
std::cerr << "Error: Invalid NMS threshold (must be between 0.0 and 1.0)" << std::endl;
return false;
}
// 验证渲染配置
// 验证窗口配置
if (config_.render.window.width <= 0 || config_.render.window.height <= 0) {
std::cerr << "Error: Invalid window dimensions" << std::endl;
return false;
}
if (config_.render.window.name.empty()) {
std::cerr << "Error: Window name not specified" << std::endl;
return false;
}
// 验证默认样式
if (config_.render.default_style.transparency < 0.0f ||
config_.render.default_style.transparency > 1.0f) {
std::cerr << "Error: Invalid default style transparency (must be between 0.0 and 1.0)" << std::endl;
return false;
}
if (config_.render.default_style.box_thickness <= 0 ||
config_.render.default_style.font_thickness <= 0) {
std::cerr << "Error: Invalid default style thickness values" << std::endl;
return false;
}
if (config_.render.default_style.font_scale <= 0.0) {
std::cerr << "Error: Invalid default style font scale" << std::endl;
return false;
}
// 验证类别样式
for (const auto& [class_name, style] : config_.render.class_styles) {
if (class_name.empty()) {
std::cerr << "Error: Empty class name in style configuration" << std::endl;
return false;
}
if (style.transparency < 0.0f || style.transparency > 1.0f) {
std::cerr << "Error: Invalid transparency for class " << class_name << std::endl;
return false;
}
if (style.box_thickness <= 0 || style.font_thickness <= 0) {
std::cerr << "Error: Invalid thickness values for class " << class_name << std::endl;
return false;
}
if (style.font_scale <= 0.0) {
std::cerr << "Error: Invalid font scale for class " << class_name << std::endl;
return false;
}
}
// 验证性能指标配置
if (config_.render.metrics.update_interval_ms <= 0) {
std::cerr << "Error: Invalid metrics update interval" << std::endl;
return false;
}
// 验证输出配置
for (const auto& target : config_.output.targets) {
if (target.type.empty() || target.name.empty()) {
std::cerr << "Error: Output target missing type or name" << std::endl;
return false;
}
if (target.type == "video") {
if (target.path.empty()) {
std::cerr << "Error: Video output target missing path" << std::endl;
return false;
}
if (target.fps <= 0) {
std::cerr << "Error: Invalid video output fps" << std::endl;
return false;
}
if (target.bitrate <= 0) {
std::cerr << "Error: Invalid video output bitrate" << std::endl;
return false;
}
if (target.codec.empty()) {
std::cerr << "Error: Video output codec not specified" << std::endl;
return false;
}
}
}
// 验证日志配置
if (config_.log.level.empty()) {
std::cerr << "Error: Log level not specified" << std::endl;
return false;
}
if (config_.log.save_path.empty()) {
std::cerr << "Error: Log save path not specified" << std::endl;
return false;
}
return true;
}
bool YamlConfigParser::parseInputConfig(const YAML::Node& node) {
try {
// 解析输入源
if (node["sources"]) {
for (const auto& source : node["sources"]) {
InputSourceConfig src_config;
src_config.type = source["type"].as<std::string>();
src_config.name = source["name"].as<std::string>();
if (source["url"]) {
src_config.url = source["url"].as<std::string>();
}
if (source["buffer_size"]) {
src_config.buffer_size = source["buffer_size"].as<int>();
}
// 解析输出目标列表
if (source["outputs"]) {
src_config.outputs = source["outputs"].as<std::vector<std::string>>();
}
config_.input.sources.push_back(src_config);
}
}
// 解析批处理大小
if (node["max_batch_size"]) {
config_.input.max_batch_size = node["max_batch_size"].as<int>();
}
return true;
} catch (const YAML::Exception& e) {
Logger::error("Error parsing input config: " + std::string(e.what()));
return false;
}
}
bool YamlConfigParser::parseModelConfig(const YAML::Node& node) {
try {
if (!node["model"]) {
Logger::error("Model configuration section not found");
return false;
}
const auto& model = node["model"];
// 检查必需的字段
if (!model["onnx_path"]) {
Logger::error("ONNX path not specified in model config");
return false;
}
if (!model["engine_path"]) {
Logger::error("Engine path not specified in model config");
return false;
}
if (!model["input_shape"]) {
Logger::error("Input shape not specified in model config");
return false;
}
// 读取配置
config_.inference.engine_path = model["engine_path"].as<std::string>();
config_.inference.input_shape = model["input_shape"].as<std::vector<int>>();
config_.inference.precision = model["precision"] ? model["precision"].as<std::string>() : "FP16";
// 读取阈值配置
if (node["threshold"]) {
config_.inference.threshold.conf = node["threshold"]["conf"] ?
node["threshold"]["conf"].as<float>() : 0.5f;
config_.inference.threshold.nms = node["threshold"]["nms"] ?
node["threshold"]["nms"].as<float>() : 0.45f;
}
// 读取GPU ID
config_.inference.gpu_id = node["gpu_id"] ? node["gpu_id"].as<int>() : 0;
// 打印读取的配置
Logger::info("Loaded model configuration:");
Logger::info(" Engine path: " + config_.inference.engine_path);
Logger::info(" Input shape: " + std::to_string(config_.inference.input_shape[0]) + "," +
std::to_string(config_.inference.input_shape[1]) + "," +
std::to_string(config_.inference.input_shape[2]));
Logger::info(" Precision: " + config_.inference.precision);
Logger::info(" GPU ID: " + std::to_string(config_.inference.gpu_id));
Logger::info(" Confidence threshold: " + std::to_string(config_.inference.threshold.conf));
Logger::info(" NMS threshold: " + std::to_string(config_.inference.threshold.nms));
return true;
} catch (const YAML::Exception& e) {
Logger::error("Failed to parse model config: " + std::string(e.what()));
return false;
} catch (const std::exception& e) {
Logger::error("Error in parseModelConfig: " + std::string(e.what()));
return false;
}
}
bool YamlConfigParser::parseRenderConfig(const YAML::Node& node) {
try {
// 解析窗口配置
if (node["window"]) {
const auto& window = node["window"];
if (window["name"]) {
config_.render.window.name = window["name"].as<std::string>();
}
if (window["width"]) {
config_.render.window.width = window["width"].as<int>();
}
if (window["height"]) {
config_.render.window.height = window["height"].as<int>();
}
if (window["fullscreen"]) {
config_.render.window.fullscreen = window["fullscreen"].as<bool>();
}
}
// 解析默认样式
if (node["default_style"]) {
const auto& style = node["default_style"];
if (style["box_color"]) {
auto color = style["box_color"].as<std::vector<int>>();
if (color.size() >= 3) {
config_.render.default_style.box_color = cv::Scalar(color[0], color[1], color[2]);
}
}
if (style["text_color"]) {
auto color = style["text_color"].as<std::vector<int>>();
if (color.size() >= 3) {
config_.render.default_style.text_color = cv::Scalar(color[0], color[1], color[2]);
}
}
if (style["transparency"]) {
config_.render.default_style.transparency = style["transparency"].as<float>();
}
if (style["box_thickness"]) {
config_.render.default_style.box_thickness = style["box_thickness"].as<int>();
}
if (style["font_scale"]) {
config_.render.default_style.font_scale = style["font_scale"].as<double>();
}
if (style["font_thickness"]) {
config_.render.default_style.font_thickness = style["font_thickness"].as<int>();
}
}
// 解析类别样式
if (node["class_styles"]) {
for (const auto& class_style : node["class_styles"]) {
std::string class_name = class_style.first.as<std::string>();
const auto& style = class_style.second;
RenderConfig::ClassStyle class_config;
if (style["box_color"]) {
auto color = style["box_color"].as<std::vector<int>>();
if (color.size() >= 3) {
class_config.box_color = cv::Scalar(color[0], color[1], color[2]);
}
}
if (style["text_color"]) {
auto color = style["text_color"].as<std::vector<int>>();
if (color.size() >= 3) {
class_config.text_color = cv::Scalar(color[0], color[1], color[2]);
}
}
if (style["transparency"]) {
class_config.transparency = style["transparency"].as<float>();
}
if (style["box_thickness"]) {
class_config.box_thickness = style["box_thickness"].as<int>();
}
if (style["font_scale"]) {
class_config.font_scale = style["font_scale"].as<double>();
}
if (style["font_thickness"]) {
class_config.font_thickness = style["font_thickness"].as<int>();
}
config_.render.class_styles[class_name] = class_config;
}
}
// 解析性能指标配置
if (node["metrics"]) {
const auto& metrics = node["metrics"];
if (metrics["show_fps"]) {
config_.render.metrics.show_fps = metrics["show_fps"].as<bool>();
}
if (metrics["show_inference_time"]) {
config_.render.metrics.show_inference_time = metrics["show_inference_time"].as<bool>();
}
if (metrics["show_gpu_usage"]) {
config_.render.metrics.show_gpu_usage = metrics["show_gpu_usage"].as<bool>();
}
if (metrics["update_interval_ms"]) {
config_.render.metrics.update_interval_ms = metrics["update_interval_ms"].as<int>();
}
}
return true;
} catch (const YAML::Exception& e) {
Logger::error("Error parsing render config: " + std::string(e.what()));
return false;
}
}
bool YamlConfigParser::parseOutputConfig(const YAML::Node& node) {
try {
if (node["targets"]) {
for (const auto& target : node["targets"]) {
OutputTargetConfig target_config;
target_config.type = target["type"].as<std::string>();
target_config.name = target["name"].as<std::string>();
if (target["path"]) {
target_config.path = target["path"].as<std::string>();
}
if (target["fps"]) {
target_config.fps = target["fps"].as<int>();
}
if (target["codec"]) {
target_config.codec = target["codec"].as<std::string>();
}
if (target["bitrate"]) {
target_config.bitrate = target["bitrate"].as<int>();
}
config_.output.targets.push_back(target_config);
}
}
return true;
} catch (const YAML::Exception& e) {
return false;
}
}
bool YamlConfigParser::parseLogConfig(const YAML::Node& node) {
try {
if (node["level"]) {
config_.log.level = node["level"].as<std::string>();
}
if (node["save_path"]) {
config_.log.save_path = node["save_path"].as<std::string>();
}
return true;
} catch (const YAML::Exception& e) {
return false;
}
}
bool YamlConfigParser::parseRtspConfig(const YAML::Node& config, RtspReader::Config& rtsp_config) {
try {
auto rtsp_node = config["rtsp"];
if (!rtsp_node) {
return false;
}
// 设置默认值
rtsp_config = RtspReader::Config();
// 读取配置
if (rtsp_node["buffer_size"]) {
rtsp_config.buffer_size = rtsp_node["buffer_size"].as<int>();
}
if (rtsp_node["max_retry_count"]) {
rtsp_config.max_retry_count = rtsp_node["max_retry_count"].as<int>();
}
if (rtsp_node["retry_interval_ms"]) {
rtsp_config.retry_interval_ms = rtsp_node["retry_interval_ms"].as<int>();
}
if (rtsp_node["frame_timeout_ms"]) {
rtsp_config.frame_timeout_ms = rtsp_node["frame_timeout_ms"].as<int>();
}
if (rtsp_node["target_fps"]) {
rtsp_config.target_fps = rtsp_node["target_fps"].as<float>();
}
return true;
} catch (const YAML::Exception& e) {
Logger::error("Error parsing RTSP config: " + std::string(e.what()));
return false;
}
}
// 工厂函数实现
std::unique_ptr<ConfigParser> createConfigParser() {
return std::make_unique<YamlConfigParser>();
}
} // namespace pipeline