kunlang_video/src/rtsp.cpp
2025-09-08 10:05:03 +08:00

145 lines
3.8 KiB
C++

// camera_to_rtsp.cpp
#include <gst/gst.h>
#include <gst/rtsp-server/rtsp-server.h>
#include <iostream>
#include <vector>
#include <atomic>
#include <thread>
#include <csignal>
#include <fstream>
#include <nlohmann/json.hpp>
#include <mutex>
using json = nlohmann::json;
GMainLoop *loop = nullptr;
// 全局退出标志
std::atomic<bool> g_running(true);
// Ctrl+C 信号处理
void signalHandler(int signum)
{
g_running = false;
if (loop)
g_main_loop_quit(loop);
}
// GStreamer 日志处理
void gstreamer_log_handler(const gchar *domain, GLogLevelFlags level,
const gchar *message, gpointer)
{
if (level & G_LOG_LEVEL_ERROR)
std::cerr << "[GStreamer-ERROR] " << (domain ? domain : "unknown") << ": " << message << std::endl;
}
// 初始化 GStreamer
void init_gstreamer()
{
gst_init(nullptr, nullptr);
g_log_set_default_handler(gstreamer_log_handler, nullptr);
// 设置GStreamer调试级别为警告及以上
setenv("GST_DEBUG", "*:2", 1);
}
// 摄像头结构体
struct Camera
{
std::string device;
std::string name;
int width, height, fps;
bool enabled;
GstElement *src = nullptr;
GstRTSPMediaFactory *factory = nullptr;
};
// 创建RTSP媒体工厂
GstRTSPMediaFactory *create_media_factory(const Camera &cam)
{
std::string launch_str =
"( v4l2src device=" + cam.device +
" ! video/x-raw,format=NV12,width=" + std::to_string(cam.width) +
",height=" + std::to_string(cam.height) +
",framerate=" + std::to_string(cam.fps) + "/1"
" ! videoconvert ! queue ! mpph264enc ! rtph264pay name=pay0 pt=96 )";
GstRTSPMediaFactory *factory = gst_rtsp_media_factory_new();
gst_rtsp_media_factory_set_launch(factory, launch_str.c_str());
gst_rtsp_media_factory_set_shared(factory, TRUE);
return factory;
}
// 主函数
int main()
{
signal(SIGINT, signalHandler);
signal(SIGPIPE, SIG_IGN);
init_gstreamer();
// 读取配置文件
std::ifstream ifs("config.json");
if (!ifs.is_open())
{
std::cerr << "Failed to open config.json" << std::endl;
return -1;
}
json j;
ifs >> j;
std::vector<Camera> cameras;
for (auto &c : j["cameras"])
{
Camera cam;
cam.device = c["device"];
cam.name = c["name"];
cam.width = c["width"];
cam.height = c["height"];
cam.fps = c["fps"];
cam.enabled = c["enabled"];
if (cam.enabled)
{
cameras.push_back(cam);
}
}
// 创建RTSP服务器
GstRTSPServer *server = gst_rtsp_server_new();
gst_rtsp_server_set_service(server, "8554"); // 设置RTSP服务器端口
// 获取服务器挂载点
GstRTSPMountPoints *mounts = gst_rtsp_server_get_mount_points(server);
// 为每个摄像头创建媒体工厂并添加到挂载点
for (auto &cam : cameras)
{
if (!cam.enabled)
continue;
cam.factory = create_media_factory(cam);
std::string mount_point = "/" + cam.name;
gst_rtsp_mount_points_add_factory(mounts, mount_point.c_str(), cam.factory);
std::cout << "Camera '" << cam.name << "' available at rtsp://localhost:8554" << mount_point << std::endl;
}
// 释放挂载点引用
g_object_unref(mounts);
// 附加服务器到默认主上下文
loop = g_main_loop_new(nullptr, FALSE);
gst_rtsp_server_attach(server, nullptr);
std::cout << "RTSP server running on rtsp://localhost:8554" << std::endl;
std::cout << "Press Ctrl+C to stop" << std::endl;
g_main_loop_run(loop); // 运行主循环
// 清理资源
g_object_unref(server);
g_main_loop_unref(loop);
std::cout << "RTSP server stopped." << std::endl;
return 0;
}