You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

457 lines
15KB

  1. #include "rtsp-media.h"
  2. #include "sdp.h"
  3. #include "sdp-options.h"
  4. #include "sdp-a-fmtp.h"
  5. #include "sdp-a-rtpmap.h"
  6. #include "sys/path.h"
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <stdarg.h>
  10. #include <string.h>
  11. #include <assert.h>
  12. static inline int scopy(struct rtsp_media_t* medias, char** dst, const char* src)
  13. {
  14. int n;
  15. n = snprintf(medias->ptr + medias->offset, sizeof(medias->ptr) - medias->offset, "%s", src);
  16. if (n < 0 || n >= (int)sizeof(medias->ptr) - medias->offset)
  17. return -1;
  18. *dst = medias->ptr + medias->offset;
  19. medias->offset += n + 1; // with '\0'
  20. return 0;
  21. }
  22. //static inline int vscopy(struct rtsp_media_t* medias, char** dst, const char* fmt, ...)
  23. //{
  24. // int n;
  25. // va_list args;
  26. // va_start(args, fmt);
  27. // n = vsnprintf(medias->ptr + medias->offset, sizeof(medias->ptr) - medias->offset, fmt, args);
  28. // va_end(args);
  29. //
  30. // if (n < 0 || n >= (int)sizeof(medias->ptr) - medias->offset)
  31. // return -1;
  32. // *dst = medias->ptr + medias->offset;
  33. // medias->offset += n + 1; // with '\0'
  34. // return 0;
  35. //}
  36. //
  37. //static inline int rtsp_media_aggregate_control_enable(void *sdp)
  38. //{
  39. // const char* control;
  40. //
  41. // // rfc 2326 C.1.1 Control URL (p80)
  42. // // If found at the session level, the attribute indicates the URL for aggregate control
  43. // control = sdp_attribute_find(sdp, "control");
  44. // return (control && *control) ? 1 : 0;
  45. //}
  46. // rfc 2326 C.1.1 Control URL (p81)
  47. // look for a base URL in the following order:
  48. // 1. The RTSP Content-Base field
  49. // 2. The RTSP Content-Location field
  50. // 3. The RTSP request URL
  51. int rtsp_media_set_url(struct rtsp_media_t* m, const char* base, const char* location, const char* request)
  52. {
  53. int r;
  54. char buffer[256] = { 0 };
  55. // C.1.1 Control URL (p81)
  56. // If this attribute contains only an asterisk (*), then the URL is
  57. // treated as if it were an empty embedded URL, and thus inherits the entire base URL.
  58. if (m->session_uri[0] && '*' != m->session_uri[0])
  59. {
  60. snprintf(buffer, sizeof(buffer)-1, "%s", m->session_uri);
  61. r = path_resolve2(m->session_uri, sizeof(m->session_uri)-1, buffer, base, location, request);
  62. }
  63. else if('*' == m->session_uri[0])
  64. {
  65. r = snprintf(m->session_uri, sizeof(m->session_uri) - 1, "%s", request);
  66. }
  67. else
  68. {
  69. // keep session uri empty
  70. r = 0;
  71. }
  72. if ('*' != m->uri[0])
  73. {
  74. snprintf(buffer, sizeof(buffer) - 1, "%s", m->uri);
  75. r = path_resolve2(m->uri, sizeof(m->uri) - 1, buffer, base, location, request);
  76. }
  77. else
  78. {
  79. r = snprintf(m->uri, sizeof(m->uri) - 1, "%s", request);
  80. }
  81. return r >= 0 ? 0 : r;
  82. }
  83. // RFC 6184 RTP Payload Format for H.264 Video
  84. // 8.2.1. Mapping of Payload Type Parameters to SDP
  85. // m=video 49170 RTP/AVP 98
  86. // a=rtpmap:98 H264/90000
  87. // a=fmtp:98 profile-level-id=42A01E;
  88. // packetization-mode=1;
  89. // sprop-parameter-sets=<parameter sets data>
  90. static void rtsp_media_onattr(void* param, const char* name, const char* value)
  91. {
  92. int i, n;
  93. int payload = -1;
  94. struct rtsp_media_t* media;
  95. media = (struct rtsp_media_t*)param;
  96. if (name)
  97. {
  98. if (0 == strcmp("rtpmap", name))
  99. {
  100. int rate = 0;
  101. char channel[64];
  102. char encoding[16 + sizeof(media->avformats[i].encoding)];
  103. if (strlen(value) < sizeof(encoding)) // make sure encoding have enough memory space
  104. {
  105. channel[0] = '\0';
  106. sdp_a_rtpmap(value, &payload, encoding, &rate, channel);
  107. for (i = 0; i < media->avformat_count; i++)
  108. {
  109. if (media->avformats[i].fmt == payload)
  110. {
  111. media->avformats[i].rate = rate;
  112. media->avformats[i].channel = *channel ? atoi(channel) : 1; // default 1-channel
  113. snprintf(media->avformats[i].encoding, sizeof(media->avformats[i].encoding), "%s", encoding);
  114. break;
  115. }
  116. }
  117. }
  118. }
  119. else if (0 == strcmp("fmtp", name))
  120. {
  121. n = (int)strlen(value);
  122. payload = atoi(value);
  123. for (i = 0; i < media->avformat_count && media->offset + n + 1 < sizeof(media->ptr); i++)
  124. {
  125. if (media->avformats[i].fmt != payload)
  126. continue;
  127. media->avformats[i].fmtp = media->ptr + media->offset;
  128. strcpy(media->avformats[i].fmtp, value);
  129. media->offset += n + 1;
  130. //if(0 == strcmp("H264", media->avformats[i].encoding))
  131. //{
  132. // struct sdp_a_fmtp_h264_t h264;
  133. // memset(&h264, 0, sizeof(h264));
  134. // sdp_a_fmtp_h264(value, &payload, &h264);
  135. // if(h264.flags & SDP_A_FMTP_H264_SPROP_PARAMETER_SETS)
  136. // snprintf(media->avformats[i].ps, sizeof(media->avformats[i].ps), "%s", h264.sprop_parameter_sets);
  137. //}
  138. //else if (0 == strcmp("H265", media->avformats[i].encoding))
  139. //{
  140. // struct sdp_a_fmtp_h265_t h265;
  141. // memset(&h265, 0, sizeof(h265));
  142. // sdp_a_fmtp_h265(value, &payload, &h265);
  143. // //if (h265.flags & SDP_A_FMTP_H265_SPROP_VPS)
  144. // // snprintf(media->avformats[i].ps, sizeof(media->avformats[i].ps), "%s", h265.sprop_vps);
  145. // //if (h265.flags & SDP_A_FMTP_H265_SPROP_SPS)
  146. // // snprintf(media->avformats[i].ps, sizeof(media->avformats[i].ps), "%s", h265.sprop_sps);
  147. // //if (h265.flags & SDP_A_FMTP_H265_SPROP_PPS)
  148. // // snprintf(media->avformats[i].ps, sizeof(media->avformats[i].ps), "%s", h265.sprop_pps);
  149. //}
  150. //else if(0 == strcmp("mpeg4-generic", media->avformats[i].encoding))
  151. //{
  152. // struct sdp_a_fmtp_mpeg4_t mpeg4;
  153. // memset(&mpeg4, 0, sizeof(mpeg4));
  154. // sdp_a_fmtp_mpeg4(value, &payload, &mpeg4);
  155. //}
  156. break;
  157. }
  158. }
  159. else if (0 == strcmp("etag", name))
  160. {
  161. // C.1.8 Entity Tag
  162. }
  163. else if (0 == strcmp("rtcp", name))
  164. {
  165. // rfc3605 Real Time Control Protocol (RTCP) attribute in Session Description Protocol (SDP)
  166. // "a=rtcp:" port [nettype space addrtype space connection-address] CRLF
  167. // a=rtcp:53020 IN IP6 2001:2345:6789:ABCD:EF01:2345:6789:ABCD
  168. assert(media->nport <= 2 && sizeof(media->port)/sizeof(media->port[0]) >= 2);
  169. if (1 == media->nport)
  170. media->nport++;
  171. media->port[1] = atoi(value);
  172. // TODO: rtcp address
  173. }
  174. else if (0 == strcmp("rtcp-mux", name))
  175. {
  176. if (1 == media->nport)
  177. media->nport++;
  178. media->port[1] = media->port[0];
  179. }
  180. else if (0 == strcmp("rtcp-xr", name))
  181. {
  182. // rfc3611 RTP Control Protocol Extended Reports (RTCP XR)
  183. // "a=rtcp-xr:" [xr-format *(SP xr-format)] CRLF
  184. }
  185. else if (0 == strcmp("ice-pwd", name))
  186. {
  187. scopy(media, &media->ice.pwd, value);
  188. }
  189. else if (0 == strcmp("ice-ufrag", name))
  190. {
  191. scopy(media, &media->ice.ufrag, value);
  192. }
  193. else if (0 == strcmp("ice-lite", name))
  194. {
  195. media->ice.lite = 1;
  196. }
  197. else if (0 == strcmp("ice-mismatch", name))
  198. {
  199. media->ice.mismatch = 1;
  200. }
  201. else if (0 == strcmp("ice-pacing", name))
  202. {
  203. media->ice.pacing = atoi(value);
  204. }
  205. else if (0 == strcmp("candidate", name))
  206. {
  207. if (media->ice.candidate_count + 1 < sizeof(media->ice.candidates) / sizeof(media->ice.candidates[0]) && media->offset + sizeof(*media->ice.candidates[0]) <= sizeof(media->ptr))
  208. {
  209. media->ice.candidates[media->ice.candidate_count] = (struct sdp_candidate_t*)(media->ptr + media->offset);
  210. if (7 == sscanf(value, "%32s %hu %7s %u %63s %hu typ %7s%n",
  211. media->ice.candidates[media->ice.candidate_count]->foundation,
  212. &media->ice.candidates[media->ice.candidate_count]->component,
  213. media->ice.candidates[media->ice.candidate_count]->transport,
  214. &media->ice.candidates[media->ice.candidate_count]->priority,
  215. media->ice.candidates[media->ice.candidate_count]->address,
  216. &media->ice.candidates[media->ice.candidate_count]->port,
  217. media->ice.candidates[media->ice.candidate_count]->candtype, &n))
  218. {
  219. sscanf(value + n, " raddr %63s rport %hu", media->ice.candidates[media->ice.candidate_count]->reladdr, &media->ice.candidates[media->ice.candidate_count]->relport);
  220. media->offset += sizeof(*media->ice.candidates[0]);
  221. ++media->ice.candidate_count;
  222. }
  223. }
  224. }
  225. else if (0 == strcmp("remote-candidates", name))
  226. {
  227. while (media->ice.remote_count + 1 < sizeof(media->ice.remotes) / sizeof(media->ice.remotes[0]) && media->offset + sizeof(*media->ice.remotes[0]) <= sizeof(media->ptr))
  228. {
  229. media->ice.remotes[media->ice.remote_count] = (struct sdp_candidate_t*)(media->ptr + media->offset);
  230. if (!value || 3 != sscanf(value, "%hu %63s %hu%n", &media->ice.remotes[media->ice.remote_count]->component, media->ice.remotes[media->ice.remote_count]->address, &media->ice.remotes[media->ice.remote_count]->port, &n))
  231. break;
  232. value += n;
  233. ++media->ice.remote_count;
  234. media->offset += sizeof(*media->ice.remotes[0]);
  235. }
  236. }
  237. else if (0 == strcmp("setup", name))
  238. {
  239. media->setup = sdp_option_setup_from(value);
  240. }
  241. else if (0 == strcmp("ssrc", name))
  242. {
  243. media->ssrc.ssrc = (uint32_t)strtoul(value, NULL, 10);
  244. // TODO: ssrc attribute
  245. }
  246. else if (0 == strcmp("ssrc-group", name))
  247. {
  248. // TODO
  249. }
  250. }
  251. }
  252. /*
  253. v=0
  254. o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4
  255. s=SDP Seminar
  256. i=A Seminar on the session description protocol
  257. u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps
  258. e=mjh@isi.edu (Mark Handley)
  259. c=IN IP4 224.2.17.12/127
  260. t=2873397496 2873404696
  261. a=recvonly
  262. m=audio 3456 RTP/AVP 0
  263. m=video 2232 RTP/AVP 31
  264. m=whiteboard 32416 UDP WB
  265. a=orient:portrait
  266. */
  267. int rtsp_media_sdp(const char* s, int len, struct rtsp_media_t* medias, int count)
  268. {
  269. int i, j, n;
  270. int formats[16];
  271. const char* control;
  272. const char* start, *stop;
  273. const char* iceufrag, *icepwd;
  274. const char* username, *session, *version;
  275. const char* network, *addrtype, *address, *source;
  276. struct rtsp_media_t* m;
  277. struct rtsp_header_range_t range;
  278. sdp_t* sdp;
  279. sdp = sdp_parse(s, len);
  280. if (!sdp)
  281. return -1;
  282. // rfc 2326 C.1.1 Control URL (p80)
  283. // If found at the session level, the attribute indicates the URL for aggregate control
  284. control = sdp_attribute_find(sdp, "control");
  285. // C.1.5 Range of presentation
  286. // The "a=range" attribute defines the total time range of the stored session.
  287. memset(&range, 0, sizeof(range));
  288. s = sdp_attribute_find(sdp, "range");
  289. if(s) rtsp_header_range(s, &range);
  290. // C.1.6 Time of availability
  291. start = stop = NULL;
  292. for (i = 0; i < sdp_timing_count(sdp); i++)
  293. {
  294. sdp_timing_get(sdp, i, &start, &stop);
  295. }
  296. // C.1.7 Connection Information
  297. network = addrtype = source = NULL;
  298. if (0 != sdp_connection_get(sdp, &network, &addrtype, &source) || 0 == strcmp("0.0.0.0", source))
  299. sdp_origin_get(sdp, &username, &session, &version, &network, &addrtype, &source);
  300. // session ice-ufrag/ice-pwd
  301. iceufrag = sdp_attribute_find(sdp, "ice-ufrag");
  302. icepwd = sdp_attribute_find(sdp, "ice-pwd");
  303. for (i = 0; i < sdp_media_count(sdp) && i < count; i++)
  304. {
  305. m = medias + i;
  306. memset(m, 0, sizeof(struct rtsp_media_t));
  307. memcpy(&m->range, &range, sizeof(m->range));
  308. if (control)
  309. snprintf(m->session_uri, sizeof(m->session_uri), "%s", control);
  310. if (start && stop)
  311. {
  312. m->start = strtoull(start, NULL, 10);
  313. m->stop = strtoull(stop, NULL, 10);
  314. }
  315. if(0 == sdp_media_get_connection(sdp, i, &network, &addrtype, &address))
  316. {
  317. if (0 == strcmp("IP4", addrtype) && 0 == strcmp("0.0.0.0", address) && source && *source)
  318. address = source;
  319. snprintf(m->source, sizeof(m->source), "%s", source && *source ? source : "");
  320. snprintf(m->network, sizeof(m->network), "%s", network);
  321. snprintf(m->address, sizeof(m->address), "%s", address);
  322. snprintf(m->addrtype, sizeof(m->addrtype), "%s", addrtype);
  323. }
  324. //media->cseq = rand();
  325. m->nport = sdp_media_port(sdp, i, m->port, sizeof(m->port)/sizeof(m->port[0]));
  326. snprintf(m->media, sizeof(m->media), "%s", sdp_media_type(sdp, i));
  327. snprintf(m->proto, sizeof(m->proto), "%s", sdp_media_proto(sdp, i));
  328. if (1 == m->nport && 0 == strncmp("RTP/", m->proto, 4))
  329. m->port[m->nport++] = m->port[0] + 1;
  330. // media control url
  331. s = sdp_media_attribute_find(sdp, i, "control");
  332. if(s)
  333. snprintf(m->uri, sizeof(m->uri), "%s", s);
  334. // media format
  335. j = sizeof(m->avformats) / sizeof(m->avformats[0]);
  336. assert(sizeof(formats) / sizeof(formats[0]) >= j);
  337. n = sdp_media_formats(sdp, i, formats, j);
  338. m->avformat_count = n > j ? j : n;
  339. for (j = 0; j < m->avformat_count; j++)
  340. m->avformats[j].fmt = formats[j];
  341. // TODO: plan-B streams
  342. m->mode = sdp_media_mode(sdp, i);
  343. m->setup = SDP_A_SETUP_NONE;
  344. // update media encoding
  345. sdp_media_attribute_list(sdp, i, NULL, rtsp_media_onattr, m);
  346. // use default ice-ufrag/pwd
  347. if(NULL == m->ice.ufrag && iceufrag)
  348. scopy(medias, &m->ice.ufrag, iceufrag);
  349. if(NULL == m->ice.pwd && icepwd)
  350. scopy(medias, &m->ice.pwd, icepwd);
  351. }
  352. count = sdp_media_count(sdp);
  353. sdp_destroy(sdp);
  354. return count; // should check return value
  355. }
  356. /// @return -0-no media, >0-ok, <0-error
  357. int rtsp_media_to_sdp(const struct rtsp_media_t* m, char* line, int bytes)
  358. {
  359. int i, n;
  360. int setup = 0;
  361. int port = m->port[0];
  362. if (SDP_M_PROTO_TEST_TCP(sdp_option_proto_from(m->proto)))
  363. {
  364. // try to set tcp active for sender side
  365. setup = (SDP_A_SETUP_NONE == m->setup || SDP_A_SETUP_ACTPASS == m->setup) ? SDP_A_SETUP_ACTIVE : m->setup;
  366. //if (SDP_A_SETUP_PASSIVE == setup || SDP_A_SETUP_ACTPASS == setup)
  367. // port = options->m[i].port[0];
  368. }
  369. n = snprintf(line, bytes, "m=%s %d %s", m->media, port, m->proto);
  370. for (i = 0; i < m->avformat_count; i++)
  371. {
  372. if (m->avformats[i].fmt >= 96 && !m->avformats[i].encoding[0])
  373. continue; // ignore empty encoding
  374. n += snprintf(line + n, bytes - n, " %d", m->avformats[i].fmt);
  375. }
  376. n += snprintf(line + n, bytes - n, "\n");
  377. for (i = 0; i < m->avformat_count && n >= 0 && n < bytes; i++)
  378. {
  379. if (!m->avformats[i].encoding[0])
  380. continue;
  381. if (SDP_M_MEDIA_VIDEO == sdp_option_media_from(m->media))
  382. {
  383. n += snprintf(line + n, bytes - n, "a=rtpmap:%d %s/%d\n", m->avformats[i].fmt, m->avformats[i].encoding, m->avformats[i].rate ? m->avformats[i].rate : 90000);
  384. if(n >= 0 && n < bytes && m->avformats[i].fmtp && m->avformats[i].fmtp[0])
  385. n += snprintf(line + n, bytes - n, "a=fmtp:%s\n", m->avformats[i].fmtp);
  386. }
  387. else if (SDP_M_MEDIA_AUDIO == sdp_option_media_from(m->media))
  388. {
  389. if(m->avformats[i].channel > 0)
  390. n += snprintf(line + n, bytes - n, "a=rtpmap:%d %s/%d/%d\n", m->avformats[i].fmt, m->avformats[i].encoding, m->avformats[i].rate, m->avformats[i].channel);
  391. else
  392. n += snprintf(line + n, bytes - n, "a=rtpmap:%d %s/%d\n", m->avformats[i].fmt, m->avformats[i].encoding, m->avformats[i].rate);
  393. if (n >= 0 && n < bytes && m->avformats[i].fmtp && m->avformats[i].fmtp[0])
  394. n += snprintf(line + n, bytes - n, "a=fmtp:%s\n", m->avformats[i].fmtp);
  395. }
  396. }
  397. //for (int j = 0; j < 128 && j < 8 * sizeof(m->payloads) / sizeof(m->payloads[0]); j++)
  398. //{
  399. // if(m->payloads[j/8] & (1<<(j%8)))
  400. // n += snprintf(answer+n, sizeof(answer)-n, " %d", j);
  401. //}
  402. if (SDP_M_PROTO_TEST_TCP(sdp_option_proto_from(m->proto)))
  403. {
  404. n += snprintf(line + n, bytes - n, "a=setup:%s\n", sdp_option_setup_to(setup));
  405. }
  406. if (m->nport < 2 || m->port[0] == m->port[1])
  407. {
  408. n += snprintf(line + n, bytes - n, "a=rtcp-mux\n");
  409. }
  410. n += snprintf(line + n, bytes - n, "a=%s\n", sdp_option_mode_to(m->mode));
  411. if (m->ssrc.ssrc)
  412. {
  413. n += snprintf(line + n, bytes - n, "a=ssrc:%u\n", m->ssrc.ssrc);
  414. }
  415. return n > 0 && n < bytes ? n : -1;
  416. }