kunlang_video/include/rtmp_manager.hpp
2025-10-17 13:36:22 +08:00

114 lines
3.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// rtmp_manager.hpp
#pragma once
#include <gst/gst.h>
#include <atomic>
#include <functional>
#include <future>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>
#include "app_config.hpp"
#include "data_manager.hpp"
class RTMPManager
{
public:
enum class StreamResult
{
OK,
PIPELINE_ERROR,
CONNECTION_FAIL,
EOS_RECEIVED,
TIMEOUT,
UNKNOWN
};
struct StreamStatus
{
bool running{false};
StreamResult last_result{StreamResult::UNKNOWN};
std::string last_error;
};
struct StreamResultInfo
{
int loc{-1};
std::string url;
int result{1}; // 0 success, 1 fail
std::string reason;
};
using StreamCallback = std::function<void(const std::string &key, StreamStatus)>;
static void init();
static void set_status_callback(StreamCallback cb);
// 单路接口
static StreamResultInfo start_camera(const Camera &cam, StreamType type);
static StreamResultInfo stop_camera(const std::string &cam_name, StreamType type);
// 批量接口:处理 VideoPushRequest
static std::vector<StreamResultInfo> process_push_request(const VideoPushRequest &req);
static void stop_all();
// 自动启动所有录像流(上电调用一次)
static void start_all_record_streams();
static bool is_streaming(const std::string &cam_name, StreamType type);
static bool is_any_streaming();
static std::string get_stream_url(const std::string &cam_name, StreamType type);
private:
struct StreamContext
{
std::atomic<bool> running{false};
std::thread thread;
// 启动阶段的 promise用于首次启动结果反馈7s 内)
std::promise<StreamStatus> start_promise;
std::atomic<bool> start_promise_set{false};
StreamStatus status;
StreamContext() = default;
StreamContext(const StreamContext &) = delete;
StreamContext &operator=(const StreamContext &) = delete;
~StreamContext()
{
try
{
running.store(false);
if (thread.joinable())
{
thread.join(); // 防止 std::terminate()
}
}
catch (...)
{
// 安全兜底,不抛异常
}
}
};
static std::string make_stream_key(const std::string &cam_name, StreamType type);
static GstElement *create_pipeline(const Camera &cam, StreamType type);
static void stream_loop(Camera cam, StreamType type, StreamContext *ctx);
static bool do_stream_once(const Camera &cam, StreamType type, StreamContext *ctx);
static void update_status(const std::string &key, const StreamStatus &status);
static std::unordered_map<std::string, std::unique_ptr<StreamContext>> streams;
static std::mutex streams_mutex;
static StreamCallback status_callback;
// 自动重试参数
// MAINrecord为永久重试SUBlive使用限次重试
static constexpr int LIVE_MAX_RETRIES = 5;
static constexpr int RETRY_BASE_DELAY_MS = 2000; // 2s -> 可指数退避
};