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