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.

620 lines
21KB

  1. /*
  2. * RTP network protocol
  3. * Copyright (c) 2002 Fabrice Bellard
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * FFmpeg is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with FFmpeg; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. /**
  22. * @file
  23. * RTP protocol
  24. */
  25. #include "libavutil/parseutils.h"
  26. #include "libavutil/avstring.h"
  27. #include "libavutil/opt.h"
  28. #include "avformat.h"
  29. #include "avio_internal.h"
  30. #include "rtp.h"
  31. #include "rtpproto.h"
  32. #include "url.h"
  33. #include <stdarg.h>
  34. #include "internal.h"
  35. #include "network.h"
  36. #include "os_support.h"
  37. #include <fcntl.h>
  38. #if HAVE_POLL_H
  39. #include <sys/poll.h>
  40. #endif
  41. typedef struct RTPContext {
  42. const AVClass *class;
  43. URLContext *rtp_hd, *rtcp_hd;
  44. int rtp_fd, rtcp_fd, nb_ssm_include_addrs, nb_ssm_exclude_addrs;
  45. struct sockaddr_storage **ssm_include_addrs, **ssm_exclude_addrs;
  46. int write_to_source;
  47. struct sockaddr_storage last_rtp_source, last_rtcp_source;
  48. socklen_t last_rtp_source_len, last_rtcp_source_len;
  49. int ttl;
  50. int buffer_size;
  51. int rtcp_port, local_rtpport, local_rtcpport;
  52. int connect;
  53. int pkt_size;
  54. int dscp;
  55. char *sources;
  56. char *block;
  57. } RTPContext;
  58. #define OFFSET(x) offsetof(RTPContext, x)
  59. #define D AV_OPT_FLAG_DECODING_PARAM
  60. #define E AV_OPT_FLAG_ENCODING_PARAM
  61. static const AVOption options[] = {
  62. { "ttl", "Time to live (in milliseconds, multicast only)", OFFSET(ttl), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
  63. { "buffer_size", "Send/Receive buffer size (in bytes)", OFFSET(buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
  64. { "rtcp_port", "Custom rtcp port", OFFSET(rtcp_port), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
  65. { "local_rtpport", "Local rtp port", OFFSET(local_rtpport), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
  66. { "local_rtcpport", "Local rtcp port", OFFSET(local_rtcpport), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
  67. { "connect", "Connect socket", OFFSET(connect), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, .flags = D|E },
  68. { "write_to_source", "Send packets to the source address of the latest received packet", OFFSET(write_to_source), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, .flags = D|E },
  69. { "pkt_size", "Maximum packet size", OFFSET(pkt_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
  70. { "dscp", "DSCP class", OFFSET(dscp), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
  71. { "sources", "Source list", OFFSET(sources), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
  72. { "block", "Block list", OFFSET(block), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
  73. { NULL }
  74. };
  75. static const AVClass rtp_class = {
  76. .class_name = "rtp",
  77. .item_name = av_default_item_name,
  78. .option = options,
  79. .version = LIBAVUTIL_VERSION_INT,
  80. };
  81. /**
  82. * If no filename is given to av_open_input_file because you want to
  83. * get the local port first, then you must call this function to set
  84. * the remote server address.
  85. *
  86. * @param h media file context
  87. * @param uri of the remote server
  88. * @return zero if no error.
  89. */
  90. int ff_rtp_set_remote_url(URLContext *h, const char *uri)
  91. {
  92. RTPContext *s = h->priv_data;
  93. char hostname[256];
  94. int port, rtcp_port;
  95. const char *p;
  96. char buf[1024];
  97. char path[1024];
  98. av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
  99. path, sizeof(path), uri);
  100. rtcp_port = port + 1;
  101. p = strchr(uri, '?');
  102. if (p) {
  103. if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
  104. rtcp_port = strtol(buf, NULL, 10);
  105. }
  106. }
  107. ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port, "%s", path);
  108. ff_udp_set_remote_url(s->rtp_hd, buf);
  109. ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, rtcp_port, "%s", path);
  110. ff_udp_set_remote_url(s->rtcp_hd, buf);
  111. return 0;
  112. }
  113. static struct addrinfo* rtp_resolve_host(const char *hostname, int port,
  114. int type, int family, int flags)
  115. {
  116. struct addrinfo hints = { 0 }, *res = 0;
  117. int error;
  118. char service[16];
  119. snprintf(service, sizeof(service), "%d", port);
  120. hints.ai_socktype = type;
  121. hints.ai_family = family;
  122. hints.ai_flags = flags;
  123. if ((error = getaddrinfo(hostname, service, &hints, &res))) {
  124. res = NULL;
  125. av_log(NULL, AV_LOG_ERROR, "rtp_resolve_host: %s\n", gai_strerror(error));
  126. }
  127. return res;
  128. }
  129. static int compare_addr(const struct sockaddr_storage *a,
  130. const struct sockaddr_storage *b)
  131. {
  132. if (a->ss_family != b->ss_family)
  133. return 1;
  134. if (a->ss_family == AF_INET) {
  135. return (((const struct sockaddr_in *)a)->sin_addr.s_addr !=
  136. ((const struct sockaddr_in *)b)->sin_addr.s_addr);
  137. }
  138. #if HAVE_STRUCT_SOCKADDR_IN6
  139. if (a->ss_family == AF_INET6) {
  140. const uint8_t *s6_addr_a = ((const struct sockaddr_in6 *)a)->sin6_addr.s6_addr;
  141. const uint8_t *s6_addr_b = ((const struct sockaddr_in6 *)b)->sin6_addr.s6_addr;
  142. return memcmp(s6_addr_a, s6_addr_b, 16);
  143. }
  144. #endif
  145. return 1;
  146. }
  147. static int get_port(const struct sockaddr_storage *ss)
  148. {
  149. if (ss->ss_family == AF_INET)
  150. return ntohs(((const struct sockaddr_in *)ss)->sin_port);
  151. #if HAVE_STRUCT_SOCKADDR_IN6
  152. if (ss->ss_family == AF_INET6)
  153. return ntohs(((const struct sockaddr_in6 *)ss)->sin6_port);
  154. #endif
  155. return 0;
  156. }
  157. static void set_port(struct sockaddr_storage *ss, int port)
  158. {
  159. if (ss->ss_family == AF_INET)
  160. ((struct sockaddr_in *)ss)->sin_port = htons(port);
  161. #if HAVE_STRUCT_SOCKADDR_IN6
  162. else if (ss->ss_family == AF_INET6)
  163. ((struct sockaddr_in6 *)ss)->sin6_port = htons(port);
  164. #endif
  165. }
  166. static int rtp_check_source_lists(RTPContext *s, struct sockaddr_storage *source_addr_ptr)
  167. {
  168. int i;
  169. if (s->nb_ssm_exclude_addrs) {
  170. for (i = 0; i < s->nb_ssm_exclude_addrs; i++) {
  171. if (!compare_addr(source_addr_ptr, s->ssm_exclude_addrs[i]))
  172. return 1;
  173. }
  174. }
  175. if (s->nb_ssm_include_addrs) {
  176. for (i = 0; i < s->nb_ssm_include_addrs; i++) {
  177. if (!compare_addr(source_addr_ptr, s->ssm_include_addrs[i]))
  178. return 0;
  179. }
  180. return 1;
  181. }
  182. return 0;
  183. }
  184. /**
  185. * add option to url of the form:
  186. * "http://host:port/path?option1=val1&option2=val2...
  187. */
  188. static av_printf_format(3, 4) void url_add_option(char *buf, int buf_size, const char *fmt, ...)
  189. {
  190. char buf1[1024];
  191. va_list ap;
  192. va_start(ap, fmt);
  193. if (strchr(buf, '?'))
  194. av_strlcat(buf, "&", buf_size);
  195. else
  196. av_strlcat(buf, "?", buf_size);
  197. vsnprintf(buf1, sizeof(buf1), fmt, ap);
  198. av_strlcat(buf, buf1, buf_size);
  199. va_end(ap);
  200. }
  201. static void build_udp_url(RTPContext *s,
  202. char *buf, int buf_size,
  203. const char *hostname,
  204. int port, int local_port,
  205. const char *include_sources,
  206. const char *exclude_sources)
  207. {
  208. ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL);
  209. if (local_port >= 0)
  210. url_add_option(buf, buf_size, "localport=%d", local_port);
  211. if (s->ttl >= 0)
  212. url_add_option(buf, buf_size, "ttl=%d", s->ttl);
  213. if (s->buffer_size >= 0)
  214. url_add_option(buf, buf_size, "buffer_size=%d", s->buffer_size);
  215. if (s->pkt_size >= 0)
  216. url_add_option(buf, buf_size, "pkt_size=%d", s->pkt_size);
  217. if (s->connect)
  218. url_add_option(buf, buf_size, "connect=1");
  219. if (s->dscp >= 0)
  220. url_add_option(buf, buf_size, "dscp=%d", s->dscp);
  221. url_add_option(buf, buf_size, "fifo_size=0");
  222. if (include_sources && include_sources[0])
  223. url_add_option(buf, buf_size, "sources=%s", include_sources);
  224. if (exclude_sources && exclude_sources[0])
  225. url_add_option(buf, buf_size, "block=%s", exclude_sources);
  226. }
  227. static void rtp_parse_addr_list(URLContext *h, char *buf,
  228. struct sockaddr_storage ***address_list_ptr,
  229. int *address_list_size_ptr)
  230. {
  231. struct addrinfo *ai = NULL;
  232. struct sockaddr_storage *source_addr;
  233. char tmp = '\0', *p = buf, *next;
  234. /* Resolve all of the IPs */
  235. while (p && p[0]) {
  236. next = strchr(p, ',');
  237. if (next) {
  238. tmp = *next;
  239. *next = '\0';
  240. }
  241. ai = rtp_resolve_host(p, 0, SOCK_DGRAM, AF_UNSPEC, 0);
  242. if (ai) {
  243. source_addr = av_mallocz(sizeof(struct sockaddr_storage));
  244. if (!source_addr) {
  245. freeaddrinfo(ai);
  246. break;
  247. }
  248. memcpy(source_addr, ai->ai_addr, ai->ai_addrlen);
  249. freeaddrinfo(ai);
  250. dynarray_add(address_list_ptr, address_list_size_ptr, source_addr);
  251. } else {
  252. av_log(h, AV_LOG_WARNING, "Unable to resolve %s\n", p);
  253. }
  254. if (next) {
  255. *next = tmp;
  256. p = next + 1;
  257. } else {
  258. p = NULL;
  259. }
  260. }
  261. }
  262. /**
  263. * url syntax: rtp://host:port[?option=val...]
  264. * option: 'ttl=n' : set the ttl value (for multicast only)
  265. * 'rtcpport=n' : set the remote rtcp port to n
  266. * 'localrtpport=n' : set the local rtp port to n
  267. * 'localrtcpport=n' : set the local rtcp port to n
  268. * 'pkt_size=n' : set max packet size
  269. * 'connect=0/1' : do a connect() on the UDP socket
  270. * 'sources=ip[,ip]' : list allowed source IP addresses
  271. * 'block=ip[,ip]' : list disallowed source IP addresses
  272. * 'write_to_source=0/1' : send packets to the source address of the latest received packet
  273. * 'dscp=n' : set DSCP value to n (QoS)
  274. * deprecated option:
  275. * 'localport=n' : set the local port to n
  276. *
  277. * if rtcpport isn't set the rtcp port will be the rtp port + 1
  278. * if local rtp port isn't set any available port will be used for the local
  279. * rtp and rtcp ports
  280. * if the local rtcp port is not set it will be the local rtp port + 1
  281. */
  282. static int rtp_open(URLContext *h, const char *uri, int flags)
  283. {
  284. RTPContext *s = h->priv_data;
  285. int rtp_port;
  286. char hostname[256], include_sources[1024] = "", exclude_sources[1024] = "";
  287. char *sources = include_sources, *block = exclude_sources;
  288. char buf[1024];
  289. char path[1024];
  290. const char *p;
  291. int i, max_retry_count = 3;
  292. av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
  293. path, sizeof(path), uri);
  294. /* extract parameters */
  295. if (s->rtcp_port < 0)
  296. s->rtcp_port = rtp_port + 1;
  297. p = strchr(uri, '?');
  298. if (p) {
  299. if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) {
  300. s->ttl = strtol(buf, NULL, 10);
  301. }
  302. if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
  303. s->rtcp_port = strtol(buf, NULL, 10);
  304. }
  305. if (av_find_info_tag(buf, sizeof(buf), "localport", p)) {
  306. s->local_rtpport = strtol(buf, NULL, 10);
  307. }
  308. if (av_find_info_tag(buf, sizeof(buf), "localrtpport", p)) {
  309. s->local_rtpport = strtol(buf, NULL, 10);
  310. }
  311. if (av_find_info_tag(buf, sizeof(buf), "localrtcpport", p)) {
  312. s->local_rtcpport = strtol(buf, NULL, 10);
  313. }
  314. if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
  315. s->pkt_size = strtol(buf, NULL, 10);
  316. }
  317. if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
  318. s->connect = strtol(buf, NULL, 10);
  319. }
  320. if (av_find_info_tag(buf, sizeof(buf), "write_to_source", p)) {
  321. s->write_to_source = strtol(buf, NULL, 10);
  322. }
  323. if (av_find_info_tag(buf, sizeof(buf), "dscp", p)) {
  324. s->dscp = strtol(buf, NULL, 10);
  325. }
  326. if (av_find_info_tag(buf, sizeof(buf), "sources", p)) {
  327. av_strlcpy(include_sources, buf, sizeof(include_sources));
  328. rtp_parse_addr_list(h, buf, &s->ssm_include_addrs, &s->nb_ssm_include_addrs);
  329. } else {
  330. rtp_parse_addr_list(h, s->sources, &s->ssm_include_addrs, &s->nb_ssm_include_addrs);
  331. sources = s->sources;
  332. }
  333. if (av_find_info_tag(buf, sizeof(buf), "block", p)) {
  334. av_strlcpy(exclude_sources, buf, sizeof(exclude_sources));
  335. rtp_parse_addr_list(h, buf, &s->ssm_exclude_addrs, &s->nb_ssm_exclude_addrs);
  336. } else {
  337. rtp_parse_addr_list(h, s->block, &s->ssm_exclude_addrs, &s->nb_ssm_exclude_addrs);
  338. block = s->block;
  339. }
  340. }
  341. for (i = 0; i < max_retry_count; i++) {
  342. build_udp_url(s, buf, sizeof(buf),
  343. hostname, rtp_port, s->local_rtpport,
  344. sources, block);
  345. if (ffurl_open_whitelist(&s->rtp_hd, buf, flags, &h->interrupt_callback,
  346. NULL, h->protocol_whitelist) < 0)
  347. goto fail;
  348. s->local_rtpport = ff_udp_get_local_port(s->rtp_hd);
  349. if(s->local_rtpport == 65535) {
  350. s->local_rtpport = -1;
  351. continue;
  352. }
  353. if (s->local_rtcpport < 0) {
  354. s->local_rtcpport = s->local_rtpport + 1;
  355. build_udp_url(s, buf, sizeof(buf),
  356. hostname, s->rtcp_port, s->local_rtcpport,
  357. sources, block);
  358. if (ffurl_open_whitelist(&s->rtcp_hd, buf, flags,
  359. &h->interrupt_callback, NULL,
  360. h->protocol_whitelist) < 0) {
  361. s->local_rtpport = s->local_rtcpport = -1;
  362. continue;
  363. }
  364. break;
  365. }
  366. build_udp_url(s, buf, sizeof(buf),
  367. hostname, s->rtcp_port, s->local_rtcpport,
  368. sources, block);
  369. if (ffurl_open_whitelist(&s->rtcp_hd, buf, flags, &h->interrupt_callback,
  370. NULL, h->protocol_whitelist) < 0)
  371. goto fail;
  372. break;
  373. }
  374. /* just to ease handle access. XXX: need to suppress direct handle
  375. access */
  376. s->rtp_fd = ffurl_get_file_handle(s->rtp_hd);
  377. s->rtcp_fd = ffurl_get_file_handle(s->rtcp_hd);
  378. h->max_packet_size = s->rtp_hd->max_packet_size;
  379. h->is_streamed = 1;
  380. return 0;
  381. fail:
  382. if (s->rtp_hd)
  383. ffurl_close(s->rtp_hd);
  384. if (s->rtcp_hd)
  385. ffurl_close(s->rtcp_hd);
  386. return AVERROR(EIO);
  387. }
  388. static int rtp_read(URLContext *h, uint8_t *buf, int size)
  389. {
  390. RTPContext *s = h->priv_data;
  391. int len, n, i;
  392. struct pollfd p[2] = {{s->rtp_fd, POLLIN, 0}, {s->rtcp_fd, POLLIN, 0}};
  393. int poll_delay = h->flags & AVIO_FLAG_NONBLOCK ? 0 : 100;
  394. struct sockaddr_storage *addrs[2] = { &s->last_rtp_source, &s->last_rtcp_source };
  395. socklen_t *addr_lens[2] = { &s->last_rtp_source_len, &s->last_rtcp_source_len };
  396. for(;;) {
  397. if (ff_check_interrupt(&h->interrupt_callback))
  398. return AVERROR_EXIT;
  399. n = poll(p, 2, poll_delay);
  400. if (n > 0) {
  401. /* first try RTCP, then RTP */
  402. for (i = 1; i >= 0; i--) {
  403. if (!(p[i].revents & POLLIN))
  404. continue;
  405. *addr_lens[i] = sizeof(*addrs[i]);
  406. len = recvfrom(p[i].fd, buf, size, 0,
  407. (struct sockaddr *)addrs[i], addr_lens[i]);
  408. if (len < 0) {
  409. if (ff_neterrno() == AVERROR(EAGAIN) ||
  410. ff_neterrno() == AVERROR(EINTR))
  411. continue;
  412. return AVERROR(EIO);
  413. }
  414. if (rtp_check_source_lists(s, addrs[i]))
  415. continue;
  416. return len;
  417. }
  418. } else if (n < 0) {
  419. if (ff_neterrno() == AVERROR(EINTR))
  420. continue;
  421. return AVERROR(EIO);
  422. }
  423. if (h->flags & AVIO_FLAG_NONBLOCK)
  424. return AVERROR(EAGAIN);
  425. }
  426. return len;
  427. }
  428. static int rtp_write(URLContext *h, const uint8_t *buf, int size)
  429. {
  430. RTPContext *s = h->priv_data;
  431. int ret;
  432. URLContext *hd;
  433. if (size < 2)
  434. return AVERROR(EINVAL);
  435. if ((buf[0] & 0xc0) != (RTP_VERSION << 6))
  436. av_log(h, AV_LOG_WARNING, "Data doesn't look like RTP packets, "
  437. "make sure the RTP muxer is used\n");
  438. if (s->write_to_source) {
  439. int fd;
  440. struct sockaddr_storage *source, temp_source;
  441. socklen_t *source_len, temp_len;
  442. if (!s->last_rtp_source.ss_family && !s->last_rtcp_source.ss_family) {
  443. av_log(h, AV_LOG_ERROR,
  444. "Unable to send packet to source, no packets received yet\n");
  445. // Intentionally not returning an error here
  446. return size;
  447. }
  448. if (RTP_PT_IS_RTCP(buf[1])) {
  449. fd = s->rtcp_fd;
  450. source = &s->last_rtcp_source;
  451. source_len = &s->last_rtcp_source_len;
  452. } else {
  453. fd = s->rtp_fd;
  454. source = &s->last_rtp_source;
  455. source_len = &s->last_rtp_source_len;
  456. }
  457. if (!source->ss_family) {
  458. source = &temp_source;
  459. source_len = &temp_len;
  460. if (RTP_PT_IS_RTCP(buf[1])) {
  461. temp_source = s->last_rtp_source;
  462. temp_len = s->last_rtp_source_len;
  463. set_port(source, get_port(source) + 1);
  464. av_log(h, AV_LOG_INFO,
  465. "Not received any RTCP packets yet, inferring peer port "
  466. "from the RTP port\n");
  467. } else {
  468. temp_source = s->last_rtcp_source;
  469. temp_len = s->last_rtcp_source_len;
  470. set_port(source, get_port(source) - 1);
  471. av_log(h, AV_LOG_INFO,
  472. "Not received any RTP packets yet, inferring peer port "
  473. "from the RTCP port\n");
  474. }
  475. }
  476. if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
  477. ret = ff_network_wait_fd(fd, 1);
  478. if (ret < 0)
  479. return ret;
  480. }
  481. ret = sendto(fd, buf, size, 0, (struct sockaddr *) source,
  482. *source_len);
  483. return ret < 0 ? ff_neterrno() : ret;
  484. }
  485. if (RTP_PT_IS_RTCP(buf[1])) {
  486. /* RTCP payload type */
  487. hd = s->rtcp_hd;
  488. } else {
  489. /* RTP payload type */
  490. hd = s->rtp_hd;
  491. }
  492. ret = ffurl_write(hd, buf, size);
  493. return ret;
  494. }
  495. static int rtp_close(URLContext *h)
  496. {
  497. RTPContext *s = h->priv_data;
  498. int i;
  499. for (i = 0; i < s->nb_ssm_include_addrs; i++)
  500. av_freep(&s->ssm_include_addrs[i]);
  501. av_freep(&s->ssm_include_addrs);
  502. for (i = 0; i < s->nb_ssm_exclude_addrs; i++)
  503. av_freep(&s->ssm_exclude_addrs[i]);
  504. av_freep(&s->ssm_exclude_addrs);
  505. ffurl_close(s->rtp_hd);
  506. ffurl_close(s->rtcp_hd);
  507. return 0;
  508. }
  509. /**
  510. * Return the local rtp port used by the RTP connection
  511. * @param h media file context
  512. * @return the local port number
  513. */
  514. int ff_rtp_get_local_rtp_port(URLContext *h)
  515. {
  516. RTPContext *s = h->priv_data;
  517. return ff_udp_get_local_port(s->rtp_hd);
  518. }
  519. /**
  520. * Return the local rtcp port used by the RTP connection
  521. * @param h media file context
  522. * @return the local port number
  523. */
  524. int ff_rtp_get_local_rtcp_port(URLContext *h)
  525. {
  526. RTPContext *s = h->priv_data;
  527. return ff_udp_get_local_port(s->rtcp_hd);
  528. }
  529. static int rtp_get_file_handle(URLContext *h)
  530. {
  531. RTPContext *s = h->priv_data;
  532. return s->rtp_fd;
  533. }
  534. static int rtp_get_multi_file_handle(URLContext *h, int **handles,
  535. int *numhandles)
  536. {
  537. RTPContext *s = h->priv_data;
  538. int *hs = *handles = av_malloc(sizeof(**handles) * 2);
  539. if (!hs)
  540. return AVERROR(ENOMEM);
  541. hs[0] = s->rtp_fd;
  542. hs[1] = s->rtcp_fd;
  543. *numhandles = 2;
  544. return 0;
  545. }
  546. const URLProtocol ff_rtp_protocol = {
  547. .name = "rtp",
  548. .url_open = rtp_open,
  549. .url_read = rtp_read,
  550. .url_write = rtp_write,
  551. .url_close = rtp_close,
  552. .url_get_file_handle = rtp_get_file_handle,
  553. .url_get_multi_file_handle = rtp_get_multi_file_handle,
  554. .priv_data_size = sizeof(RTPContext),
  555. .flags = URL_PROTOCOL_FLAG_NETWORK,
  556. .priv_data_class = &rtp_class,
  557. };