temp
This commit is contained in:
parent
516f1d4404
commit
786c4db596
@ -9,18 +9,22 @@
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
enum class StreamType
|
||||
{
|
||||
MAIN,
|
||||
SUB
|
||||
};
|
||||
|
||||
class RTMPManager
|
||||
{
|
||||
public:
|
||||
static void init();
|
||||
// start/stop 增加 StreamType 参数
|
||||
static void start_camera(const Camera &cam, StreamType type);
|
||||
static void stop_camera(const std::string &cam_name, StreamType type);
|
||||
static void stop_all();
|
||||
static bool is_streaming(const std::string &cam_name, StreamType type);
|
||||
static bool is_any_streaming();
|
||||
|
||||
// 获取推流 URL,用于应答
|
||||
static std::string get_stream_url(const std::string &cam_name, StreamType type);
|
||||
|
||||
private:
|
||||
@ -29,16 +33,17 @@ private:
|
||||
std::atomic<bool> running;
|
||||
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::mutex streams_mutex;
|
||||
|
||||
// stream loop 接收 StreamType 作为参数
|
||||
static void stream_loop(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);
|
||||
};
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <gst/gst.h>
|
||||
#include <algorithm>
|
||||
|
||||
std::unordered_map<std::string, RTMPManager::StreamContext> RTMPManager::streams;
|
||||
std::mutex RTMPManager::streams_mutex;
|
||||
@ -26,7 +28,6 @@ void RTMPManager::init()
|
||||
|
||||
GstElement *RTMPManager::create_pipeline(const Camera &cam, StreamType type)
|
||||
{
|
||||
// 拷贝原始参数
|
||||
int width = cam.width;
|
||||
int height = cam.height;
|
||||
int fps = cam.fps;
|
||||
@ -34,15 +35,13 @@ GstElement *RTMPManager::create_pipeline(const Camera &cam, StreamType type)
|
||||
|
||||
if (type == StreamType::SUB)
|
||||
{
|
||||
// 简单一刀切策略:分辨率 /2,帧率 /2,码率 /2,临界值保护
|
||||
width = std::max(160, width / 2);
|
||||
height = std::max(120, height / 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 + (type == StreamType::MAIN ? "_main" : "_sub");
|
||||
std::string stream_name = cam.name + stream_type_suffix(type);
|
||||
|
||||
std::string pipeline_str =
|
||||
"v4l2src device=" + cam.device +
|
||||
@ -99,7 +98,6 @@ void RTMPManager::stream_loop(Camera cam, StreamType type)
|
||||
LOG_INFO("[RTMP] Camera '" + key + "' streaming...");
|
||||
|
||||
bool error_occurred = false;
|
||||
// 简单重连计数(可选):连续失败超过 N 次可以退出
|
||||
int consecutive_failures = 0;
|
||||
const int MAX_RETRIES = 5;
|
||||
|
||||
@ -151,7 +149,6 @@ void RTMPManager::stream_loop(Camera cam, StreamType type)
|
||||
if (consecutive_failures >= MAX_RETRIES)
|
||||
{
|
||||
LOG_ERROR("[RTMP] Max retries reached for '" + key + "'. Stopping reconnection attempts.");
|
||||
// 可以选择将 running 置为 false,让上层知道失败
|
||||
std::lock_guard<std::mutex> lock(streams_mutex);
|
||||
streams[key].running = false;
|
||||
break;
|
||||
@ -193,8 +190,6 @@ void RTMPManager::stop_camera(const std::string &cam_name, StreamType type)
|
||||
}
|
||||
|
||||
it->second.running = false;
|
||||
LOG_INFO("[RTMP] Stopping camera '" + key + "'...");
|
||||
|
||||
if (it->second.thread.joinable())
|
||||
it->second.thread.join();
|
||||
|
||||
@ -220,38 +215,31 @@ bool RTMPManager::is_any_streaming()
|
||||
|
||||
void RTMPManager::stop_all()
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
std::vector<std::string> keys;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(streams_mutex);
|
||||
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
|
||||
// 我们可以解析后缀,或新增一个 stop_by_key。为简单起见解析:
|
||||
if (name.size() > 5 && name.find("_sub") == name.size() - 4)
|
||||
if (key.size() > 4 && key.find("_sub") == key.size() - 4)
|
||||
{
|
||||
std::string cam_name = name.substr(0, name.size() - 4);
|
||||
stop_camera(cam_name, StreamType::SUB);
|
||||
stop_camera(key.substr(0, key.size() - 4), 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(cam_name, StreamType::MAIN);
|
||||
stop_camera(key.substr(0, key.size() - 5), StreamType::MAIN);
|
||||
}
|
||||
else
|
||||
{
|
||||
// fallback: stop by treating as MAIN
|
||||
stop_camera(name, StreamType::MAIN);
|
||||
stop_camera(key, StreamType::MAIN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string RTMPManager::get_stream_url(const std::string &cam_name, StreamType type)
|
||||
{
|
||||
// 根据你本地 RTMP 服务地址组装 URL,和 create_pipeline 的 stream_name 保持一致
|
||||
std::string stream_name = cam_name + stream_type_suffix(type);
|
||||
return std::string("rtmp://127.0.0.1/live/") + stream_name;
|
||||
return "rtmp://127.0.0.1/live/" + make_stream_key(cam_name, type);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user