Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

10 месяцев назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. #if defined(_DEBUG) || defined(DEBUG)
  2. #include "cstringext.h"
  3. #include "sys/sock.h"
  4. #include "sys/system.h"
  5. #include "sys/path.h"
  6. #include "sys/sync.hpp"
  7. #include "aio-worker.h"
  8. #include "ctypedef.h"
  9. #include "ntp-time.h"
  10. #include "rtp-profile.h"
  11. #include "rtsp-server.h"
  12. #include "media/ps-file-source.h"
  13. #include "media/h264-file-source.h"
  14. #include "media/h265-file-source.h"
  15. #include "media/mp4-file-source.h"
  16. #include "rtp-udp-transport.h"
  17. #include "rtp-tcp-transport.h"
  18. #include "rtsp-server-aio.h"
  19. #include "uri-parse.h"
  20. #include "urlcodec.h"
  21. #include "path.h"
  22. #include <map>
  23. #include <memory>
  24. #include "cpm/shared_ptr.h"
  25. #if defined(_HAVE_FFMPEG_)
  26. #include "media/ffmpeg-file-source.h"
  27. #include "media/ffmpeg-live-source.h"
  28. #endif
  29. #define UDP_MULTICAST_ADDR "239.0.0.2"
  30. #define UDP_MULTICAST_PORT 6000
  31. #if defined(OS_WINDOWS)
  32. static const char* s_workdir = "d:\\";
  33. #else
  34. static const char* s_workdir = "./";
  35. #endif
  36. static ThreadLocker s_locker;
  37. struct rtsp_media_t
  38. {
  39. std::shared_ptr<IMediaSource> media;
  40. std::shared_ptr<IRTPTransport> transport;
  41. uint8_t channel; // rtp over rtsp interleaved channel
  42. int status; // setup-init, 1-play, 2-pause
  43. rtsp_server_t* rtsp;
  44. };
  45. typedef std::map<std::string, rtsp_media_t> TSessions;
  46. static TSessions s_sessions;
  47. struct TFileDescription
  48. {
  49. int64_t duration;
  50. std::string sdpmedia;
  51. };
  52. static std::map<std::string, TFileDescription> s_describes;
  53. static int rtsp_uri_parse(const char* uri, std::string& path)
  54. {
  55. char path1[256];
  56. struct uri_t* r = uri_parse(uri, strlen(uri));
  57. if(!r)
  58. return -1;
  59. url_decode(r->path, strlen(r->path), path1, sizeof(path1));
  60. path = path1;
  61. uri_free(r);
  62. return 0;
  63. }
  64. static int rtsp_ondescribe(void* /*ptr*/, rtsp_server_t* rtsp, const char* uri)
  65. {
  66. static const char* pattern_vod =
  67. "v=0\n"
  68. "o=- %llu %llu IN IP4 %s\n"
  69. "s=%s\n"
  70. "c=IN IP4 0.0.0.0\n"
  71. "t=0 0\n"
  72. "a=range:npt=0-%.1f\n"
  73. "a=recvonly\n"
  74. "a=control:*\n"; // aggregate control
  75. static const char* pattern_live =
  76. "v=0\n"
  77. "o=- %llu %llu IN IP4 %s\n"
  78. "s=%s\n"
  79. "c=IN IP4 0.0.0.0\n"
  80. "t=0 0\n"
  81. "a=range:npt=now-\n" // live
  82. "a=recvonly\n"
  83. "a=control:*\n"; // aggregate control
  84. std::string filename;
  85. std::map<std::string, TFileDescription>::const_iterator it;
  86. rtsp_uri_parse(uri, filename);
  87. if (strstartswith(filename.c_str(), "/live/"))
  88. {
  89. filename = filename.c_str() + 6;
  90. }
  91. else if (strstartswith(filename.c_str(), "/vod/"))
  92. {
  93. filename = path::join(s_workdir, filename.c_str() + 5);
  94. }
  95. else
  96. {
  97. assert(0);
  98. return -1;
  99. }
  100. char buffer[1024] = { 0 };
  101. {
  102. AutoThreadLocker locker(s_locker);
  103. it = s_describes.find(filename);
  104. if(it == s_describes.end())
  105. {
  106. // unlock
  107. TFileDescription describe;
  108. std::shared_ptr<IMediaSource> source;
  109. if (0 == strcmp(filename.c_str(), "camera"))
  110. {
  111. #if defined(_HAVE_FFMPEG_)
  112. source.reset(new FFLiveSource("video=Integrated Webcam"));
  113. #endif
  114. int offset = snprintf(buffer, sizeof(buffer), pattern_live, ntp64_now(), ntp64_now(), "0.0.0.0", uri);
  115. assert(offset > 0 && offset + 1 < sizeof(buffer));
  116. }
  117. else
  118. {
  119. if (strendswith(filename.c_str(), ".ps"))
  120. source.reset(new PSFileSource(filename.c_str()));
  121. else if (strendswith(filename.c_str(), ".h264"))
  122. source.reset(new H264FileSource(filename.c_str()));
  123. else if (strendswith(filename.c_str(), ".h265"))
  124. source.reset(new H265FileSource(filename.c_str()));
  125. else
  126. {
  127. #if defined(_HAVE_FFMPEG_)
  128. source.reset(new FFFileSource(filename.c_str()));
  129. #else
  130. source.reset(new MP4FileSource(filename.c_str()));
  131. #endif
  132. }
  133. source->GetDuration(describe.duration);
  134. int offset = snprintf(buffer, sizeof(buffer), pattern_vod, ntp64_now(), ntp64_now(), "0.0.0.0", uri, describe.duration / 1000.0);
  135. assert(offset > 0 && offset + 1 < sizeof(buffer));
  136. }
  137. source->GetSDPMedia(describe.sdpmedia);
  138. // re-lock
  139. it = s_describes.insert(std::make_pair(filename, describe)).first;
  140. }
  141. }
  142. std::string sdp = buffer;
  143. sdp += it->second.sdpmedia;
  144. return rtsp_server_reply_describe(rtsp, 200, sdp.c_str());
  145. }
  146. static int rtsp_onsetup(void* /*ptr*/, rtsp_server_t* rtsp, const char* uri, const char* session, const struct rtsp_header_transport_t transports[], size_t num)
  147. {
  148. std::string filename;
  149. char rtsp_transport[128];
  150. const struct rtsp_header_transport_t *transport = NULL;
  151. rtsp_uri_parse(uri, filename);
  152. if (strstartswith(filename.c_str(), "/live/"))
  153. {
  154. filename = filename.c_str() + 6;
  155. }
  156. else if (strstartswith(filename.c_str(), "/vod/"))
  157. {
  158. filename = path::join(s_workdir, filename.c_str() + 5);
  159. }
  160. else
  161. {
  162. assert(0);
  163. return -1;
  164. }
  165. if ('\\' == *filename.rbegin() || '/' == *filename.rbegin())
  166. filename.erase(filename.end() - 1);
  167. const char* basename = path_basename(filename.c_str());
  168. if (NULL == strchr(basename, '.')) // filter track1
  169. filename.erase(basename - filename.c_str() - 1, std::string::npos);
  170. TSessions::iterator it;
  171. if(session)
  172. {
  173. AutoThreadLocker locker(s_locker);
  174. it = s_sessions.find(session);
  175. if(it == s_sessions.end())
  176. {
  177. // 454 Session Not Found
  178. return rtsp_server_reply_setup(rtsp, 454, NULL, NULL);
  179. }
  180. else
  181. {
  182. // don't support aggregate control
  183. if (0)
  184. {
  185. // 459 Aggregate Operation Not Allowed
  186. return rtsp_server_reply_setup(rtsp, 459, NULL, NULL);
  187. }
  188. }
  189. }
  190. else
  191. {
  192. rtsp_media_t item;
  193. item.rtsp = rtsp;
  194. item.channel = 0;
  195. item.status = 0;
  196. if (0 == strcmp(filename.c_str(), "camera"))
  197. {
  198. #if defined(_HAVE_FFMPEG_)
  199. item.media.reset(new FFLiveSource("video=Integrated Webcam"));
  200. #endif
  201. }
  202. else
  203. {
  204. if (strendswith(filename.c_str(), ".ps"))
  205. item.media.reset(new PSFileSource(filename.c_str()));
  206. else if (strendswith(filename.c_str(), ".h264"))
  207. item.media.reset(new H264FileSource(filename.c_str()));
  208. else if (strendswith(filename.c_str(), ".h265"))
  209. item.media.reset(new H265FileSource(filename.c_str()));
  210. else
  211. {
  212. #if defined(_HAVE_FFMPEG_)
  213. item.media.reset(new FFFileSource(filename.c_str()));
  214. #else
  215. item.media.reset(new MP4FileSource(filename.c_str()));
  216. #endif
  217. }
  218. }
  219. char rtspsession[32];
  220. snprintf(rtspsession, sizeof(rtspsession), "%p", item.media.get());
  221. AutoThreadLocker locker(s_locker);
  222. it = s_sessions.insert(std::make_pair(rtspsession, item)).first;
  223. }
  224. assert(NULL == transport);
  225. for(size_t i = 0; i < num && !transport; i++)
  226. {
  227. if(RTSP_TRANSPORT_RTP_UDP == transports[i].transport)
  228. {
  229. // RTP/AVP/UDP
  230. transport = &transports[i];
  231. }
  232. else if(RTSP_TRANSPORT_RTP_TCP == transports[i].transport)
  233. {
  234. // RTP/AVP/TCP
  235. // 10.12 Embedded (Interleaved) Binary Data (p40)
  236. transport = &transports[i];
  237. }
  238. }
  239. if(!transport)
  240. {
  241. // 461 Unsupported Transport
  242. return rtsp_server_reply_setup(rtsp, 461, NULL, NULL);
  243. }
  244. rtsp_media_t &item = it->second;
  245. if (RTSP_TRANSPORT_RTP_TCP == transport->transport)
  246. {
  247. // 10.12 Embedded (Interleaved) Binary Data (p40)
  248. int interleaved[2];
  249. if (transport->interleaved1 == transport->interleaved2)
  250. {
  251. interleaved[0] = item.channel++;
  252. interleaved[1] = item.channel++;
  253. }
  254. else
  255. {
  256. interleaved[0] = transport->interleaved1;
  257. interleaved[1] = transport->interleaved2;
  258. }
  259. item.transport = std::make_shared<RTPTcpTransport>(rtsp, interleaved[0], interleaved[1]);
  260. item.media->SetTransport(path_basename(uri), item.transport);
  261. // RTP/AVP/TCP;interleaved=0-1
  262. snprintf(rtsp_transport, sizeof(rtsp_transport), "RTP/AVP/TCP;interleaved=%d-%d", interleaved[0], interleaved[1]);
  263. }
  264. else if(transport->multicast)
  265. {
  266. unsigned short port[2] = { transport->rtp.u.client_port1, transport->rtp.u.client_port2 };
  267. char multicast[SOCKET_ADDRLEN];
  268. // RFC 2326 1.6 Overall Operation p12
  269. if(transport->destination[0])
  270. {
  271. // Multicast, client chooses address
  272. snprintf(multicast, sizeof(multicast), "%s", transport->destination);
  273. port[0] = transport->rtp.m.port1;
  274. port[1] = transport->rtp.m.port2;
  275. }
  276. else
  277. {
  278. // Multicast, server chooses address
  279. snprintf(multicast, sizeof(multicast), "%s", UDP_MULTICAST_ADDR);
  280. port[0] = UDP_MULTICAST_PORT;
  281. port[1] = UDP_MULTICAST_PORT + 1;
  282. }
  283. item.transport = std::make_shared<RTPUdpTransport>();
  284. if(0 != ((RTPUdpTransport*)item.transport.get())->Init(multicast, port))
  285. {
  286. // log
  287. // 500 Internal Server Error
  288. return rtsp_server_reply_setup(rtsp, 500, NULL, NULL);
  289. }
  290. item.media->SetTransport(path_basename(uri), item.transport);
  291. // Transport: RTP/AVP;multicast;destination=224.2.0.1;port=3456-3457;ttl=16
  292. snprintf(rtsp_transport, sizeof(rtsp_transport),
  293. "RTP/AVP;multicast;destination=%s;port=%hu-%hu;ttl=%d",
  294. multicast, port[0], port[1], 16);
  295. // 461 Unsupported Transport
  296. //return rtsp_server_reply_setup(rtsp, 461, NULL, NULL);
  297. }
  298. else
  299. {
  300. // unicast
  301. item.transport = std::make_shared<RTPUdpTransport>();
  302. assert(transport->rtp.u.client_port1 && transport->rtp.u.client_port2);
  303. unsigned short port[2] = { transport->rtp.u.client_port1, transport->rtp.u.client_port2 };
  304. const char *ip = transport->destination[0] ? transport->destination : rtsp_server_get_client(rtsp, NULL);
  305. if(0 != ((RTPUdpTransport*)item.transport.get())->Init(ip, port))
  306. {
  307. // log
  308. // 500 Internal Server Error
  309. return rtsp_server_reply_setup(rtsp, 500, NULL, NULL);
  310. }
  311. item.media->SetTransport(path_basename(uri), item.transport);
  312. // RTP/AVP;unicast;client_port=4588-4589;server_port=6256-6257;destination=xxxx
  313. snprintf(rtsp_transport, sizeof(rtsp_transport),
  314. "RTP/AVP;unicast;client_port=%hu-%hu;server_port=%hu-%hu%s%s",
  315. transport->rtp.u.client_port1, transport->rtp.u.client_port2,
  316. port[0], port[1],
  317. transport->destination[0] ? ";destination=" : "",
  318. transport->destination[0] ? transport->destination : "");
  319. }
  320. return rtsp_server_reply_setup(rtsp, 200, it->first.c_str(), rtsp_transport);
  321. }
  322. static int rtsp_onplay(void* /*ptr*/, rtsp_server_t* rtsp, const char* uri, const char* session, const int64_t *npt, const double *scale)
  323. {
  324. std::shared_ptr<IMediaSource> source;
  325. TSessions::iterator it;
  326. {
  327. AutoThreadLocker locker(s_locker);
  328. it = s_sessions.find(session ? session : "");
  329. if(it == s_sessions.end())
  330. {
  331. // 454 Session Not Found
  332. return rtsp_server_reply_play(rtsp, 454, NULL, NULL, NULL);
  333. }
  334. else
  335. {
  336. // uri with track
  337. if (0)
  338. {
  339. // 460 Only aggregate operation allowed
  340. return rtsp_server_reply_play(rtsp, 460, NULL, NULL, NULL);
  341. }
  342. }
  343. source = it->second.media;
  344. }
  345. if(npt && 0 != source->Seek(*npt))
  346. {
  347. // 457 Invalid Range
  348. return rtsp_server_reply_play(rtsp, 457, NULL, NULL, NULL);
  349. }
  350. if(scale && 0 != source->SetSpeed(*scale))
  351. {
  352. // set speed
  353. assert(*scale > 0);
  354. // 406 Not Acceptable
  355. return rtsp_server_reply_play(rtsp, 406, NULL, NULL, NULL);
  356. }
  357. // RFC 2326 12.33 RTP-Info (p55)
  358. // 1. Indicates the RTP timestamp corresponding to the time value in the Range response header.
  359. // 2. A mapping from RTP timestamps to NTP timestamps (wall clock) is available via RTCP.
  360. char rtpinfo[512] = { 0 };
  361. source->GetRTPInfo(uri, rtpinfo, sizeof(rtpinfo));
  362. // for vlc 2.2.2
  363. MP4FileSource* mp4 = dynamic_cast<MP4FileSource*>(source.get());
  364. if(mp4)
  365. mp4->SendRTCP(system_clock());
  366. it->second.status = 1;
  367. return rtsp_server_reply_play(rtsp, 200, npt, NULL, rtpinfo);
  368. }
  369. static int rtsp_onpause(void* /*ptr*/, rtsp_server_t* rtsp, const char* /*uri*/, const char* session, const int64_t* /*npt*/)
  370. {
  371. std::shared_ptr<IMediaSource> source;
  372. TSessions::iterator it;
  373. {
  374. AutoThreadLocker locker(s_locker);
  375. it = s_sessions.find(session ? session : "");
  376. if(it == s_sessions.end())
  377. {
  378. // 454 Session Not Found
  379. return rtsp_server_reply_pause(rtsp, 454);
  380. }
  381. else
  382. {
  383. // uri with track
  384. if (0)
  385. {
  386. // 460 Only aggregate operation allowed
  387. return rtsp_server_reply_pause(rtsp, 460);
  388. }
  389. }
  390. source = it->second.media;
  391. it->second.status = 2;
  392. }
  393. source->Pause();
  394. // 457 Invalid Range
  395. return rtsp_server_reply_pause(rtsp, 200);
  396. }
  397. static int rtsp_onteardown(void* /*ptr*/, rtsp_server_t* rtsp, const char* /*uri*/, const char* session)
  398. {
  399. std::shared_ptr<IMediaSource> source;
  400. TSessions::iterator it;
  401. {
  402. AutoThreadLocker locker(s_locker);
  403. it = s_sessions.find(session ? session : "");
  404. if(it == s_sessions.end())
  405. {
  406. // 454 Session Not Found
  407. return rtsp_server_reply_teardown(rtsp, 454);
  408. }
  409. source = it->second.media;
  410. s_sessions.erase(it);
  411. }
  412. return rtsp_server_reply_teardown(rtsp, 200);
  413. }
  414. static int rtsp_onannounce(void* /*ptr*/, rtsp_server_t* rtsp, const char* uri, const char* sdp, int len)
  415. {
  416. return rtsp_server_reply_announce(rtsp, 200);
  417. }
  418. static int rtsp_onrecord(void* /*ptr*/, rtsp_server_t* rtsp, const char* uri, const char* session, const int64_t *npt, const double *scale)
  419. {
  420. return rtsp_server_reply_record(rtsp, 200, NULL, NULL);
  421. }
  422. static int rtsp_onoptions(void* ptr, rtsp_server_t* rtsp, const char* uri)
  423. {
  424. const char* require = rtsp_server_get_header(rtsp, "Require");
  425. return rtsp_server_reply_options(rtsp, 200);
  426. }
  427. static int rtsp_ongetparameter(void* ptr, rtsp_server_t* rtsp, const char* uri, const char* session, const void* content, int bytes)
  428. {
  429. const char* ctype = rtsp_server_get_header(rtsp, "Content-Type");
  430. const char* encoding = rtsp_server_get_header(rtsp, "Content-Encoding");
  431. const char* language = rtsp_server_get_header(rtsp, "Content-Language");
  432. return rtsp_server_reply_get_parameter(rtsp, 200, NULL, 0);
  433. }
  434. static int rtsp_onsetparameter(void* ptr, rtsp_server_t* rtsp, const char* uri, const char* session, const void* content, int bytes)
  435. {
  436. const char* ctype = rtsp_server_get_header(rtsp, "Content-Type");
  437. const char* encoding = rtsp_server_get_header(rtsp, "Content-Encoding");
  438. const char* language = rtsp_server_get_header(rtsp, "Content-Language");
  439. return rtsp_server_reply_set_parameter(rtsp, 200);
  440. }
  441. static int rtsp_onclose(void* /*ptr2*/)
  442. {
  443. // TODO: notify rtsp connection lost
  444. // start a timer to check rtp/rtcp activity
  445. // close rtsp media session on expired
  446. printf("rtsp close\n");
  447. return 0;
  448. }
  449. static void rtsp_onerror(void* /*param*/, rtsp_server_t* rtsp, int code)
  450. {
  451. printf("rtsp_onerror code=%d, rtsp=%p\n", code, rtsp);
  452. TSessions::iterator it;
  453. AutoThreadLocker locker(s_locker);
  454. for (it = s_sessions.begin(); it != s_sessions.end(); ++it)
  455. {
  456. if (rtsp == it->second.rtsp)
  457. {
  458. it->second.media->Pause();
  459. s_sessions.erase(it);
  460. break;
  461. }
  462. }
  463. //return 0;
  464. }
  465. #define N_AIO_THREAD 4
  466. extern "C" void rtsp_example()
  467. {
  468. aio_worker_init(N_AIO_THREAD);
  469. struct aio_rtsp_handler_t handler;
  470. memset(&handler, 0, sizeof(handler));
  471. handler.base.ondescribe = rtsp_ondescribe;
  472. handler.base.onsetup = rtsp_onsetup;
  473. handler.base.onplay = rtsp_onplay;
  474. handler.base.onpause = rtsp_onpause;
  475. handler.base.onteardown = rtsp_onteardown;
  476. handler.base.close = rtsp_onclose;
  477. handler.base.onannounce = rtsp_onannounce;
  478. handler.base.onrecord = rtsp_onrecord;
  479. handler.base.onoptions = rtsp_onoptions;
  480. handler.base.ongetparameter = rtsp_ongetparameter;
  481. handler.base.onsetparameter = rtsp_onsetparameter;
  482. // handler.base.send; // ignore
  483. handler.onerror = rtsp_onerror;
  484. // 1. check s_workdir, MUST be end with '/' or '\\'
  485. // 2. url: rtsp://127.0.0.1:8554/vod/<filename>
  486. void* tcp = rtsp_server_listen("0.0.0.0", 8554, &handler, NULL); assert(tcp);
  487. // void* udp = rtsp_transport_udp_create(NULL, 554, &handler, NULL); assert(udp);
  488. // test only
  489. while(1)
  490. {
  491. system_sleep(5);
  492. TSessions::iterator it;
  493. AutoThreadLocker locker(s_locker);
  494. for(it = s_sessions.begin(); it != s_sessions.end(); ++it)
  495. {
  496. rtsp_media_t &session = it->second;
  497. if(1 == session.status)
  498. session.media->Play();
  499. }
  500. // TODO: check rtsp session activity
  501. }
  502. aio_worker_clean(N_AIO_THREAD);
  503. rtsp_server_unlisten(tcp);
  504. // rtsp_transport_udp_destroy(udp);
  505. }
  506. #endif