针对下面【】的工程代码，运行后的结果如下面的"""   """内的所出现的错误，帮我分析一下问题原因，如有那个文件需要修改，请最后请给出修改后的完整代码。用中文回复。
【
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>
#include <iomanip>

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设置唯一名称

    // 计算帧率：每隔 frame_interval 毫秒获取一帧
    double interval_seconds = config_.frame_interval / 1000.0;
    int numerator = 1;
    int denominator = static_cast<int>(interval_seconds);

    if (denominator == 0)
    {
        denominator = 1;
    }

    // 使用硬件解码器，例如 vaapih264dec，如果不可用，可以尝试其他硬件解码器avdec_h264
    std::string decoder = "avdec_h264"; // 根据您的系统调整硬件解码器

    // 构建GStreamer管道，在解码器之后使用 videorate 来降低帧率
    std::ostringstream pipeline_ss;
    pipeline_ss << "rtspsrc location=" << config_.rtsp_url << " protocols=tcp latency=300 ! "
                << "rtph264depay ! h264parse ! "
                << decoder << " ! "
                << "videorate ! video/x-raw,framerate=" << numerator << "/" << denominator << " ! "
                << "videoconvert ! appsink name=" << sink_name << " max-buffers=1 drop=true";

    std::string pipeline_str = pipeline_ss.str();

    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;
    }

    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);

    // 处理GStreamer的bus消息，监听错误和EOS
    GstBus *bus = gst_element_get_bus(pipeline_);
    gst_bus_add_watch(bus, (GstBusFunc)onBusMessage, this);
    gst_object_unref(bus);

    // 等待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;
    }
    
    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"))
        {
            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;
        }

        // 处理帧
        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;
    }
}

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);
        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);
        self->reconnect();
        g_clear_error(&err);
        g_free(debug_info);
        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
)
】
"""
(triton) (base) chen@chen-Precision-3660:~/data/algorithm_analysis_service/build$ export GST_DEBUG=3
(triton) (base) chen@chen-Precision-3660:~/data/algorithm_analysis_service/build$ ./algorithm_analysis_service
2024-11-17 20:30:41 [INFO] Starting Video Analysis Service...
2024-11-17 20:30:41 [INFO] Configuration loaded successfully
constuct FrameProcessor: triton_client_
0:00:03.260459854 776871 0x7f6a8c006520 FIXME               basesink gstbasesink.c:3246:gst_base_sink_default_event:<sink_Camera1> stream-start event without group-id. Consider implementing group-id handling in the upstream elements
2024-11-17 20:30:46 [ERROR] Pipeline failed to reach PLAYING state for camera Camera1
0:00:05.025354769 776871 0x56082329ed80 WARN                 rtspsrc gstrtspsrc.c:6326:gst_rtsp_src_receive_response:<rtspsrc0> receive interrupted
0:00:05.025375080 776871 0x56082329ed80 WARN                 rtspsrc gstrtspsrc.c:6424:gst_rtspsrc_try_send:<rtspsrc0> receive interrupted
0:00:05.025385756 776871 0x56082329ed80 WARN                 rtspsrc gstrtspsrc.c:8672:gst_rtspsrc_pause:<rtspsrc0> PAUSE interrupted
0:00:05.045582288 776871 0x56082329ed80 WARN                 rtspsrc gstrtspsrc.c:6385:gst_rtspsrc_try_send:<rtspsrc0> server closed connection
0:00:05.045616127 776871 0x56082329ed80 WARN                 rtspsrc gstrtspsrc.c:6421:gst_rtspsrc_try_send:<rtspsrc0> error: Could not receive message. (Received end-of-file)
0:00:05.045678442 776871 0x56082329ed80 WARN                 rtspsrc gstrtspsrc.c:8096:gst_rtspsrc_close:<rtspsrc0> error: Could not send message. (Received end-of-file)
2024-11-17 20:30:46 [ERROR] Failed to start video capture for camera: Camera1
constuct FrameProcessor: triton_client_
0:00:06.585416400 776871 0x7f6a8c006520 FIXME               basesink gstbasesink.c:3246:gst_base_sink_default_event:<sink_Camera2> stream-start event without group-id. Consider implementing group-id handling in the upstream elements
2024-11-17 20:30:51 [ERROR] Pipeline failed to reach PLAYING state for camera Camera2
0:00:10.053848479 776871 0x7f6a8c0f88c0 WARN                 rtspsrc gstrtspsrc.c:6326:gst_rtsp_src_receive_response:<rtspsrc1> receive interrupted
0:00:10.053874356 776871 0x7f6a8c0f88c0 WARN                 rtspsrc gstrtspsrc.c:6424:gst_rtspsrc_try_send:<rtspsrc1> receive interrupted
0:00:10.053882733 776871 0x7f6a8c0f88c0 WARN                 rtspsrc gstrtspsrc.c:8672:gst_rtspsrc_pause:<rtspsrc1> PAUSE interrupted
0:00:10.089053645 776871 0x7f6a8c0f88c0 WARN                 rtspsrc gstrtspsrc.c:6385:gst_rtspsrc_try_send:<rtspsrc1> server closed connection
0:00:10.089084363 776871 0x7f6a8c0f88c0 WARN                 rtspsrc gstrtspsrc.c:6421:gst_rtspsrc_try_send:<rtspsrc1> error: Could not receive message. (Received end-of-file)
0:00:10.089120815 776871 0x7f6a8c0f88c0 WARN                 rtspsrc gstrtspsrc.c:8096:gst_rtspsrc_close:<rtspsrc1> error: Could not send message. (Received end-of-file)
2024-11-17 20:30:51 [ERROR] Failed to start video capture for camera: Camera2
"""