sweeper_video/src/rtmp_manager.cpp

164 lines
4.5 KiB
C++
Raw Normal View History

2025-10-15 15:36:48 +08:00
// rtmp_manager.cpp
#include "rtmp_manager.hpp"
2025-10-15 14:14:00 +08:00
2025-10-15 17:01:43 +08:00
#include <gst/gst.h>
2025-10-15 10:18:02 +08:00
2025-10-15 14:14:00 +08:00
#include "logger.hpp"
2025-10-15 08:57:40 +08:00
std::unordered_map<std::string, std::unique_ptr<RTMPManager::StreamContext>> RTMPManager::streams;
std::mutex RTMPManager::streams_mutex;
2025-10-15 17:01:43 +08:00
std::queue<VideoPushRequest> RTMPManager::request_queue;
std::mutex RTMPManager::queue_mutex;
std::condition_variable RTMPManager::queue_cv;
std::thread RTMPManager::worker_thread;
std::atomic<bool> RTMPManager::running{false};
void RTMPManager::init()
{
gst_init(nullptr, nullptr);
2025-10-15 17:01:43 +08:00
running = true;
worker_thread = std::thread(rtmp_worker_thread);
LOG_INFO("[RTMP] Initialized and worker thread started.");
}
2025-10-15 17:01:43 +08:00
void RTMPManager::stop_all()
2025-10-15 08:50:01 +08:00
{
2025-10-15 17:01:43 +08:00
running = false;
queue_cv.notify_all();
2025-10-15 08:50:01 +08:00
2025-10-15 17:01:43 +08:00
// 停止所有流
{
2025-10-15 17:01:43 +08:00
std::lock_guard<std::mutex> lock(streams_mutex);
for (auto &kv : streams) kv.second->running = false;
}
2025-10-15 17:01:43 +08:00
if (worker_thread.joinable()) worker_thread.join();
2025-10-15 17:01:43 +08:00
LOG_INFO("[RTMP] stop_all completed.");
}
2025-10-15 17:01:43 +08:00
void RTMPManager::enqueue_video_push_request(const VideoPushRequest &req)
2025-10-15 11:27:53 +08:00
{
2025-10-15 17:01:43 +08:00
{
std::lock_guard<std::mutex> lock(queue_mutex);
request_queue.push(req);
}
queue_cv.notify_one();
2025-10-15 15:01:55 +08:00
}
2025-10-15 17:01:43 +08:00
void RTMPManager::rtmp_worker_thread()
2025-10-15 15:01:55 +08:00
{
2025-10-15 17:01:43 +08:00
while (running)
2025-10-15 13:09:10 +08:00
{
2025-10-15 17:01:43 +08:00
VideoPushRequest req;
{
std::unique_lock<std::mutex> lock(queue_mutex);
queue_cv.wait(lock, [] { return !request_queue.empty() || !running; });
if (!running) break;
req = request_queue.front();
request_queue.pop();
}
2025-10-15 16:21:25 +08:00
2025-10-15 17:01:43 +08:00
nlohmann::json results = nlohmann::json::array();
for (auto &item : req.data)
2025-10-15 13:09:10 +08:00
{
2025-10-15 17:01:43 +08:00
for (int ch : item.channels)
2025-10-15 16:21:25 +08:00
{
2025-10-15 17:01:43 +08:00
if (ch < 0 || ch >= static_cast<int>(g_app_config.cameras.size())) continue;
Camera &cam = g_app_config.cameras[ch];
StreamResultInfo res;
if (item.switchVal == 0)
res = start_camera(cam, item.streamType);
else
res = stop_camera(cam, item.streamType);
res.loc = ch;
res.url = "rtmp://127.0.0.1/live/" + cam.name;
results.push_back({{"loc", res.loc}, {"url", res.url}, {"result", res.result}, {"reason", res.reason}});
2025-10-15 16:21:25 +08:00
}
}
2025-10-15 15:33:00 +08:00
2025-10-15 17:01:43 +08:00
// 上报 MQTT
nlohmann::json reply;
reply["type"] = "response";
reply["seqNo"] = req.seqNo;
reply["data"] = results;
if (mqtt_client) mqtt_client->publish(g_app_config.mqtt.topics.video_down, reply.dump());
}
}
2025-10-15 15:33:00 +08:00
2025-10-15 17:01:43 +08:00
// 简化 start_camera / stop_camera不阻塞 MQTT 回调
RTMPManager::StreamResultInfo RTMPManager::start_camera(const Camera &cam, int streamType)
{
StreamResultInfo res;
std::string key = cam.name + (streamType == 0 ? "_main" : "_sub");
2025-10-15 15:33:00 +08:00
2025-10-15 17:01:43 +08:00
{
std::lock_guard<std::mutex> lock(streams_mutex);
if (streams.find(key) != streams.end())
2025-10-15 16:21:25 +08:00
{
2025-10-15 17:01:43 +08:00
res.result = 0;
res.reason = "Already streaming";
return res;
2025-10-15 16:21:25 +08:00
}
2025-10-15 17:01:43 +08:00
auto ctx = std::make_unique<StreamContext>();
ctx->running = true;
ctx->thread = std::thread(
[cam, streamType, ctx_ptr = ctx.get()]
{
// TODO: GStreamer pipeline loop
std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟启动
StreamResultInfo r;
r.result = 0;
r.reason = "Started OK";
ctx_ptr->start_result.set_value(r);
});
streams[key] = std::move(ctx);
}
// 非阻塞:直接返回 future 的结果即可
try
{
res = streams[key]->start_result.get_future().get();
2025-10-15 15:33:00 +08:00
}
2025-10-15 17:01:43 +08:00
catch (...)
2025-10-15 15:33:00 +08:00
{
res.result = 1;
2025-10-15 17:01:43 +08:00
res.reason = "Exception in start_camera";
2025-10-15 13:09:10 +08:00
}
2025-10-15 15:01:55 +08:00
return res;
}
2025-10-15 11:27:53 +08:00
2025-10-15 17:01:43 +08:00
RTMPManager::StreamResultInfo RTMPManager::stop_camera(const Camera &cam, int streamType)
2025-10-15 15:01:55 +08:00
{
StreamResultInfo res;
2025-10-15 17:01:43 +08:00
std::string key = cam.name + (streamType == 0 ? "_main" : "_sub");
2025-10-15 11:27:53 +08:00
2025-10-15 15:01:55 +08:00
std::unique_ptr<StreamContext> ctx;
{
std::lock_guard<std::mutex> lock(streams_mutex);
auto it = streams.find(key);
if (it == streams.end())
{
res.result = 0;
res.reason = "Not streaming";
return res;
}
ctx = std::move(it->second);
streams.erase(it);
2025-10-15 17:01:43 +08:00
ctx->running = false;
2025-10-15 15:01:55 +08:00
}
2025-10-15 16:13:52 +08:00
if (ctx->thread.joinable()) ctx->thread.join();
2025-10-15 15:01:55 +08:00
res.result = 0;
2025-10-15 17:01:43 +08:00
res.reason = "Stopped OK";
2025-10-15 15:01:55 +08:00
return res;
2025-10-15 17:01:43 +08:00
}