修改一个工程项目代码，整体要求：要仔细分析和审核【】内提供的源代码。要求：根据第三部分问题，程序运行后CPU占用太高。分析问题和解决问题，然后将修改后的代码文件完整
的输出来（要包括头文件），下面第一部分是项目介绍，第二部分是福建内容。第三部分是工程正常运行后的出现的问题：
一、项目介绍
一个c++的视频分析服务，目前算法分析服务triton server已经部署好了，并且部署了10种算法模型，可以通过的
TritonInference推理客户端调用triton server部署的算法算法模型（有10类算法：人员检测、车辆检测、船只检测、
土壤裸露、烟火检测、违法捕捞、非法垂钓、违法搭建、垃圾裸露、鸟类检测）。实现路径：读取配置文件RTSP流的地址，然后
通过GStreamer并发发接入多路视频流，然后调用ffmpeng来抽帧，抽帧形成图片数据，发送给triton server，然后将
返回的分析结果传给上层应用。同时实现多路并发、高性能、高可靠、系统调用，高效的图片抽帧、报警录像等等。
二、附件内容
完整代码工程如【】内所示，【】内包括项目整体的架构，所有的.h和.cpp文件，配置文件camera_config.ini和CMakeLists.txt。
三、问题
1）问题：根据配置文件camera_config.ini的接入两路相机，程序正常运行后，cpu占用太高占用太高，高达27.8。其"""   """内是通过top指令查看程序占用的内存和CPU情况。本程序对应的：进程号：733517；%CPU ：27.8；COMMAND ：algorithm_analy 。
2）为了问题分析简单：在VideoCapture类的onNewSample的回调函数中，直接返回，return GST_FLOW_OK；没有后续的算法分析，报警和录像功能干扰了；
但是还是cpu占用太高占用太高了，高达20%多。	
【
1. 项目整体架构
video_analysis_service/
├── CMakeLists.txt
├── config/
│   └── camera_config.ini
├── include/
│   ├── alarm_manager.h
│   ├── config_manager.h
│   ├── frame_processor.h
│   ├── logger.h
│   ├── triton_inference.h
│   └── video_capture.h
├── src/
│   ├── alarm_manager.cpp
│   ├── config_manager.cpp
│   ├── frame_processor.cpp
│   ├── logger.cpp
│   ├── main.cpp
│   ├── triton_inference.cpp
│   └── video_capture.cpp
└── build/
2. 项目整体的源代码如下
2.1 config_manager.h
#pragma once
#include <string>
#include <vector>
#include <map>

struct CameraConfig {
    std::string name;
    std::string rtsp_url;
    std::vector<std::string> algorithms;
    int frame_interval;
    std::map<std::string, std::string> alarm_strategies;
    std::string alarm_storage_path;
};

class ConfigManager {
public:
    static ConfigManager& getInstance();
    bool loadConfig(const std::string& config_path);
    const std::vector<CameraConfig>& getCameraConfigs() const;

private:
    ConfigManager() = default;
    std::vector<CameraConfig> camera_configs_;
};
2.2 config_manager.cpp
#include "config_manager.h"
#include "logger.h"
#include <fstream>
#include <sstream>

ConfigManager& ConfigManager::getInstance() {
    static ConfigManager instance;
    return instance;
}

bool ConfigManager::loadConfig(const std::string& config_path) {
    std::ifstream file(config_path);
    if (!file.is_open()) {
        LOG_ERROR("Failed to open config file: " + config_path);
        return false;
    }

    std::string line;
    CameraConfig current_config;
    
    while (std::getline(file, line)) {
        if (line.empty() || line[0] == '#') continue;
        
        if (line[0] == '[') {
            if (!current_config.name.empty()) {
                camera_configs_.push_back(current_config);
            }
            current_config = CameraConfig();
            current_config.name = line.substr(1, line.size() - 2);
            continue;
        }

        size_t pos = line.find('=');
        if (pos == std::string::npos) continue;

        std::string key = line.substr(0, pos);
        std::string value = line.substr(pos + 1);

        if (key == "rtsp_url") {
            current_config.rtsp_url = value;
        } else if (key == "frame_interval") {
            current_config.frame_interval = std::stoi(value);
        } else if (key == "algorithms") {
            std::stringstream ss(value);
            std::string algorithm;
            while (std::getline(ss, algorithm, ',')) {
                current_config.algorithms.push_back(algorithm);
            }
        } else if (key == "alarm_storage_path") {
            current_config.alarm_storage_path = value;
        } else if (key == "alarm_strategy") {
            std::stringstream ss(value);
            std::string strategy;
            while (std::getline(ss, strategy, ',')) {
                size_t colon_pos = strategy.find(':');
                if (colon_pos != std::string::npos) {
                    std::string alg = strategy.substr(0, colon_pos);
                    std::string strat = strategy.substr(colon_pos + 1);
                    current_config.alarm_strategies[alg] = strat;
                }
            }
        }
    }

    if (!current_config.name.empty()) {
        camera_configs_.push_back(current_config);
    }

    return true;
}

const std::vector<CameraConfig>& ConfigManager::getCameraConfigs() const {
    return camera_configs_;
}
2.3 video_capture.h
#pragma once

#include <string>
#include <memory>
#include <chrono>
#include <gst/gst.h>
#include <gst/video/video.h>  
#include <opencv2/opencv.hpp>
#include "config_manager.h"
#include "frame_processor.h"

class VideoCapture {
public:
    VideoCapture(const CameraConfig& config);
    ~VideoCapture();

    bool start();
    bool stop();

    bool isRunning() const;

    void setFrameProcessor(std::shared_ptr<FrameProcessor> processor);

private:
    static GstFlowReturn onNewSample(GstElement* sink, gpointer data);
        static gboolean onBusMessage(GstBus* bus, GstMessage* msg, gpointer data);

    void reconnect();
    
    
    std::chrono::system_clock::time_point last_frame_time_;
    bool is_running_;    
    GstElement* pipeline_;
    std::shared_ptr<FrameProcessor> frame_processor_;
    CameraConfig config_;

    std::mutex reconnect_mutex_;
    int reconnect_attempts_;
    std::vector<int> reconnect_intervals_;

   
};
2.4 video_capture.cpp
#include "video_capture.h"
#include "logger.h"
#include <gst/app/gstappsink.h>
#include <gst/video/video.h>

VideoCapture::VideoCapture(const CameraConfig &config)
    : config_(config), pipeline_(nullptr),
      is_running_(false),
      reconnect_attempts_(0),
      last_frame_time_(std::chrono::system_clock::now())
{
    if (!gst_is_initialized())
    {
        gst_init(NULL, NULL); // Initialize GStreamer if not already initialized
    }

    reconnect_intervals_ = {5, 10, 30, 180}; // 秒
}

VideoCapture::~VideoCapture()
{
    stop();
}

void VideoCapture::setFrameProcessor(std::shared_ptr<FrameProcessor> processor)
{
    frame_processor_ = processor;
}

bool VideoCapture::start()
{
    std::lock_guard<std::mutex> lock(reconnect_mutex_);

    if (!frame_processor_)
    {
        LOG_ERROR("No frame processor set for camera " + config_.name);
        return false;
    }

    if (is_running_)
    {
        LOG_WARNING("Camera " + config_.name + " is already running");
        return true;
    }

    // 确保清理之前的pipeline
    if (pipeline_)
    {
        gst_element_set_state(pipeline_, GST_STATE_NULL);
        gst_object_unref(pipeline_);
        pipeline_ = nullptr;
    }

    GError *error = nullptr;
    std::string sink_name = "sink_" + config_.name; // 为每个摄像头的appsink设置唯一名称
    std::string pipeline_str =
        "rtspsrc location=" + config_.rtsp_url +
        " protocols=tcp latency=500 ! rtph264depay ! h264parse ! avdec_h264 ! videoconvert ! appsink name=" + sink_name;

    pipeline_ = gst_parse_launch(pipeline_str.c_str(), &error);
    if (error)
    {
        LOG_ERROR("Failed to create pipeline for camera " + config_.name + ": " + error->message);
        g_error_free(error);
        return false;
    }

    // 修改这里：使用正确的sink名称
    GstElement *sink = gst_bin_get_by_name(GST_BIN(pipeline_), sink_name.c_str());
    if (!sink)
    {
        LOG_ERROR("Failed to get sink element for camera " + config_.name);
        gst_object_unref(pipeline_);
        pipeline_ = nullptr;
        return false;
    }

    g_object_set(G_OBJECT(sink),
                 "emit-signals", TRUE,
                 "sync", FALSE,
                 "max-buffers", 1,
                 "drop", TRUE,
                 NULL);

    g_signal_connect(sink, "new-sample", G_CALLBACK(onNewSample), this);
    gst_object_unref(sink);

    // 等待pipeline完全启动
    GstStateChangeReturn ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);
    if (ret == GST_STATE_CHANGE_FAILURE)
    {
        LOG_ERROR("Failed to start pipeline for camera " + config_.name);
        gst_object_unref(pipeline_);
        pipeline_ = nullptr;
        return false;
    }

    // 验证pipeline是否真正启动
    GstState state;
    ret = gst_element_get_state(pipeline_, &state, nullptr, 5 * GST_SECOND);
    if (ret != GST_STATE_CHANGE_SUCCESS || state != GST_STATE_PLAYING)
    {
        LOG_ERROR("Pipeline failed to reach PLAYING state for camera " + config_.name);
        gst_element_set_state(pipeline_, GST_STATE_NULL);
        gst_object_unref(pipeline_);
        pipeline_ = nullptr;
        return false;
    }

    is_running_ = true;
    LOG_INFO("Started video capture for camera " + config_.name);
    return true;
}

bool VideoCapture::stop()
{
    std::lock_guard<std::mutex> lock(reconnect_mutex_);
    if (!is_running_)
        return true;

    if (pipeline_)
    {
        gst_element_set_state(pipeline_, GST_STATE_NULL);
        gst_object_unref(pipeline_);
        pipeline_ = nullptr;
    }

    is_running_ = false;
    return true;
}

// 其他代码保持不变

bool VideoCapture::isRunning() const
{
    return is_running_;
}

GstFlowReturn VideoCapture::onNewSample(GstElement *sink, gpointer data)
{
    VideoCapture *self = static_cast<VideoCapture *>(data);
    if (!self)
    {
        g_print("Error: Invalid VideoCapture instance\n");
        return GST_FLOW_ERROR;
    }
	return GST_FLOW_OK; // Skip frame
	
    // Frame interval check
    auto current_time = std::chrono::system_clock::now();
    auto elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - self->last_frame_time_);

    if (elapsed_time.count() < self->config_.frame_interval)
    {
        return GST_FLOW_OK; // Skip frame
    }
    self->last_frame_time_ = current_time;

    std::cout << "VideoCapture::onNewSample==1 " << self->config_.name << std::endl;

    // 获取示例
    GstSample *sample_ptr = nullptr;
    g_signal_emit_by_name(sink, "pull-sample", &sample_ptr);
    if (!sample_ptr)
    {
        g_print("Error: Failed to pull sample for camera %s\n", self->config_.name.c_str());
        return GST_FLOW_ERROR;
    }

    // 使用智能指针管理 GstSample
    std::unique_ptr<GstSample, decltype(&gst_sample_unref)> sample(sample_ptr, gst_sample_unref);

    // 获取缓冲区
    GstBuffer *buffer = gst_sample_get_buffer(sample.get());
    if (!buffer)
    {
        g_print("Error: Failed to get buffer from sample for camera %s\n", self->config_.name.c_str());
        return GST_FLOW_ERROR;
    }

    try
    {
        // 获取 caps 和视频格式信息
        GstCaps *caps = gst_sample_get_caps(sample.get());
        if (!caps)
        {
            g_print("Error: No caps in sample for camera %s\n", self->config_.name.c_str());
            return GST_FLOW_ERROR;
        }

        GstStructure *structure = gst_caps_get_structure(caps, 0);
        if (!structure)
        {
            g_print("Error: No structure in caps for camera %s\n", self->config_.name.c_str());
            return GST_FLOW_ERROR;
        }

        // 获取视频格式
        const gchar *format = gst_structure_get_string(structure, "format");
        if (!format)
        {
            g_print("Error: No format in caps for camera %s\n", self->config_.name.c_str());
            return GST_FLOW_ERROR;
        }

        // 获取视频尺寸
        int width = 0, height = 0;
        if (!gst_structure_get_int(structure, "width", &width) ||
            !gst_structure_get_int(structure, "height", &height) ||
            width <= 0 || height <= 0)
        {
            g_print("Error: Invalid dimensions (%dx%d) for camera %s\n",
                    width, height, self->config_.name.c_str());
            return GST_FLOW_ERROR;
        }

        // Map buffer
        GstMapInfo map;
        if (!gst_buffer_map(buffer, &map, GST_MAP_READ))
        {
            g_print("Error: Failed to map buffer for camera %s\n", self->config_.name.c_str());
            return GST_FLOW_ERROR;
        }

        // 使用RAII确保buffer被正确unmap
        struct MapGuard
        {
            GstBuffer *buffer;
            GstMapInfo *map;
            ~MapGuard()
            {
                if (buffer && map)
                    gst_buffer_unmap(buffer, map);
            }
        } mapGuard{buffer, &map};

        // 确定正确的 Mat 类型
        int cv_type;
        if (g_str_equal(format, "RGB"))
        {
            cv_type = CV_8UC3;
        }
        else if (g_str_equal(format, "RGBA"))
        {
            cv_type = CV_8UC4;
        }
        else if (g_str_equal(format, "GRAY8"))
        {
            cv_type = CV_8UC1;
        }
        else if (g_str_equal(format, "BGR"))
        { // I420
            cv_type = CV_8UC3;
        }
        else if (g_str_equal(format, "I420"))
        {
            cv_type = CV_8UC1;
        }
        else
        {
            g_print("Error: Unsupported format %s for camera %s\n", format, self->config_.name.c_str());
            return GST_FLOW_ERROR;
        }

        // 安全地创建 Mat
        cv::Mat frame;
        {
            cv::Mat temp(height, width, cv_type, (void *)map.data);
            if (temp.empty())
            {
                g_print("Error: Failed to create temp frame for camera %s\n", self->config_.name.c_str());
                return GST_FLOW_ERROR;
            }

            // 确保数据被完全复制
            frame = temp.clone();
        }

        if (frame.empty())
        {
            g_print("Error: Failed to clone frame for camera %s\n", self->config_.name.c_str());
            return GST_FLOW_ERROR;
        }

        // 如果需要，转换为 BGR 格式
        if (!g_str_equal(format, "BGR"))
        {
            cv::Mat bgr_frame;
            if (g_str_equal(format, "RGB"))
            {
                cv::cvtColor(frame, bgr_frame, cv::COLOR_RGB2BGR);
            }
            else if (g_str_equal(format, "RGBA"))
            {
                cv::cvtColor(frame, bgr_frame, cv::COLOR_RGBA2BGR);
            }
            else if (g_str_equal(format, "GRAY8"))
            {
                cv::cvtColor(frame, bgr_frame, cv::COLOR_GRAY2BGR);
            }
            else if (g_str_equal(format, "I420"))
            {
                cv::cvtColor(frame, bgr_frame, cv::COLOR_YUV2BGR_I420);
            }
            frame = bgr_frame;
        }

        // 获取时间戳
        GstClockTime timestamp = GST_BUFFER_PTS(buffer);
        if (timestamp != GST_CLOCK_TIME_NONE)
        {
            // 转换为毫秒
            double timestamp_ms = timestamp / 1000000.0;
            // 可以在这里使用时间戳
        }

        // 处理帧
        if (self->frame_processor_)
        {
            try
            {
                self->frame_processor_->processFrame(frame);
            }
            catch (const std::exception &e)
            {
                g_print("Error: Frame processing exception for camera %s: %s\n",
                        self->config_.name.c_str(), e.what());
                return GST_FLOW_ERROR;
            }
        }

        return GST_FLOW_OK;
    }
    catch (const cv::Exception &e)
    {
        g_print("OpenCV Error in onNewSample for camera %s: %s\n",
                self->config_.name.c_str(), e.what());
        return GST_FLOW_ERROR;
    }
    catch (const std::exception &e)
    {
        g_print("Fatal: Unhandled exception in onNewSample for camera %s: %s\n",
                self->config_.name.c_str(), e.what());
        return GST_FLOW_ERROR;
    }
    catch (...)
    {
        g_print("Fatal: Unknown exception in onNewSample for camera %s\n",
                self->config_.name.c_str());
        return GST_FLOW_ERROR;
    }
}

// GstFlowReturn VideoCapture::onNewSample(GstElement *sink, gpointer data)
// {
//     VideoCapture *self = static_cast<VideoCapture *>(data);

//     // Frame interval check
//     auto current_time = std::chrono::system_clock::now();
//     auto elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - self->last_frame_time_);

//     if (elapsed_time.count() < self->config_.frame_interval)
//     {
//         return GST_FLOW_OK; // Skip frame
//     }
//     self->last_frame_time_ = current_time;
//     std::cout << "VideoCapture::onNewSample==1 " << self->config_.name << std::endl;
//     GstSample *sample = gst_app_sink_pull_sample(GST_APP_SINK(sink));
//     if (!sample)
//     {
//         return GST_FLOW_OK;
//     }

//     GstBuffer *buffer = gst_sample_get_buffer(sample);
//     GstMapInfo map;

//     if (gst_buffer_map(buffer, &map, GST_MAP_READ))
//     {
//         GstCaps *caps = gst_sample_get_caps(sample);
//         GstStructure *structure = gst_caps_get_structure(caps, 0);
//         int width, height;
//         gst_structure_get_int(structure, "width", &width);
//         gst_structure_get_int(structure, "height", &height);
//         const gchar *format = gst_structure_get_string(structure, "format");

//         cv::Mat frame;
//         if (strcmp(format, "BGR") == 0)
//         {
//             frame = cv::Mat(height, width, CV_8UC3, (char *)map.data);
//         }
//         else if (strcmp(format, "RGB") == 0)
//         {
//             frame = cv::Mat(height, width, CV_8UC3, (char *)map.data);
//             cv::cvtColor(frame, frame, cv::COLOR_RGB2BGR);
//         }
//         else if (strcmp(format, "RGBA") == 0)
//         {
//             cv::Mat rgba_frame(height, width, CV_8UC4, (char *)map.data);
//             cv::cvtColor(rgba_frame, frame, cv::COLOR_RGBA2BGR);
//         }
//         else if (strcmp(format, "NV12") == 0)
//         {
//             cv::Mat nv12_frame(height * 3 / 2, width, CV_8UC1, (char *)map.data);
//             cv::cvtColor(nv12_frame, frame, cv::COLOR_YUV2BGR_NV12);
//         }
//         else if (strcmp(format, "I420") == 0)
//         {
//             cv::Mat i420_frame(height * 3 / 2, width, CV_8UC1, (char *)map.data);
//             cv::cvtColor(i420_frame, frame, cv::COLOR_YUV2BGR_I420);
//         }
//         else
//         {
//             LOG_ERROR("Unsupported video format: " + std::string(format));
//             gst_buffer_unmap(buffer, &map);
//             gst_sample_unref(sample);
//             return GST_FLOW_OK;
//         }
//         // Make sure the processor is set
//         if (self->frame_processor_)
//         {
//             self->frame_processor_->processFrame(frame);
//         }
//         else
//         {
//             LOG_WARNING("Frame processor not set for camera " + self->config_.name);
//         }

//         gst_buffer_unmap(buffer, &map);
//     }

//     gst_sample_unref(sample);
//     return GST_FLOW_OK;
// }

gboolean VideoCapture::onBusMessage(GstBus *bus, GstMessage *msg, gpointer data)
{
    VideoCapture *self = static_cast<VideoCapture *>(data);

    switch (GST_MESSAGE_TYPE(msg))
    {
    case GST_MESSAGE_EOS:
        LOG_WARNING("Stream reached EOS for camera " + self->config_.name);
        std::cout << "VideoCapture::onBusMessage==disconnect" << std::endl;
        self->reconnect();
        break;
    case GST_MESSAGE_ERROR:
    {
        GError *err;
        gchar *debug_info;
        gst_message_parse_error(msg, &err, &debug_info);
        LOG_ERROR("GStreamer error for camera " + self->config_.name + ": " + err->message);
        std::cout << "VideoCapture::onBusMessage:error" << std::endl;
        self->reconnect();
        g_clear_error(&err);
        g_free(debug_info);
        self->reconnect();
        break;
    }
    default:
        break;
    }
    return TRUE;
}

void VideoCapture::reconnect()
{
    std::lock_guard<std::mutex> lock(reconnect_mutex_);
    if (is_running_)
    {
        gst_element_set_state(pipeline_, GST_STATE_NULL);
        gst_object_unref(pipeline_);
        pipeline_ = nullptr;
        is_running_ = false;
    }

    int wait_time = reconnect_attempts_ < reconnect_intervals_.size() ? reconnect_intervals_[reconnect_attempts_] : reconnect_intervals_.back();
    LOG_INFO("Attempting to reconnect camera " + config_.name + " in " + std::to_string(wait_time) + " seconds");
    std::this_thread::sleep_for(std::chrono::seconds(wait_time));

    reconnect_attempts_++;
    start();
}
2.5 alarm_manager.h
#pragma once
#include <string>
#include <vector>
#include <memory>
#include "config_manager.h"
#include "triton_inference.h"

class AlarmManager {
public:
    AlarmManager(const std::string& alarm_log_path);
    void handleAlarm(const CameraConfig& config, 
                     const std::vector<TritonInference::Detection>& detections);

private:
    bool checkAlarmCondition(const CameraConfig& config,
                             const std::vector<TritonInference::Detection>& detections);
    void startRecording(const CameraConfig& config, 
                        const std::string& video_path);
    void recordAlarm(const CameraConfig& config,
                     const std::string& image_path,
                     const std::string& video_path);
    std::string createMonthDirectory();
    
    std::string alarm_log_path_;
    bool is_recording_;
};
2.6 alarm_manager.cpp
#include "alarm_manager.h"
#include "logger.h"
#include <fstream>
#include <filesystem>
#include <chrono>
#include <thread>
#include <gst/gst.h>

namespace fs = std::filesystem;

AlarmManager::AlarmManager(const std::string& alarm_log_path)
    : alarm_log_path_(alarm_log_path) ,is_recording_(false) {
    fs::create_directories(alarm_log_path);
}

void AlarmManager::handleAlarm(const CameraConfig& config,
                               const std::vector<TritonInference::Detection>& detections) {

    // 检查报警条件
    bool should_alarm = checkAlarmCondition(config, detections);
    if (!should_alarm) return;

    // 生成报警时间戳
    auto now = std::chrono::system_clock::now();
    auto timestamp = std::chrono::system_clock::to_time_t(now);

    // 创建月份目录
    std::string month_dir = createMonthDirectory();

    // 保存报警图片
    std::string image_path = month_dir + "/" + config.name + "_" +
                            std::to_string(timestamp) + ".jpg";
    // 保存图片的逻辑需要在FrameProcessor中实现，这里假设已经保存

    // 开始录制报警视频
    std::string video_path = month_dir + "/" + config.name + "_" +
                            std::to_string(timestamp) + ".mp4";
    startRecording(config, video_path);

    // 记录报警信息
    recordAlarm(config, image_path, video_path);
}

bool AlarmManager::checkAlarmCondition(
    const CameraConfig& config,
    const std::vector<TritonInference::Detection>& detections) {
    
    // 根据配置文件中的报警策略检查是否需要报警
    for (const auto& det : detections) {
        auto it = config.alarm_strategies.find(det.model_name);
        if (it != config.alarm_strategies.end()) {
            // 根据策略进行判断，这里简单示例
            if (det.model_name == "peoplecarboat_detector" && det.class_id == 0) {
                int person_count = std::count_if(detections.begin(), detections.end(),
                    [&](const auto& d) { return d.model_name == "peoplecarboat_detector" && d.class_id == 0; });
                if (person_count >= 1) return true;
            } else if (det.model_name == "peoplecarboat_detector"  && det.class_id ==13) {
                return true; // 只要检测到船只就报警
            }
            // 其他策略...
        }
    }

    return false;
}

void AlarmManager::startRecording(const CameraConfig& config, 
                                  const std::string& video_path) {
    // 使用更完善的 GStreamer 管道配置
    if (is_recording_)
       return;

    is_recording_ = true;
    std::string pipeline_str = 
        "rtspsrc location=" + config.rtsp_url + " protocols=tcp latency=500 ! "
        "rtph264depay ! h264parse ! "
        "mp4mux faststart=true fragment-duration=1000 ! "  // 添加 faststart 和 fragment-duration 配置
        "filesink location=" + video_path + " sync=false";

    GError* error = nullptr;
    GstElement* pipeline = gst_parse_launch(pipeline_str.c_str(), &error);
    
    if (error) {
        LOG_ERROR("Failed to create recording pipeline: " + std::string(error->message));
        g_error_free(error);
        is_recording_ = false;
        return;
    }

    // 设置录制时长为10秒
    gst_element_set_state(pipeline, GST_STATE_PLAYING);
    
    // 等待pipeline完全启动
    GstState state;
    GstStateChangeReturn ret = gst_element_get_state(pipeline, &state, nullptr, GST_CLOCK_TIME_NONE);
    if (ret == GST_STATE_CHANGE_FAILURE) {
        LOG_ERROR("Failed to start recording pipeline");
        gst_object_unref(pipeline);
        is_recording_ = false;
        return;
    }

    std::this_thread::sleep_for(std::chrono::seconds(10));
    
    // 优雅地停止pipeline
    gst_element_send_event(pipeline, gst_event_new_eos());
    gst_element_set_state(pipeline, GST_STATE_NULL);
    
    gst_object_unref(pipeline);
    is_recording_ = false;
}

void AlarmManager::recordAlarm(const CameraConfig& config,
                               const std::string& image_path,
                               const std::string& video_path) {
    std::ofstream log_file(alarm_log_path_ + "/alarm_log.txt", 
                          std::ios::app);
    
    if (log_file.is_open()) {
        auto now = std::chrono::system_clock::now();
        auto timestamp = std::chrono::system_clock::to_time_t(now);
        
        log_file << "时间: " << std::ctime(&timestamp)
                << "摄像头: " << config.name << "\n"
                << "报警图片: " << image_path << "\n"
                << "报警视频: " << video_path << "\n"
                << "-------------------\n";
        
        log_file.close();
    }
}

std::string AlarmManager::createMonthDirectory() {
    auto now = std::chrono::system_clock::now();
    auto time = std::chrono::system_clock::to_time_t(now);
    std::tm* ltm = std::localtime(&time);
    
    std::string month_dir = alarm_log_path_ + "/" + 
                           std::to_string(1900 + ltm->tm_year) + "_" +
                           std::to_string(1 + ltm->tm_mon);
    
    fs::create_directories(month_dir);
    return month_dir;
}
2.7 triton_inference.h
#pragma once
#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <filesystem>
#include "http_client.h"

namespace tc = triton::client;
class TritonInference {
public:
    TritonInference(const std::string& url, const std::vector<std::string>& model_names);

    struct Detection {
        cv::Rect box;
        float confidence;
        int class_id;
        std::string model_name;
    };

    std::vector<Detection> infer(const cv::Mat& image);

private:
    std::unique_ptr<tc::InferenceServerHttpClient> triton_client_;
    std::vector<std::string> model_names_;
    std::string input_name_;
    std::string output_name_;
    int input_h_;
    int input_w_;
    std::vector<std::string> class_names_;

    std::tuple<cv::Mat, float, cv::Point2f> preprocess(const cv::Mat& image);
    std::vector<float> prepare_input(const cv::Mat& image);
    std::vector<Detection> postprocess(const float* output_data, size_t output_size, float scale_factor, const cv::Point2f& offset, const cv::Size& original_size, const std::string& model_name);
};
2.8 triton_inference.cpp
#include "triton_inference.h"
#include "logger.h"

TritonInference::TritonInference(const std::string &url, const std::vector<std::string> &model_names)
    : model_names_(model_names)
{
    // 创建HTTP客户端
    tc::Error err = tc::InferenceServerHttpClient::Create(
        &triton_client_, url, false);
    if (!err.IsOk())
    {
        throw std::runtime_error("Failed to create client: " + err.Message());
    }

    input_name_ = "images";
    output_name_ = "output0";
    input_h_ = 640;
    input_w_ = 640;

    // 初始化类别名称
    class_names_ = {"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat",
                    "traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat",
                    "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack",
                    "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball",
                    "kite", "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket",
                    "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
                    "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair",
                    "couch", "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse",
                    "remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator",
                    "book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush"}; // 根据实际类别设置
}

std::vector<TritonInference::Detection> TritonInference::infer(const cv::Mat &image)
{
    if (image.empty())
    {
        throw std::runtime_error("Invalid image");
    }

    // 预处理
    cv::Mat preprocessed;
    float scale_factor;
    cv::Point2f offset;
    std::tie(preprocessed, scale_factor, offset) = preprocess(image);

    // 准备输入数据
    std::vector<float> input_data = prepare_input(preprocessed);

    // 创建输入tensor
    std::vector<int64_t> input_shape = {1, 3, input_h_, input_w_};

    std::vector<TritonInference::Detection> all_detections;

    for (const auto &model_name : model_names_)
    {
        std::cout << "infer:for===1 " << std::endl;
        tc::InferInput *input;
        tc::Error err = tc::InferInput::Create(&input, input_name_, input_shape, "FP32");
        if (!err.IsOk())
        {
            LOG_ERROR("Failed to create input: " + err.Message());
            continue;
        }
        std::shared_ptr<tc::InferInput> input_ptr(input);

        // 设置输入数据
        err = input_ptr->AppendRaw(
            reinterpret_cast<uint8_t *>(input_data.data()),
            input_data.size() * sizeof(float));
        if (!err.IsOk())
        {
            LOG_ERROR("Failed to set input data: " + err.Message());
            continue;
        }

        // 创建输出
        tc::InferRequestedOutput *output;
        err = tc::InferRequestedOutput::Create(&output, output_name_);
        if (!err.IsOk())
        {
            LOG_ERROR("Failed to create output: " + err.Message());
            continue;
        }
        std::shared_ptr<tc::InferRequestedOutput> output_ptr(output);

        // 设置推理选项
        tc::InferOptions options(model_name);
        options.model_version_ = "1";

        // 执行推理
        std::vector<tc::InferInput *> inputs = {input_ptr.get()};
        std::vector<const tc::InferRequestedOutput *> outputs = {output_ptr.get()};
        tc::InferResult *result;

        err = triton_client_->Infer(&result, options, inputs, outputs);
        if (!err.IsOk())
        {
            LOG_ERROR("Failed to run inference: " + err.Message());
            continue;
        }
        std::shared_ptr<tc::InferResult> result_ptr(result);

        // 获取输出数据
        const uint8_t *output_data;
        size_t output_byte_size;
        err = result_ptr->RawData(output_name_, &output_data, &output_byte_size);
        if (!err.IsOk())
        {
            LOG_ERROR("Failed to get output data: " + err.Message());
            continue;
        }

        // 后处理
        std::vector<Detection> detections = postprocess(
            reinterpret_cast<const float *>(output_data),
            output_byte_size / sizeof(float),
            scale_factor,
            offset,
            image.size(),
            model_name);

        all_detections.insert(all_detections.end(), detections.begin(), detections.end());
    }

    return all_detections;
}

std::tuple<cv::Mat, float, cv::Point2f> TritonInference::preprocess(const cv::Mat &image)
{
    float ratio = std::min(
        static_cast<float>(input_w_) / image.cols,
        static_cast<float>(input_h_) / image.rows);

    int new_width = static_cast<int>(image.cols * ratio);
    int new_height = static_cast<int>(image.rows * ratio);

    cv::Mat resized;
    cv::resize(image, resized, cv::Size(new_width, new_height));

    cv::Mat canvas = cv::Mat::zeros(input_h_, input_w_, CV_8UC3);
    cv::Point2f offset(
        (input_w_ - new_width) / 2.0f,
        (input_h_ - new_height) / 2.0f);

    resized.copyTo(canvas(cv::Rect(
        offset.x, offset.y, new_width, new_height)));

    return {canvas, ratio, offset};
}

std::vector<float> TritonInference::prepare_input(const cv::Mat &image)
{
    cv::Mat blob;
    cv::dnn::blobFromImage(image, blob, 1.0 / 255.0,
                           cv::Size(input_w_, input_h_),
                           cv::Scalar(0, 0, 0), true, false, CV_32F);

    std::vector<float> input_data(blob.ptr<float>(),
                                  blob.ptr<float>() + blob.total());
    return input_data;
}

// ... 前面的代码保持不变 ...

std::vector<TritonInference::Detection> TritonInference::postprocess(
    const float *output_data,
    size_t output_size,
    float scale_factor,
    const cv::Point2f &offset,
    const cv::Size &original_size,
    const std::string &model_name) // 添加缺失的 model_name 参数
{
    const int num_classes = 80;
    const int num_anchors = 8400;
    std::vector<Detection> detections;

    // 重新组织输出数据为 [num_anchors, num_classes + 4] 格式
    std::vector<std::vector<float>> output_reshaped(num_anchors,
                                                    std::vector<float>(num_classes + 4));
    for (int i = 0; i < num_anchors; ++i)
    {
        for (int j = 0; j < num_classes + 4; ++j)
        {
            output_reshaped[i][j] = output_data[j * num_anchors + i];
        }
    }

    // 处理每个候选框
    for (int i = 0; i < num_anchors; ++i)
    {
        const auto &anchor_data = output_reshaped[i];

        // 获取类别得分
        float max_conf = 0;
        int class_id = -1;
        for (int j = 4; j < num_classes + 4; ++j)
        {
            if (anchor_data[j] > max_conf)
            {
                max_conf = anchor_data[j];
                class_id = j - 4;
            }
        }

        // 应用置信度阈值
        if (max_conf > 0.25f && class_id >= 0)
        {
            // 解析边界框坐标
            float cx = anchor_data[0];
            float cy = anchor_data[1];
            float w = anchor_data[2];
            float h = anchor_data[3];

            // 转换为左上角和右下角坐标
            float x1 = (cx - w / 2 - offset.x) / scale_factor;
            float y1 = (cy - h / 2 - offset.y) / scale_factor;
            float x2 = (cx + w / 2 - offset.x) / scale_factor;
            float y2 = (cy + h / 2 - offset.y) / scale_factor;

            // 确保坐标在图像范围内
            x1 = std::max(0.0f, std::min(x1, static_cast<float>(original_size.width)));
            y1 = std::max(0.0f, std::min(y1, static_cast<float>(original_size.height)));
            x2 = std::max(0.0f, std::min(x2, static_cast<float>(original_size.width)));
            y2 = std::max(0.0f, std::min(y2, static_cast<float>(original_size.height)));

            Detection det;
            det.box = cv::Rect(x1, y1, x2 - x1, y2 - y1);
            det.confidence = max_conf;
            det.class_id = class_id;
            det.model_name = model_name; // 设置模型名称
            detections.push_back(det);
        }
    }

    // 执行NMS
    std::vector<cv::Rect> boxes;
    std::vector<float> scores;
    std::vector<int> class_ids;
    for (const auto &det : detections)
    {
        boxes.push_back(det.box);
        scores.push_back(det.confidence);
        class_ids.push_back(det.class_id);
    }

    std::vector<int> indices;
    cv::dnn::NMSBoxes(boxes, scores, 0.25f, 0.45f, indices);

    // 保留NMS后的检测框
    std::vector<Detection> final_detections;
    for (int idx : indices)
    {
        final_detections.push_back(detections[idx]);
    }

    return final_detections;
}

// 其他方法实现（预处理、后处理等）需要根据实际模型进行编写s
2.9 frame_processor.h
#pragma once
#include <string>
#include <memory>
#include <nlohmann/json.hpp>
#include "triton_inference.h"
#include "config_manager.h"
#include "alarm_manager.h"
#include <opencv2/opencv.hpp>

class FrameProcessor {
public:
    FrameProcessor(const std::string& save_path, const CameraConfig& config, std::shared_ptr<AlarmManager> alarm_manager);
    void processFrame(const cv::Mat& frame);
    void sendAlarmToUpperLayer(const nlohmann::json& alarm_json);
    void printDetectionResults();

private:
    void saveFrame(const cv::Mat& frame);
    void cleanOldFrames();

   
    TritonInference triton_client_;  
    std::shared_ptr<AlarmManager> alarm_manager_;  
    CameraConfig config_; 
    std::string save_path_;
};
2.10 frame_processor.cpp
#include "frame_processor.h"
#include "logger.h"
#include <filesystem>
#include <chrono>
#include <ctime>

namespace fs = std::filesystem;

FrameProcessor::FrameProcessor(const std::string &save_path, const CameraConfig &config, std::shared_ptr<AlarmManager> alarm_manager)
    : save_path_(save_path), config_(config), alarm_manager_(alarm_manager), triton_client_("192.168.20.95:9000", config.algorithms)
{
    std::cout << "constuct FrameProcessor: triton_client_" << std::endl;
    fs::create_directories(save_path_);
}

void FrameProcessor::processFrame(const cv::Mat &frame)
{
    // 保存原始帧
    //saveFrame(frame);

    // 清理旧文件
    cleanOldFrames();

    // 调用Triton进行推理
    try
    {
        auto detections = triton_client_.infer(frame);
        
        //std::cout << "Detection Results:" << std::endl;
        printDetectionResults();
        for (const auto &det : detections)
        {
            std::cout << "Class: " << det.class_id
                      << ", Confidence: " << det.confidence
                      << ", Box: [" << det.box.x << ", " << det.box.y << ", "
                      << det.box.width << ", " << det.box.height << "]" << std::endl;
        }

        // 处理检测结果
        if (!detections.empty())
        {
            // 生成报警信息
            // nlohmann::json alarm_info = {
            //     {"camera_name", config_.name},
            //     {"timestamp", std::chrono::system_clock::now().time_since_epoch().count()},
            //     {"detections", nlohmann::json::array()}};

            // for (const auto &det : detections)
            // {
            //     alarm_info["detections"].push_back({{"model_name", det.model_name},
            //                                         {"class_id", det.class_id},
            //                                         {"confidence", det.confidence},
            //                                         {"box", {{"x", det.box.x}, {"y", det.box.y}, {"width", det.box.width}, {"height", det.box.height}}}});
            // }

            // 发送报警信息到报警管理器
            alarm_manager_->handleAlarm(config_, detections);

            // // 发送报警信息到上层应用
            // sendAlarmToUpperLayer(alarm_info);
        }
    }
    catch (const std::exception &e)
    {
        LOG_ERROR("Failed to process frame for camera " + config_.name + ": " + e.what());
    }
}

void FrameProcessor::printDetectionResults() {
    // 获取当前时间点
    auto now = std::chrono::system_clock::now();

    // 将时间点转换为时间戳
    std::time_t now_c = std::chrono::system_clock::to_time_t(now);

    // 将时间戳格式化为字符串
    char buffer[80];
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", std::localtime(&now_c));

    // 打印检测结果和当前时间
    std::cout << "Detection Results at " << buffer << ":" << std::endl;
}

void FrameProcessor::sendAlarmToUpperLayer(const nlohmann::json &alarm_json)
{
    // 实现发送报警信息的逻辑，比如通过HTTP POST发送到上层Java应用
    std::cout << "Sending alarm: " << alarm_json.dump() << std::endl;
}

void FrameProcessor::saveFrame(const cv::Mat &frame)
{
    auto now = std::chrono::system_clock::now();
    auto timestamp = std::chrono::system_clock::to_time_t(now);

    std::string filename = save_path_ + "/" + config_.name + "_" +
                           std::to_string(timestamp) + ".jpg";

    cv::imwrite(filename, frame);
}

void FrameProcessor::cleanOldFrames()
{
    const int MAX_FILES = 1000; // 限制最大文件数
    const int MAX_AGE_MINUTES = 10;
    auto now = fs::file_time_type::clock::now();

    std::vector<fs::path> files;
    for (const auto& entry : fs::directory_iterator(save_path_)) {
        files.push_back(entry.path());
    }

    // 按修改时间排序
    std::sort(files.begin(), files.end(),
        [](const fs::path& a, const fs::path& b) {
            return fs::last_write_time(a) < fs::last_write_time(b);
        });

    // 删除超出数量限制的文件
    while (files.size() > MAX_FILES) {
        fs::remove(files.front());
        files.erase(files.begin());
    }

    // 删除过期文件
    for (const auto& file : files) {
        auto last_write_time = fs::last_write_time(file);
        auto duration = std::chrono::duration_cast<std::chrono::minutes>(
            now - last_write_time);
        if (duration.count() > MAX_AGE_MINUTES) {
            fs::remove(file);
        }
    }
}

2.11 logger.h
#pragma once
#include <string>
#include <fstream>
#include <mutex>

enum class LogLevel {
    DEBUG,
    INFO,
    WARNING,
    ERROR
};

class Logger {
public:
    static void init(const std::string& log_file);
    static void log(LogLevel level, const std::string& message);

    static void debug(const std::string& message) {
        log(LogLevel::DEBUG, message);
    }
    
    static void info(const std::string& message) {
        log(LogLevel::INFO, message);
    }
    
    static void warning(const std::string& message) {
        log(LogLevel::WARNING, message);
    }
    
    static void error(const std::string& message) {
        log(LogLevel::ERROR, message);
    }

private:
    static std::ofstream log_file_;
    static std::mutex mutex_;
    static std::string getTimestamp();
    static std::string getLevelString(LogLevel level);
};

#define LOG_DEBUG(msg) Logger::debug(msg)
#define LOG_INFO(msg) Logger::info(msg)
#define LOG_WARNING(msg) Logger::warning(msg)
#define LOG_ERROR(msg) Logger::error(msg)
2.12 logger.cpp
#include "logger.h"
#include <chrono>
#include <iomanip>
#include <iostream>

std::ofstream Logger::log_file_;
std::mutex Logger::mutex_;

void Logger::init(const std::string& log_file) {
    std::lock_guard<std::mutex> lock(mutex_);
    log_file_.open(log_file, std::ios::app);
}

void Logger::log(LogLevel level, const std::string& message) {
    std::lock_guard<std::mutex> lock(mutex_);
    
    std::string log_message = getTimestamp() + " [" + 
                             getLevelString(level) + "] " + 
                             message + "\n";
    
    // 输出到控制台
    std::cout << log_message;
    
    // 写入日志文件
    if (log_file_.is_open()) {
        log_file_ << log_message;
        log_file_.flush();
    }
}

std::string Logger::getTimestamp() {
    auto now = std::chrono::system_clock::now();
    auto time = std::chrono::system_clock::to_time_t(now);
    std::stringstream ss;
    ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S");
    return ss.str();
}

std::string Logger::getLevelString(LogLevel level) {
    switch (level) {
        case LogLevel::DEBUG:   return "DEBUG";
        case LogLevel::INFO:    return "INFO";
        case LogLevel::WARNING: return "WARNING";
        case LogLevel::ERROR:   return "ERROR";
        default:               return "UNKNOWN";
    }
}
2.13 frame_processor.cpp
#include "frame_processor.h"
#include "logger.h"
#include <filesystem>
#include <chrono>
#include <ctime>

namespace fs = std::filesystem;

FrameProcessor::FrameProcessor(const std::string &save_path, const CameraConfig &config, std::shared_ptr<AlarmManager> alarm_manager)
    : save_path_(save_path), config_(config), alarm_manager_(alarm_manager), triton_client_("192.168.20.95:9000", config.algorithms)
{
    std::cout << "constuct FrameProcessor: triton_client_" << std::endl;
    fs::create_directories(save_path_);
}

void FrameProcessor::processFrame(const cv::Mat &frame)
{
    // 保存原始帧
    //saveFrame(frame);

    // 清理旧文件
    cleanOldFrames();

    // 调用Triton进行推理
    try
    {
        auto detections = triton_client_.infer(frame);
        
        //std::cout << "Detection Results:" << std::endl;
        printDetectionResults();
        for (const auto &det : detections)
        {
            std::cout << "Class: " << det.class_id
                      << ", Confidence: " << det.confidence
                      << ", Box: [" << det.box.x << ", " << det.box.y << ", "
                      << det.box.width << ", " << det.box.height << "]" << std::endl;
        }

        // 处理检测结果
        if (!detections.empty())
        {
            // 生成报警信息
            // nlohmann::json alarm_info = {
            //     {"camera_name", config_.name},
            //     {"timestamp", std::chrono::system_clock::now().time_since_epoch().count()},
            //     {"detections", nlohmann::json::array()}};

            // for (const auto &det : detections)
            // {
            //     alarm_info["detections"].push_back({{"model_name", det.model_name},
            //                                         {"class_id", det.class_id},
            //                                         {"confidence", det.confidence},
            //                                         {"box", {{"x", det.box.x}, {"y", det.box.y}, {"width", det.box.width}, {"height", det.box.height}}}});
            // }

            // 发送报警信息到报警管理器
            alarm_manager_->handleAlarm(config_, detections);

            // // 发送报警信息到上层应用
            // sendAlarmToUpperLayer(alarm_info);
        }
    }
    catch (const std::exception &e)
    {
        LOG_ERROR("Failed to process frame for camera " + config_.name + ": " + e.what());
    }
}

void FrameProcessor::printDetectionResults() {
    // 获取当前时间点
    auto now = std::chrono::system_clock::now();

    // 将时间点转换为时间戳
    std::time_t now_c = std::chrono::system_clock::to_time_t(now);

    // 将时间戳格式化为字符串
    char buffer[80];
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", std::localtime(&now_c));

    // 打印检测结果和当前时间
    std::cout << "Detection Results at " << buffer << ":" << std::endl;
}

void FrameProcessor::sendAlarmToUpperLayer(const nlohmann::json &alarm_json)
{
    // 实现发送报警信息的逻辑，比如通过HTTP POST发送到上层Java应用
    std::cout << "Sending alarm: " << alarm_json.dump() << std::endl;
}

void FrameProcessor::saveFrame(const cv::Mat &frame)
{
    auto now = std::chrono::system_clock::now();
    auto timestamp = std::chrono::system_clock::to_time_t(now);

    std::string filename = save_path_ + "/" + config_.name + "_" +
                           std::to_string(timestamp) + ".jpg";

    cv::imwrite(filename, frame);
}

void FrameProcessor::cleanOldFrames()
{
    const int MAX_FILES = 1000; // 限制最大文件数
    const int MAX_AGE_MINUTES = 10;
    auto now = fs::file_time_type::clock::now();

    std::vector<fs::path> files;
    for (const auto& entry : fs::directory_iterator(save_path_)) {
        files.push_back(entry.path());
    }

    // 按修改时间排序
    std::sort(files.begin(), files.end(),
        [](const fs::path& a, const fs::path& b) {
            return fs::last_write_time(a) < fs::last_write_time(b);
        });

    // 删除超出数量限制的文件
    while (files.size() > MAX_FILES) {
        fs::remove(files.front());
        files.erase(files.begin());
    }

    // 删除过期文件
    for (const auto& file : files) {
        auto last_write_time = fs::last_write_time(file);
        auto duration = std::chrono::duration_cast<std::chrono::minutes>(
            now - last_write_time);
        if (duration.count() > MAX_AGE_MINUTES) {
            fs::remove(file);
        }
    }
}

2.14 main.cpp
#include <iostream>
#include <thread>
#include <vector>
#include "config_manager.h"
#include "video_capture.h"
#include "logger.h"
#include "alarm_manager.h"

int main() {
    Logger::init("video_analysis_service.log");
    LOG_INFO("Starting Video Analysis Service...");

    // 初始化 GStreamer
    gst_init(nullptr, nullptr);

    // 加载配置
    if (!ConfigManager::getInstance().loadConfig("../config/camera_config.ini")) {
        LOG_ERROR("Failed to load configuration");
        return -1;
    }
    LOG_INFO("Configuration loaded successfully");

    // 初始化组件
    std::vector<std::unique_ptr<VideoCapture>> video_captures;

    // 创建一个共享的报警管理器实例
    auto alarm_manager = std::make_shared<AlarmManager>("./alarm_logs");

    // 启动视频捕获
    for (const auto& config : ConfigManager::getInstance().getCameraConfigs()) {
        auto capture = std::make_unique<VideoCapture>(config);

        // 创建带有自己TritonInference客户端的FrameProcessor
        auto frame_processor = std::make_shared<FrameProcessor>("./frames", config, alarm_manager);

        // 设置帧处理器
        capture->setFrameProcessor(frame_processor);

        if (!capture->start()) {
            LOG_ERROR("Failed to start video capture for camera: " + config.name);
            continue;
        }
        video_captures.push_back(std::move(capture));
        LOG_INFO("Started video capture for camera: " + config.name);
    }

    // 主循环
    while (true) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    gst_deinit();
    return 0;
}
2.15.配置文件内容(camera_config.ini)
[Camera1]
name=room1
rtsp_url=rtsp://117.71.99.41:5544/live/43130100001320000006_43130100001320000006?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVSUQiOjAsIlVzZXJuYW1lIjoiNDMxMzAxMDAwMDEzMjAwMDAwMDZfNDMxMzAxMDAwMDEzMjAwMDAwMDYiLCJHcm91cElEIjowLCJpc3MiOiJ4eEBnb2xhbmcuc3BhY2UiLCJleHAiOjE3Mzc3MTI5MDMsImlhdCI6MTczMTQ5MjEwM30.NT9CkDrZVLRZGjxX_DJiCXH0yvCN64D01gr1eXDJHbI&expired=20250124180143algorithms=peoplecarboat_detector
frame_interval=5000
alarm_strategy=peoplecarboat_detector:boat_present=true,peoplecarboat_detector:illegal_fishing=true
alarm_storage_path=/data/alarms/camera1

[Camera2]
name=room2
rtsp_url=rtsp://117.71.99.41:5544/live/43130100001320000002_43130100001320000002?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVSUQiOjAsIlVzZXJuYW1lIjoiNDMxMzAxMDAwMDEzMjAwMDAwMDJfNDMxMzAxMDAwMDEzMjAwMDAwMDIiLCJHcm91cElEIjowLCJpc3MiOiJ4eEBnb2xhbmcuc3BhY2UiLCJleHAiOjE3Mzc3MTI5NDIsImlhdCI6MTczMTQ5MjE0Mn0.VuU_FjJZ0JqevQt3PJjKMhsJjOn4-WU75xf5XYut5as&expired=20250124180222algorithms=peoplecarboat_detector
frame_interval=5000
alarm_strategy=peoplecarboat_detector:person_count>2,peoplecarboat_detector:vehicle_present=true
alarm_storage_path=/data/alarms/camera2


2.16.makefile文件内容(CMakeLists.txt)
cmake_minimum_required(VERSION 3.10)
project(algorithm_analysis_service)

# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 查找必要的包
find_package(OpenCV REQUIRED)
find_package(CURL REQUIRED)
find_package(PkgConfig REQUIRED)
find_package(ZLIB REQUIRED)
pkg_check_modules(GST REQUIRED gstreamer-1.0 gstreamer-app-1.0)

# 设置Triton Client的路径
set(TRITON_CLIENT_PATH "/home/chen/data/client-main/build/install/client")

# 添加头文件路径
include_directories(
    ${PROJECT_SOURCE_DIR}/include
    ${TRITON_CLIENT_PATH}/include
    ${OpenCV_INCLUDE_DIRS}
    ${GST_INCLUDE_DIRS}
    ${CURL_INCLUDE_DIRS}
)

# 添加源文件
set(SOURCES
    src/main.cpp
    src/config_manager.cpp
    src/video_capture.cpp
    src/frame_processor.cpp
    src/alarm_manager.cpp
    src/logger.cpp
    src/triton_inference.cpp
)

# 添加可执行文件
add_executable(${PROJECT_NAME} ${SOURCES})

# 链接库
link_directories(${TRITON_CLIENT_PATH}/lib)

# 链接库
target_link_libraries(${PROJECT_NAME}
    PRIVATE
    ${OpenCV_LIBS}
    ${GST_LIBRARIES}
    ${CURL_LIBRARIES}
    httpclient_static
    grpcclient_static
    curl
    ZLIB::ZLIB
    pthread
    stdc++fs
)

# 设置编译选项
target_compile_options(${PROJECT_NAME}
    PRIVATE
    -Wall
    -Wextra
    -O2
)
】
"""
(base) chen@chen-Precision-3660:~/data/algorithm_analysis_service/build$ top
top - 13:54:41 up 24 days,  1:52,  3 users,  load average: 0.19, 0.41, 0.46
任务: 561 total,   1 running, 560 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.9 us,  0.2 sy,  1.3 ni, 97.5 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :  63997.0 total,  50295.2 free,   8026.4 used,   5675.4 buff/cache
MiB Swap:   2048.0 total,    288.7 free,   1759.3 used.  55239.3 avail Mem 

 进程号 USER      PR  NI    VIRT    RES    SHR    %CPU  %MEM     TIME+ COMMAND                                                                                             
 733517 chen      20   0 2119616 119128  46340 S  27.8   0.2  25:18.65 algorithm_analy                                                                                     
 735998 chen      39  19  138484 108704  83072 S  16.2   0.2   0:00.49 apt-check                                                                                           
  14284 chen      20   0 3917916 473324 120836 S   1.3   0.7 420:10.47 firefox                                                                                             
  14541 chen      20   0 2656968 197172  27348 S   1.3   0.3 590:01.60 Isolated Web Co                                                                                     
 593070 chen      20   0   61.9g 984744  33892 S   1.3   1.5  63:15.70 node                                                                                                
  14544 chen      20   0 2714476 191828  31760 S   1.0   0.3 428:21.66 Isolated Web Co                                                                                     
 593027 chen      20   0   11.3g  84216  26724 S   0.3   0.1   3:33.25 node                                                                                                
 714725 chen      20   0   21056   4508   3296 R   0.3   0.0   0:33.48 top                                                                                                 
      1 root      20   0  171612   8740   4532 S   0.0   0.0   0:25.76 systemd                                                                                             
      2 root      20   0       0      0      0 S   0.0   0.0   0:00.40 kthreadd                                                                                            
      3 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 rcu_gp                                                                                              
      4 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 rcu_par_gp                                                                                          
      5 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 slub_flushwq                                                                                        
      6 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 netns                                                                                               
      8 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 kworker/0:0H-events_highpri                                                                         
     10 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 mm_percpu_wq                    
"""