修复了一个关闭程序时因为提前释放了全局变量导致SF的问题
This commit is contained in:
parent
b6315d1790
commit
0de78cd02e
|
|
@ -24,4 +24,6 @@ public:
|
||||||
* @param frame [in/out] 传入原始帧,模块应在此帧上直接绘制结果。
|
* @param frame [in/out] 传入原始帧,模块应在此帧上直接绘制结果。
|
||||||
*/
|
*/
|
||||||
virtual bool process(cv::Mat& frame) = 0;
|
virtual bool process(cv::Mat& frame) = 0;
|
||||||
|
|
||||||
|
virtual void stop() = 0;
|
||||||
};
|
};
|
||||||
|
|
@ -20,9 +20,6 @@ IntrusionModule::IntrusionModule(std::string model_path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// init() 函数: 从 video_service.cc 的 start() 移动而来
|
|
||||||
//
|
|
||||||
bool IntrusionModule::init() {
|
bool IntrusionModule::init() {
|
||||||
rknn_pool_ = std::make_unique<rknnPool<rkYolov5s, cv::Mat, detect_result_group_t>>(model_path_.c_str(), thread_num_);
|
rknn_pool_ = std::make_unique<rknnPool<rkYolov5s, cv::Mat, detect_result_group_t>>(model_path_.c_str(), thread_num_);
|
||||||
if (rknn_pool_->init() != 0) {
|
if (rknn_pool_->init() != 0) {
|
||||||
|
|
@ -33,22 +30,17 @@ bool IntrusionModule::init() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// process() 函数: 从 video_service.cc 的 processing_loop() 移动而来
|
|
||||||
//
|
|
||||||
bool IntrusionModule::process(cv::Mat& frame) {
|
bool IntrusionModule::process(cv::Mat& frame) {
|
||||||
if (frame.empty()) {
|
if (frame.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. 图像预处理 (来自)
|
|
||||||
cv::Mat model_input_image;
|
cv::Mat model_input_image;
|
||||||
cv::resize(frame, model_input_image, cv::Size(640, 640));
|
cv::resize(frame, model_input_image, cv::Size(640, 640));
|
||||||
if (!model_input_image.isContinuous()) {
|
if (!model_input_image.isContinuous()) {
|
||||||
model_input_image = model_input_image.clone();
|
model_input_image = model_input_image.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. RKNN 推理 (来自)
|
|
||||||
if (rknn_pool_->put(model_input_image) != 0) {
|
if (rknn_pool_->put(model_input_image) != 0) {
|
||||||
spdlog::error("[IntrusionModule] Failed to put frame into rknnPool.");
|
spdlog::error("[IntrusionModule] Failed to put frame into rknnPool.");
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -60,19 +52,14 @@ bool IntrusionModule::process(cv::Mat& frame) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 跟踪与报警 (来自)
|
|
||||||
this->update_tracker(detection_results, frame.size());
|
this->update_tracker(detection_results, frame.size());
|
||||||
|
|
||||||
// 4. 绘制结果 (来自)
|
|
||||||
this->draw_results(frame); // 直接在传入的 frame 上绘制
|
this->draw_results(frame); // 直接在传入的 frame 上绘制
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// 以下所有函数均从 video_service.cc 完整剪切而来
|
|
||||||
//
|
|
||||||
|
|
||||||
void IntrusionModule::trigger_alarm(int person_id, const cv::Rect& box) {
|
void IntrusionModule::trigger_alarm(int person_id, const cv::Rect& box) {
|
||||||
printf("[ALARM] Intrusion detected! Person ID: %d at location (%d, %d, %d, %d)\n",
|
printf("[ALARM] Intrusion detected! Person ID: %d at location (%d, %d, %d, %d)\n",
|
||||||
|
|
@ -88,12 +75,10 @@ double IntrusionModule::get_current_time_seconds() {
|
||||||
|
|
||||||
void IntrusionModule::update_tracker(detect_result_group_t &detect_result_group, const cv::Size& frame_size)
|
void IntrusionModule::update_tracker(detect_result_group_t &detect_result_group, const cv::Size& frame_size)
|
||||||
{
|
{
|
||||||
// 如果入侵区域无效,则设置为帧中心的 1/4 区域 (基于原始帧大小)
|
|
||||||
if (intrusion_zone_.width <= 0 || intrusion_zone_.height <= 0) {
|
if (intrusion_zone_.width <= 0 || intrusion_zone_.height <= 0) {
|
||||||
intrusion_zone_ = cv::Rect(frame_size.width / 4, frame_size.height / 4, frame_size.width / 2, frame_size.height / 2);
|
intrusion_zone_ = cv::Rect(frame_size.width / 4, frame_size.height / 4, frame_size.width / 2, frame_size.height / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 缩放比例计算 ---
|
|
||||||
const float model_input_width = 640.0f;
|
const float model_input_width = 640.0f;
|
||||||
const float model_input_height = 640.0f;
|
const float model_input_height = 640.0f;
|
||||||
float scale_x = (float)frame_size.width / model_input_width;
|
float scale_x = (float)frame_size.width / model_input_width;
|
||||||
|
|
@ -205,7 +190,7 @@ void IntrusionModule::update_tracker(detect_result_group_t &detect_result_group,
|
||||||
|
|
||||||
void IntrusionModule::draw_results(cv::Mat& frame)
|
void IntrusionModule::draw_results(cv::Mat& frame)
|
||||||
{
|
{
|
||||||
cv::rectangle(frame, this->intrusion_zone_, cv::Scalar(255, 255, 0), 2); // 黄色
|
cv::rectangle(frame, this->intrusion_zone_, cv::Scalar(255, 255, 0), 2);
|
||||||
|
|
||||||
for (auto const& [id, person] : this->tracked_persons_) {
|
for (auto const& [id, person] : this->tracked_persons_) {
|
||||||
cv::Scalar box_color = person.alarm_triggered ? cv::Scalar(0, 0, 255) : cv::Scalar(0, 255, 0);
|
cv::Scalar box_color = person.alarm_triggered ? cv::Scalar(0, 0, 255) : cv::Scalar(0, 255, 0);
|
||||||
|
|
@ -219,4 +204,13 @@ void IntrusionModule::draw_results(cv::Mat& frame)
|
||||||
cv::putText(frame, label, cv::Point(person.box.x, person.box.y - 10),
|
cv::putText(frame, label, cv::Point(person.box.x, person.box.y - 10),
|
||||||
cv::FONT_HERSHEY_SIMPLEX, 0.5, box_color, 2);
|
cv::FONT_HERSHEY_SIMPLEX, 0.5, box_color, 2);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
void IntrusionModule::stop() {
|
||||||
|
spdlog::info("Stopping IntrusionModule internal threads...");
|
||||||
|
|
||||||
|
if (rknn_pool_) {
|
||||||
|
rknn_pool_->stop(); // <-- 这会阻塞并等待 rknnPool 的所有线程退出
|
||||||
|
}
|
||||||
|
|
||||||
|
spdlog::info("IntrusionModule stopped.");
|
||||||
}
|
}
|
||||||
|
|
@ -40,18 +40,17 @@ public:
|
||||||
|
|
||||||
virtual ~IntrusionModule() = default;
|
virtual ~IntrusionModule() = default;
|
||||||
|
|
||||||
// --- 实现 IAnalysisModule 接口 ---
|
|
||||||
virtual bool init() override;
|
virtual bool init() override;
|
||||||
virtual bool process(cv::Mat& frame) override;
|
virtual bool process(cv::Mat& frame) override;
|
||||||
|
virtual void stop() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- 以下函数从 video_service.cc 移动到这里 ---
|
|
||||||
void update_tracker(detect_result_group_t &detect_result_group, const cv::Size& frame_size);
|
void update_tracker(detect_result_group_t &detect_result_group, const cv::Size& frame_size);
|
||||||
void draw_results(cv::Mat& frame);
|
void draw_results(cv::Mat& frame);
|
||||||
void trigger_alarm(int person_id, const cv::Rect& box);
|
void trigger_alarm(int person_id, const cv::Rect& box);
|
||||||
double get_current_time_seconds();
|
double get_current_time_seconds();
|
||||||
|
|
||||||
// --- 以下成员变量从 video_service.h 移动到这里 ---
|
|
||||||
std::string model_path_;
|
std::string model_path_;
|
||||||
int thread_num_;
|
int thread_num_;
|
||||||
std::unique_ptr<rknnPool<rkYolov5s, cv::Mat, detect_result_group_t>> rknn_pool_;
|
std::unique_ptr<rknnPool<rkYolov5s, cv::Mat, detect_result_group_t>> rknn_pool_;
|
||||||
|
|
|
||||||
|
|
@ -98,8 +98,18 @@ int readLines(const char *fileName, char *lines[], int max_line)
|
||||||
int loadLabelName(const char *locationFilename, char *label[])
|
int loadLabelName(const char *locationFilename, char *label[])
|
||||||
{
|
{
|
||||||
printf("loadLabelName %s\n", locationFilename);
|
printf("loadLabelName %s\n", locationFilename);
|
||||||
readLines(locationFilename, label, OBJ_CLASS_NUM);
|
int ret = readLines(locationFilename, label, OBJ_CLASS_NUM);
|
||||||
return 0;
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
printf("readLines failed!\n");
|
||||||
|
return -1; // <--- 返回错误
|
||||||
|
}
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
printf("No labels read from %s. File is empty or invalid.\n", locationFilename);
|
||||||
|
return -1; // <--- 返回错误
|
||||||
|
}
|
||||||
|
return 0; // 只有成功才返回 0
|
||||||
}
|
}
|
||||||
|
|
||||||
static float CalculateOverlap(float xmin0, float ymin0, float xmax0, float ymax0, float xmin1, float ymin1, float xmax1,
|
static float CalculateOverlap(float xmin0, float ymin0, float xmax0, float ymax0, float xmin1, float ymin1, float xmax1,
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,7 @@ detect_result_group_t rkYolov5s::infer(const cv::Mat &orig_img)
|
||||||
|
|
||||||
rkYolov5s::~rkYolov5s()
|
rkYolov5s::~rkYolov5s()
|
||||||
{
|
{
|
||||||
deinitPostProcess();
|
// deinitPostProcess();
|
||||||
|
|
||||||
ret = rknn_destroy(ctx);
|
ret = rknn_destroy(ctx);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,9 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <atomic>
|
||||||
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
// rknnModel模型类, inputType模型输入类型, outputType模型输出类型
|
|
||||||
template <typename rknnModel, typename inputType, typename outputType>
|
template <typename rknnModel, typename inputType, typename outputType>
|
||||||
class rknnPool
|
class rknnPool
|
||||||
{
|
{
|
||||||
|
|
@ -22,6 +23,8 @@ private:
|
||||||
std::queue<std::future<outputType>> futs;
|
std::queue<std::future<outputType>> futs;
|
||||||
std::vector<std::shared_ptr<rknnModel>> models;
|
std::vector<std::shared_ptr<rknnModel>> models;
|
||||||
|
|
||||||
|
std::atomic<bool> is_stopped{false};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int getModelId();
|
int getModelId();
|
||||||
|
|
||||||
|
|
@ -32,6 +35,9 @@ public:
|
||||||
int put(inputType inputData);
|
int put(inputType inputData);
|
||||||
// 获取推理结果/Get the results of your inference
|
// 获取推理结果/Get the results of your inference
|
||||||
int get(outputType &outputData);
|
int get(outputType &outputData);
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
~rknnPool();
|
~rknnPool();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -41,11 +47,13 @@ rknnPool<rknnModel, inputType, outputType>::rknnPool(const std::string modelPath
|
||||||
this->modelPath = modelPath;
|
this->modelPath = modelPath;
|
||||||
this->threadNum = threadNum;
|
this->threadNum = threadNum;
|
||||||
this->id = 0;
|
this->id = 0;
|
||||||
|
this->is_stopped = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename rknnModel, typename inputType, typename outputType>
|
template <typename rknnModel, typename inputType, typename outputType>
|
||||||
int rknnPool<rknnModel, inputType, outputType>::init()
|
int rknnPool<rknnModel, inputType, outputType>::init()
|
||||||
{
|
{
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this->pool = std::make_unique<dpool::ThreadPool>(this->threadNum);
|
this->pool = std::make_unique<dpool::ThreadPool>(this->threadNum);
|
||||||
|
|
@ -80,6 +88,10 @@ int rknnPool<rknnModel, inputType, outputType>::getModelId()
|
||||||
template <typename rknnModel, typename inputType, typename outputType>
|
template <typename rknnModel, typename inputType, typename outputType>
|
||||||
int rknnPool<rknnModel, inputType, outputType>::put(inputType inputData)
|
int rknnPool<rknnModel, inputType, outputType>::put(inputType inputData)
|
||||||
{
|
{
|
||||||
|
if (is_stopped) {
|
||||||
|
return -1; // Or handle as an error
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(queueMtx);
|
std::lock_guard<std::mutex> lock(queueMtx);
|
||||||
futs.push(pool->submit(&rknnModel::infer, models[this->getModelId()], inputData));
|
futs.push(pool->submit(&rknnModel::infer, models[this->getModelId()], inputData));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -88,22 +100,53 @@ int rknnPool<rknnModel, inputType, outputType>::put(inputType inputData)
|
||||||
template <typename rknnModel, typename inputType, typename outputType>
|
template <typename rknnModel, typename inputType, typename outputType>
|
||||||
int rknnPool<rknnModel, inputType, outputType>::get(outputType &outputData)
|
int rknnPool<rknnModel, inputType, outputType>::get(outputType &outputData)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(queueMtx);
|
std::future<outputType> future_to_get;
|
||||||
if(futs.empty() == true)
|
|
||||||
return 1;
|
{
|
||||||
outputData = futs.front().get();
|
std::lock_guard<std::mutex> lock(queueMtx);
|
||||||
futs.pop();
|
if (futs.empty() == true)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
future_to_get = std::move(futs.front());
|
||||||
|
futs.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
outputData = future_to_get.get();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename rknnModel, typename inputType, typename outputType>
|
||||||
|
void rknnPool<rknnModel, inputType, outputType>::stop()
|
||||||
|
{
|
||||||
|
|
||||||
|
spdlog::critical("!!! [RKNN_POOL_STOP_CALLED] Shutdown sequence initiated. !!!");
|
||||||
|
if (is_stopped.exchange(true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
std::future<outputType> future_to_get;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(queueMtx);
|
||||||
|
if (futs.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
future_to_get = std::move(futs.front());
|
||||||
|
futs.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
future_to_get.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.reset();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
template <typename rknnModel, typename inputType, typename outputType>
|
template <typename rknnModel, typename inputType, typename outputType>
|
||||||
rknnPool<rknnModel, inputType, outputType>::~rknnPool()
|
rknnPool<rknnModel, inputType, outputType>::~rknnPool()
|
||||||
{
|
{
|
||||||
while (!futs.empty())
|
stop();
|
||||||
{
|
|
||||||
outputType temp = futs.front().get();
|
|
||||||
futs.pop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -2,33 +2,17 @@
|
||||||
#include "video_service.h"
|
#include "video_service.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "opencv2/imgproc/imgproc.hpp"
|
#include "opencv2/imgproc/imgproc.hpp"
|
||||||
// #include "rknn/rkYolov5s.hpp" // <-- 移除
|
|
||||||
// #include "rknn/rknnPool.hpp" // <-- 移除
|
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
// #include <chrono> // <-- 移除 (已移至 IntrusionModule)
|
|
||||||
// #include <algorithm> // <-- 移除 (已移至 IntrusionModule)
|
|
||||||
|
|
||||||
//
|
|
||||||
// !!! 关键: trigger_alarm, get_current_time_seconds, update_tracker, draw_results
|
|
||||||
// !!! 所有这些函数 都已被剪切并移动到 IntrusionModule.cc
|
|
||||||
//
|
|
||||||
|
|
||||||
// 构造函数:修改为接收 module
|
|
||||||
VideoService::VideoService(std::unique_ptr<IAnalysisModule> module,
|
VideoService::VideoService(std::unique_ptr<IAnalysisModule> module,
|
||||||
std::string input_url,
|
std::string input_url,
|
||||||
std::string output_rtsp_url)
|
std::string output_rtsp_url)
|
||||||
: module_(std::move(module)), // <-- 关键:接收模块所有权
|
: module_(std::move(module)),
|
||||||
input_url_(input_url),
|
input_url_(input_url),
|
||||||
output_rtsp_url_(output_rtsp_url),
|
output_rtsp_url_(output_rtsp_url),
|
||||||
running_(false)
|
running_(false)
|
||||||
{
|
{
|
||||||
log_prefix_ = "[VideoService: " + input_url + "]";
|
log_prefix_ = "[VideoService: " + input_url + "]";
|
||||||
|
|
||||||
// !!! 移除所有AI相关的初始化 !!!
|
|
||||||
// next_track_id_ = 1;
|
|
||||||
// intrusion_time_threshold_ = 3.0;
|
|
||||||
// intrusion_zone_ = cv::Rect(0, 0, 0, 0);
|
|
||||||
|
|
||||||
spdlog::info("{} Created. Input: {}, Output: {}", log_prefix_, input_url_.c_str(), output_rtsp_url_.c_str());
|
spdlog::info("{} Created. Input: {}, Output: {}", log_prefix_, input_url_.c_str(), output_rtsp_url_.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,23 +24,18 @@ VideoService::~VideoService() {
|
||||||
|
|
||||||
|
|
||||||
bool VideoService::start() {
|
bool VideoService::start() {
|
||||||
// 1. (修改) 初始化AI模块
|
|
||||||
if (!module_ || !module_->init()) {
|
if (!module_ || !module_->init()) {
|
||||||
spdlog::error("{} Failed to initialize analysis module!", log_prefix_);
|
spdlog::error("{} Failed to initialize analysis module!", log_prefix_);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
spdlog::info("{} Analysis module initialized successfully.", log_prefix_);
|
spdlog::info("{} Analysis module initialized successfully.", log_prefix_);
|
||||||
|
|
||||||
// 2. (移除) RKNN Pool 初始化
|
|
||||||
// rknn_pool_ = std::make_unique<...>();
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// 3. (不变) GStreamer 输入管线初始化
|
|
||||||
std::string gst_input_pipeline =
|
std::string gst_input_pipeline =
|
||||||
"rtspsrc location=" + input_url_ + " latency=0 protocols=tcp ! "
|
"rtspsrc location=" + input_url_ + " latency=0 protocols=tcp ! "
|
||||||
"rtph265depay ! "
|
"rtph265depay ! "
|
||||||
"h265parse ! "
|
"h265parse ! "
|
||||||
"mppvideodec format=16 ! "
|
"mppvideodec format=16 ! "
|
||||||
|
"videoconvert ! "
|
||||||
"video/x-raw,format=BGR ! "
|
"video/x-raw,format=BGR ! "
|
||||||
"appsink";
|
"appsink";
|
||||||
|
|
||||||
|
|
@ -98,18 +77,17 @@ bool VideoService::start() {
|
||||||
} else {
|
} else {
|
||||||
spdlog::error("{} Failed to read first frame to determine size. Aborting.", log_prefix_);
|
spdlog::error("{} Failed to read first frame to determine size. Aborting.", log_prefix_);
|
||||||
capture_.release();
|
capture_.release();
|
||||||
return false; // 提前中止
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("RTSP stream opened successfully! (%dx%d @ %.2f FPS)\n", frame_width_, frame_height_, frame_fps_);
|
printf("RTSP stream opened successfully! (%dx%d @ %.2f FPS)\n", frame_width_, frame_height_, frame_fps_);
|
||||||
|
|
||||||
// 4. (不变) GStreamer 输出管线初始化
|
|
||||||
std::string gst_pipeline =
|
std::string gst_pipeline =
|
||||||
"appsrc ! "
|
"appsrc ! "
|
||||||
"queue max-size-buffers=2 leaky=downstream ! "
|
"queue max-size-buffers=2 leaky=downstream ! "
|
||||||
"video/x-raw,format=BGR ! "
|
"video/x-raw,format=BGR ! "
|
||||||
"videoconvert ! "
|
"videoconvert ! "
|
||||||
"video/x-raw,format=NV12 ! "
|
"video/x-raw,format=NV12 ! "
|
||||||
"mpph265enc gop=25 rc-mode=fixqp qp-init=26 ! "
|
"mpph265enc gop=25 rc-mode=fixqp qp-init=26 ! "
|
||||||
"h265parse ! "
|
"h265parse ! "
|
||||||
|
|
@ -130,7 +108,6 @@ bool VideoService::start() {
|
||||||
}
|
}
|
||||||
printf("VideoWriter opened successfully.\n");
|
printf("VideoWriter opened successfully.\n");
|
||||||
|
|
||||||
// 5. (不变) 启动线程
|
|
||||||
running_ = true;
|
running_ = true;
|
||||||
reading_thread_ = std::thread(&VideoService::reading_loop, this);
|
reading_thread_ = std::thread(&VideoService::reading_loop, this);
|
||||||
processing_thread_ = std::thread(&VideoService::processing_loop, this);
|
processing_thread_ = std::thread(&VideoService::processing_loop, this);
|
||||||
|
|
@ -144,7 +121,6 @@ void VideoService::stop() {
|
||||||
printf("Stopping VideoService...\n");
|
printf("Stopping VideoService...\n");
|
||||||
running_ = false;
|
running_ = false;
|
||||||
|
|
||||||
// 唤醒可能在 frame_cv_.wait() 处等待的线程
|
|
||||||
frame_cv_.notify_all();
|
frame_cv_.notify_all();
|
||||||
|
|
||||||
if (reading_thread_.joinable()) {
|
if (reading_thread_.joinable()) {
|
||||||
|
|
@ -162,17 +138,12 @@ void VideoService::stop() {
|
||||||
if (writer_.isOpened()) {
|
if (writer_.isOpened()) {
|
||||||
writer_.release();
|
writer_.release();
|
||||||
}
|
}
|
||||||
|
module_->stop();
|
||||||
// (可选) 确保模块资源被释放 (虽然unique_ptr析构时会自动处理)
|
module_.reset();
|
||||||
module_.reset();
|
|
||||||
|
|
||||||
printf("VideoService stopped.\n");
|
printf("VideoService stopped.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// reading_loop() 函数: 完全不变
|
|
||||||
//
|
|
||||||
void VideoService::reading_loop() {
|
void VideoService::reading_loop() {
|
||||||
cv::Mat frame;
|
cv::Mat frame;
|
||||||
spdlog::info("Reading thread started.");
|
spdlog::info("Reading thread started.");
|
||||||
|
|
@ -202,12 +173,8 @@ void VideoService::reading_loop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// processing_loop() 函数: 极大简化 (关键修改)
|
|
||||||
//
|
|
||||||
void VideoService::processing_loop() {
|
void VideoService::processing_loop() {
|
||||||
cv::Mat frame;
|
cv::Mat frame;
|
||||||
// detect_result_group_t detection_results; // <-- 移除
|
|
||||||
|
|
||||||
while (running_) {
|
while (running_) {
|
||||||
{
|
{
|
||||||
|
|
@ -229,16 +196,10 @@ void VideoService::processing_loop() {
|
||||||
if (frame.empty()) {
|
if (frame.empty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. (关键修改) 调用AI模块处理
|
|
||||||
// --- 移除所有 resize, put, get, update_tracker, draw_results ---
|
|
||||||
if (!module_->process(frame)) {
|
if (!module_->process(frame)) {
|
||||||
// 模块报告处理失败
|
// 模块报告处理失败
|
||||||
spdlog::warn("{} Module failed to process frame. Skipping.", log_prefix_);
|
spdlog::warn("{} Module failed to process frame. Skipping.", log_prefix_);
|
||||||
}
|
}
|
||||||
// 此时 'frame' 已经被 module_->process() 修改(例如,绘制了框)
|
|
||||||
|
|
||||||
// 3. (不变) 写入输出流
|
|
||||||
if (writer_.isOpened()) {
|
if (writer_.isOpened()) {
|
||||||
writer_.write(frame);
|
writer_.write(frame);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue