1 // RTSP Server
2
3 #include "xop/RtspServer.h"
4 #include "net/Timer.h"
5 #include <thread>
6 #include <memory>
7 #include <iostream>
8 #include <string>
9
10 class H264File
11 {
12 public:
13 H264File(int buf_size=500000);
14 ~H264File();
15
16 bool Open(const char *path);
17 void Close();
18
IsOpened() const19 bool IsOpened() const
20 { return (m_file != NULL); }
21
22 int ReadFrame(char* in_buf, int in_buf_size, bool* end);
23
24 private:
25 FILE *m_file = NULL;
26 char *m_buf = NULL;
27 int m_buf_size = 0;
28 int m_bytes_used = 0;
29 int m_count = 0;
30 };
31
32 void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, H264File* h264_file);
33
main(int argc,char ** argv)34 int main(int argc, char **argv)
35 {
36 if(argc != 2) {
37 printf("Usage: %s test.h264 \n", argv[0]);
38 return 0;
39 }
40
41 H264File h264_file;
42 if(!h264_file.Open(argv[1])) {
43 printf("Open %s failed.\n", argv[1]);
44 return 0;
45 }
46
47 std::string suffix = "live";
48 std::string ip = "127.0.0.1";
49 std::string port = "554";
50 std::string rtsp_url = "rtsp://" + ip + ":" + port + "/" + suffix;
51
52 std::shared_ptr<xop::EventLoop> event_loop(new xop::EventLoop());
53 std::shared_ptr<xop::RtspServer> server = xop::RtspServer::Create(event_loop.get());
54
55 if (!server->Start("0.0.0.0", atoi(port.c_str()))) {
56 printf("RTSP Server listen on %s failed.\n", port.c_str());
57 return 0;
58 }
59
60 #ifdef AUTH_CONFIG
61 server->SetAuthConfig("-_-", "admin", "12345");
62 #endif
63
64 xop::MediaSession *session = xop::MediaSession::CreateNew("live");
65 session->AddSource(xop::channel_0, xop::H264Source::CreateNew());
66 //session->StartMulticast();
67 session->AddNotifyConnectedCallback([] (xop::MediaSessionId sessionId, std::string peer_ip, uint16_t peer_port){
68 printf("RTSP client connect, ip=%s, port=%hu \n", peer_ip.c_str(), peer_port);
69 });
70
71 session->AddNotifyDisconnectedCallback([](xop::MediaSessionId sessionId, std::string peer_ip, uint16_t peer_port) {
72 printf("RTSP client disconnect, ip=%s, port=%hu \n", peer_ip.c_str(), peer_port);
73 });
74
75 xop::MediaSessionId session_id = server->AddSession(session);
76
77 std::thread t1(SendFrameThread, server.get(), session_id, &h264_file);
78 t1.detach();
79
80 std::cout << "Play URL: " << rtsp_url << std::endl;
81
82 while (1) {
83 xop::Timer::Sleep(100);
84 }
85
86 getchar();
87 return 0;
88 }
89
SendFrameThread(xop::RtspServer * rtsp_server,xop::MediaSessionId session_id,H264File * h264_file)90 void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, H264File* h264_file)
91 {
92 int buf_size = 2000000;
93 std::unique_ptr<uint8_t> frame_buf(new uint8_t[buf_size]);
94
95 while(1) {
96 bool end_of_frame = false;
97 int frame_size = h264_file->ReadFrame((char*)frame_buf.get(), buf_size, &end_of_frame);
98 if(frame_size > 0) {
99 xop::AVFrame videoFrame = {0};
100 videoFrame.type = 0;
101 videoFrame.size = frame_size;
102 videoFrame.timestamp = xop::H264Source::GetTimestamp();
103 videoFrame.buffer.reset(new uint8_t[videoFrame.size]);
104 memcpy(videoFrame.buffer.get(), frame_buf.get(), videoFrame.size);
105 rtsp_server->PushFrame(session_id, xop::channel_0, videoFrame);
106 }
107 else {
108 break;
109 }
110
111 xop::Timer::Sleep(40);
112 };
113 }
114
H264File(int buf_size)115 H264File::H264File(int buf_size)
116 : m_buf_size(buf_size)
117 {
118 m_buf = new char[m_buf_size];
119 }
120
~H264File()121 H264File::~H264File()
122 {
123 delete m_buf;
124 }
125
Open(const char * path)126 bool H264File::Open(const char *path)
127 {
128 m_file = fopen(path, "rb");
129 if(m_file == NULL) {
130 return false;
131 }
132
133 return true;
134 }
135
Close()136 void H264File::Close()
137 {
138 if(m_file) {
139 fclose(m_file);
140 m_file = NULL;
141 m_count = 0;
142 m_bytes_used = 0;
143 }
144 }
145
ReadFrame(char * in_buf,int in_buf_size,bool * end)146 int H264File::ReadFrame(char* in_buf, int in_buf_size, bool* end)
147 {
148 if(m_file == NULL) {
149 return -1;
150 }
151
152 int bytes_read = (int)fread(m_buf, 1, m_buf_size, m_file);
153 if(bytes_read == 0) {
154 fseek(m_file, 0, SEEK_SET);
155 m_count = 0;
156 m_bytes_used = 0;
157 bytes_read = (int)fread(m_buf, 1, m_buf_size, m_file);
158 if(bytes_read == 0) {
159 this->Close();
160 return -1;
161 }
162 }
163
164 bool is_find_start = false, is_find_end = false;
165 int i = 0, start_code = 3;
166 *end = false;
167
168 for (i=0; i<bytes_read-5; i++) {
169 if(m_buf[i] == 0 && m_buf[i+1] == 0 && m_buf[i+2] == 1) {
170 start_code = 3;
171 }
172 else if(m_buf[i] == 0 && m_buf[i+1] == 0 && m_buf[i+2] == 0 && m_buf[i+3] == 1) {
173 start_code = 4;
174 }
175 else {
176 continue;
177 }
178
179 if (((m_buf[i+start_code]&0x1F) == 0x5 || (m_buf[i+start_code]&0x1F) == 0x1)
180 && ((m_buf[i+start_code+1]&0x80) == 0x80)) {
181 is_find_start = true;
182 i += 4;
183 break;
184 }
185 }
186
187 for (; i<bytes_read-5; i++) {
188 if(m_buf[i] == 0 && m_buf[i+1] == 0 && m_buf[i+2] == 1)
189 {
190 start_code = 3;
191 }
192 else if(m_buf[i] == 0 && m_buf[i+1] == 0 && m_buf[i+2] == 0 && m_buf[i+3] == 1) {
193 start_code = 4;
194 }
195 else {
196 continue;
197 }
198
199 if (((m_buf[i+start_code]&0x1F) == 0x7) || ((m_buf[i+start_code]&0x1F) == 0x8)
200 || ((m_buf[i+start_code]&0x1F) == 0x6)|| (((m_buf[i+start_code]&0x1F) == 0x5
201 || (m_buf[i+start_code]&0x1F) == 0x1) &&((m_buf[i+start_code+1]&0x80) == 0x80))) {
202 is_find_end = true;
203 break;
204 }
205 }
206
207 bool flag = false;
208 if(is_find_start && !is_find_end && m_count>0) {
209 flag = is_find_end = true;
210 i = bytes_read;
211 *end = true;
212 }
213
214 if(!is_find_start || !is_find_end) {
215 this->Close();
216 return -1;
217 }
218
219 int size = (i<=in_buf_size ? i : in_buf_size);
220 memcpy(in_buf, m_buf, size);
221
222 if(!flag) {
223 m_count += 1;
224 m_bytes_used += i;
225 }
226 else {
227 m_count = 0;
228 m_bytes_used = 0;
229 }
230
231 fseek(m_file, m_bytes_used, SEEK_SET);
232 return size;
233 }
234
235
236