wangrong
2025-03-19 291afb9c81aae1d15d9e3edcea618d0a2e1fc5a6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
 
#include <iostream>
#include <thread>
#include <vector>
#include <sstream>
#include <utility>
#include <gst/gst.h>
#include <gst/rtsp-server/rtsp-server.h>
 
inline std::vector<std::string> string_split(const std::string& s, char delimiter) {
    std::vector<std::string> tokens;
    std::string token;
    std::istringstream tokenStream(s);
    while (std::getline(tokenStream, token, delimiter)) {
        tokens.push_back(token);
    }
    return tokens;
}
 
/*
 * usage:
 * ./run_rtsp_server [-p] [rtsp_port] [-s] [stream_name1:inner_port1/stream_name2:inner_port2/...]
 * 
 * for example:
 * ./run_rtsp_server -p 8554 -s 1st_rtsp:8000/2nd_rtsp:8001/3rd_rtsp:8002
 * rtsp server will listen at ports(8000/8001/8002) to receive udp stream and distribute them at port 8554 using rtsp protocal:
 * (1) rtsp://127.0.0.1:8554/1st_rtsp
 * (2) rtsp://127.0.0.1:8554/2nd_rtsp
 * (3) rtsp://127.0.0.1:8554/3rd_rtsp
*/
bool parse_args(int argc, char** argv, std::string& rtsp_port, std::vector<std::pair<std::string, std::string>>& streams_info) {
    auto print_error = []() {
        std::cout << "invalid arguments!" << std::endl;
        std::cout << "./run_rtsp_server [-p] [rtsp_port] [-s] [stream_name1:inner_port1/stream_name2:inner_port2/...]" << std::endl;
    };
 
    if (argc != 5) {
        print_error();
        return false;
    }
    
    auto _p = std::string(argv[1]);
    rtsp_port = std::string(argv[2]);
    auto _s = std::string(argv[3]);
    auto streams = std::string(argv[4]);
 
    if (_p != "-p" || _s != "-s") {
        print_error();
        return false;
    }
 
    auto streams_list = string_split(streams, '/');
    for (auto& stream: streams_list) {
        auto name_port = string_split(stream, ':');
        if (name_port.size() != 2) {
            print_error();
            return false;
        }
        streams_info.push_back(std::pair<std::string, std::string>(name_port[0], name_port[1]));
    }
    return true;
}
 
int main(int argc, char** argv) {
    std::string rtsp_port;
    std::vector<std::pair<std::string, std::string>> streams_info;
    if (!parse_args(argc, argv, rtsp_port, streams_info)) {
        return -1;
    }
    
    auto rtsp_server_run = [&]() {
        GMainLoop* loop;
        GstRTSPServer* server;
 
        gst_init(&argc, &argv);
        server = gst_rtsp_server_new();
        g_object_set(server, "service", rtsp_port.c_str(), NULL);
        gst_rtsp_server_attach(server, NULL);
        auto mounts = gst_rtsp_server_get_mount_points(server);
 
        for(auto& stream: streams_info) {
            auto stream_name = stream.first;
            auto stream_port = stream.second;
 
            char udpsrc_pipeline[512];
            int udp_buffer_size = 512 * 1024;
            
            // receive stream data from udpsrc internally and push it via rtsp
            sprintf (udpsrc_pipeline,
                    "( udpsrc name=pay0 port=%s buffer-size=%lu caps=\"application/x-rtp, media=video, "
                    "clock-rate=90000, encoding-name=H264, payload=96 \" )",
                    stream_port.c_str(), udp_buffer_size);
 
            auto factory = gst_rtsp_media_factory_new();
            gst_rtsp_media_factory_set_launch(factory, udpsrc_pipeline);
            gst_rtsp_media_factory_set_shared(factory, true);
            gst_rtsp_mount_points_add_factory(mounts, ("/" + stream_name).c_str(), factory);
        }        
        g_object_unref(mounts);
 
        std::cout << "########## rtsp server info ###########" << std::endl;
        for (int i = 0; i < streams_info.size(); i++) {
            std::cout << "(" << i + 1 << ") " 
                << streams_info[i].first << "==>" << streams_info[i].second 
                << "==>rtsp://127.0.0.1:" << rtsp_port << "/" << streams_info[i].first << std::endl;
        }
        
        loop = g_main_loop_new(NULL, FALSE);
        g_main_loop_run(loop);
        g_main_loop_unref(loop);
        gst_object_unref(server);
    };
    std::thread rtsp_server(rtsp_server_run);
 
    // enter to exit
    std::string wait;
    std::getline(std::cin, wait);
    return 0;
}