145 lines
3.8 KiB
C++
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;
|
|
} |