This commit is contained in:
cxh 2025-10-14 17:49:26 +08:00
parent 516f1d4404
commit 786c4db596
2 changed files with 24 additions and 31 deletions

View File

@ -9,18 +9,22 @@
#include <thread> #include <thread>
#include <atomic> #include <atomic>
enum class StreamType
{
MAIN,
SUB
};
class RTMPManager class RTMPManager
{ {
public: public:
static void init(); static void init();
// start/stop 增加 StreamType 参数
static void start_camera(const Camera &cam, StreamType type); static void start_camera(const Camera &cam, StreamType type);
static void stop_camera(const std::string &cam_name, StreamType type); static void stop_camera(const std::string &cam_name, StreamType type);
static void stop_all(); static void stop_all();
static bool is_streaming(const std::string &cam_name, StreamType type); static bool is_streaming(const std::string &cam_name, StreamType type);
static bool is_any_streaming(); static bool is_any_streaming();
// 获取推流 URL用于应答
static std::string get_stream_url(const std::string &cam_name, StreamType type); static std::string get_stream_url(const std::string &cam_name, StreamType type);
private: private:
@ -29,16 +33,17 @@ private:
std::atomic<bool> running; std::atomic<bool> running;
std::thread thread; std::thread thread;
StreamContext() : running(false) {} // 确保 atomic 初始化 StreamContext() : running(false) {}
StreamContext(StreamContext &&) = default; // 允许移动
StreamContext &operator=(StreamContext &&) = default;
StreamContext(const StreamContext &) = delete;
StreamContext &operator=(const StreamContext &) = delete;
}; };
static std::unordered_map<std::string, StreamContext> streams; static std::unordered_map<std::string, StreamContext> streams;
static std::mutex streams_mutex; static std::mutex streams_mutex;
// stream loop 接收 StreamType 作为参数
static void stream_loop(Camera cam, StreamType type); static void stream_loop(Camera cam, StreamType type);
static GstElement *create_pipeline(const Camera &cam, StreamType type); static GstElement *create_pipeline(const Camera &cam, StreamType type);
// 辅助:构建 map key
static std::string make_stream_key(const std::string &cam_name, StreamType type); static std::string make_stream_key(const std::string &cam_name, StreamType type);
}; };

View File

@ -4,6 +4,8 @@
#include <iostream> #include <iostream>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <gst/gst.h>
#include <algorithm>
std::unordered_map<std::string, RTMPManager::StreamContext> RTMPManager::streams; std::unordered_map<std::string, RTMPManager::StreamContext> RTMPManager::streams;
std::mutex RTMPManager::streams_mutex; std::mutex RTMPManager::streams_mutex;
@ -26,7 +28,6 @@ void RTMPManager::init()
GstElement *RTMPManager::create_pipeline(const Camera &cam, StreamType type) GstElement *RTMPManager::create_pipeline(const Camera &cam, StreamType type)
{ {
// 拷贝原始参数
int width = cam.width; int width = cam.width;
int height = cam.height; int height = cam.height;
int fps = cam.fps; int fps = cam.fps;
@ -34,15 +35,13 @@ GstElement *RTMPManager::create_pipeline(const Camera &cam, StreamType type)
if (type == StreamType::SUB) if (type == StreamType::SUB)
{ {
// 简单一刀切策略:分辨率 /2帧率 /2码率 /2临界值保护
width = std::max(160, width / 2); width = std::max(160, width / 2);
height = std::max(120, height / 2); height = std::max(120, height / 2);
fps = std::max(10, fps / 2); fps = std::max(10, fps / 2);
bitrate = std::max(300000, bitrate / 2); // 最低 300kbps bitrate = std::max(300000, bitrate / 2);
} }
// 构建不同的流名stream key std::string stream_name = cam.name + stream_type_suffix(type);
std::string stream_name = cam.name + (type == StreamType::MAIN ? "_main" : "_sub");
std::string pipeline_str = std::string pipeline_str =
"v4l2src device=" + cam.device + "v4l2src device=" + cam.device +
@ -99,7 +98,6 @@ void RTMPManager::stream_loop(Camera cam, StreamType type)
LOG_INFO("[RTMP] Camera '" + key + "' streaming..."); LOG_INFO("[RTMP] Camera '" + key + "' streaming...");
bool error_occurred = false; bool error_occurred = false;
// 简单重连计数(可选):连续失败超过 N 次可以退出
int consecutive_failures = 0; int consecutive_failures = 0;
const int MAX_RETRIES = 5; const int MAX_RETRIES = 5;
@ -151,7 +149,6 @@ void RTMPManager::stream_loop(Camera cam, StreamType type)
if (consecutive_failures >= MAX_RETRIES) if (consecutive_failures >= MAX_RETRIES)
{ {
LOG_ERROR("[RTMP] Max retries reached for '" + key + "'. Stopping reconnection attempts."); LOG_ERROR("[RTMP] Max retries reached for '" + key + "'. Stopping reconnection attempts.");
// 可以选择将 running 置为 false让上层知道失败
std::lock_guard<std::mutex> lock(streams_mutex); std::lock_guard<std::mutex> lock(streams_mutex);
streams[key].running = false; streams[key].running = false;
break; break;
@ -193,8 +190,6 @@ void RTMPManager::stop_camera(const std::string &cam_name, StreamType type)
} }
it->second.running = false; it->second.running = false;
LOG_INFO("[RTMP] Stopping camera '" + key + "'...");
if (it->second.thread.joinable()) if (it->second.thread.joinable())
it->second.thread.join(); it->second.thread.join();
@ -220,38 +215,31 @@ bool RTMPManager::is_any_streaming()
void RTMPManager::stop_all() void RTMPManager::stop_all()
{ {
std::vector<std::string> names; std::vector<std::string> keys;
{ {
std::lock_guard<std::mutex> lock(streams_mutex); std::lock_guard<std::mutex> lock(streams_mutex);
for (auto &kv : streams) for (auto &kv : streams)
names.push_back(kv.first); keys.push_back(kv.first);
} }
for (auto &name : names) for (auto &key : keys)
{ {
// name 中包含后缀,但是 stop_camera 需要 cam_name + StreamType if (key.size() > 4 && key.find("_sub") == key.size() - 4)
// 我们可以解析后缀,或新增一个 stop_by_key。为简单起见解析
if (name.size() > 5 && name.find("_sub") == name.size() - 4)
{ {
std::string cam_name = name.substr(0, name.size() - 4); stop_camera(key.substr(0, key.size() - 4), StreamType::SUB);
stop_camera(cam_name, StreamType::SUB);
} }
else if (name.size() > 6 && name.find("_main") == name.size() - 5) else if (key.size() > 5 && key.find("_main") == key.size() - 5)
{ {
std::string cam_name = name.substr(0, name.size() - 5); stop_camera(key.substr(0, key.size() - 5), StreamType::MAIN);
stop_camera(cam_name, StreamType::MAIN);
} }
else else
{ {
// fallback: stop by treating as MAIN stop_camera(key, StreamType::MAIN);
stop_camera(name, StreamType::MAIN);
} }
} }
} }
std::string RTMPManager::get_stream_url(const std::string &cam_name, StreamType type) std::string RTMPManager::get_stream_url(const std::string &cam_name, StreamType type)
{ {
// 根据你本地 RTMP 服务地址组装 URL和 create_pipeline 的 stream_name 保持一致 return "rtmp://127.0.0.1/live/" + make_stream_key(cam_name, type);
std::string stream_name = cam_name + stream_type_suffix(type);
return std::string("rtmp://127.0.0.1/live/") + stream_name;
} }