rtpproto.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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 libavformat/rtpproto.c
  23. * RTP protocol
  24. */
  25. #include "libavutil/avstring.h"
  26. #include "avformat.h"
  27. #include <unistd.h>
  28. #include <stdarg.h>
  29. #include "network.h"
  30. #include "os_support.h"
  31. #include <fcntl.h>
  32. #if HAVE_SYS_SELECT_H
  33. #include <sys/select.h>
  34. #endif
  35. #define RTP_TX_BUF_SIZE (64 * 1024)
  36. #define RTP_RX_BUF_SIZE (128 * 1024)
  37. typedef struct RTPContext {
  38. URLContext *rtp_hd, *rtcp_hd;
  39. int rtp_fd, rtcp_fd;
  40. } RTPContext;
  41. /**
  42. * If no filename is given to av_open_input_file because you want to
  43. * get the local port first, then you must call this function to set
  44. * the remote server address.
  45. *
  46. * @param s1 media file context
  47. * @param uri of the remote server
  48. * @return zero if no error.
  49. */
  50. int rtp_set_remote_url(URLContext *h, const char *uri)
  51. {
  52. RTPContext *s = h->priv_data;
  53. char hostname[256];
  54. int port;
  55. char buf[1024];
  56. char path[1024];
  57. url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
  58. path, sizeof(path), uri);
  59. snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port, path);
  60. udp_set_remote_url(s->rtp_hd, buf);
  61. snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port + 1, path);
  62. udp_set_remote_url(s->rtcp_hd, buf);
  63. return 0;
  64. }
  65. /**
  66. * add option to url of the form:
  67. * "http://host:port/path?option1=val1&option2=val2...
  68. */
  69. static void url_add_option(char *buf, int buf_size, const char *fmt, ...)
  70. {
  71. char buf1[1024];
  72. va_list ap;
  73. va_start(ap, fmt);
  74. if (strchr(buf, '?'))
  75. av_strlcat(buf, "&", buf_size);
  76. else
  77. av_strlcat(buf, "?", buf_size);
  78. vsnprintf(buf1, sizeof(buf1), fmt, ap);
  79. av_strlcat(buf, buf1, buf_size);
  80. va_end(ap);
  81. }
  82. static void build_udp_url(char *buf, int buf_size,
  83. const char *hostname, int port,
  84. int local_port, int ttl,
  85. int max_packet_size)
  86. {
  87. snprintf(buf, buf_size, "udp://%s:%d", hostname, port);
  88. if (local_port >= 0)
  89. url_add_option(buf, buf_size, "localport=%d", local_port);
  90. if (ttl >= 0)
  91. url_add_option(buf, buf_size, "ttl=%d", ttl);
  92. if (max_packet_size >=0)
  93. url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size);
  94. }
  95. /**
  96. * url syntax: rtp://host:port[?option=val...]
  97. * option: 'ttl=n' : set the ttl value (for multicast only)
  98. * 'localport=n' : set the local port to n
  99. * 'pkt_size=n' : set max packet size
  100. *
  101. */
  102. static int rtp_open(URLContext *h, const char *uri, int flags)
  103. {
  104. RTPContext *s;
  105. int port, is_output, ttl, local_port, max_packet_size;
  106. char hostname[256];
  107. char buf[1024];
  108. char path[1024];
  109. const char *p;
  110. is_output = (flags & URL_WRONLY);
  111. s = av_mallocz(sizeof(RTPContext));
  112. if (!s)
  113. return AVERROR(ENOMEM);
  114. h->priv_data = s;
  115. url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
  116. path, sizeof(path), uri);
  117. /* extract parameters */
  118. ttl = -1;
  119. local_port = -1;
  120. max_packet_size = -1;
  121. p = strchr(uri, '?');
  122. if (p) {
  123. if (find_info_tag(buf, sizeof(buf), "ttl", p)) {
  124. ttl = strtol(buf, NULL, 10);
  125. }
  126. if (find_info_tag(buf, sizeof(buf), "localport", p)) {
  127. local_port = strtol(buf, NULL, 10);
  128. }
  129. if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
  130. max_packet_size = strtol(buf, NULL, 10);
  131. }
  132. }
  133. build_udp_url(buf, sizeof(buf),
  134. hostname, port, local_port, ttl, max_packet_size);
  135. if (url_open(&s->rtp_hd, buf, flags) < 0)
  136. goto fail;
  137. local_port = udp_get_local_port(s->rtp_hd);
  138. /* XXX: need to open another connection if the port is not even */
  139. /* well, should suppress localport in path */
  140. build_udp_url(buf, sizeof(buf),
  141. hostname, port + 1, local_port + 1, ttl, max_packet_size);
  142. if (url_open(&s->rtcp_hd, buf, flags) < 0)
  143. goto fail;
  144. /* just to ease handle access. XXX: need to suppress direct handle
  145. access */
  146. s->rtp_fd = udp_get_file_handle(s->rtp_hd);
  147. s->rtcp_fd = udp_get_file_handle(s->rtcp_hd);
  148. h->max_packet_size = url_get_max_packet_size(s->rtp_hd);
  149. h->is_streamed = 1;
  150. return 0;
  151. fail:
  152. if (s->rtp_hd)
  153. url_close(s->rtp_hd);
  154. if (s->rtcp_hd)
  155. url_close(s->rtcp_hd);
  156. av_free(s);
  157. return AVERROR(EIO);
  158. }
  159. static int rtp_read(URLContext *h, uint8_t *buf, int size)
  160. {
  161. RTPContext *s = h->priv_data;
  162. struct sockaddr_in from;
  163. socklen_t from_len;
  164. int len, fd_max, n;
  165. fd_set rfds;
  166. #if 0
  167. for(;;) {
  168. from_len = sizeof(from);
  169. len = recvfrom (s->rtp_fd, buf, size, 0,
  170. (struct sockaddr *)&from, &from_len);
  171. if (len < 0) {
  172. if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
  173. ff_neterrno() == FF_NETERROR(EINTR))
  174. continue;
  175. return AVERROR(EIO);
  176. }
  177. break;
  178. }
  179. #else
  180. for(;;) {
  181. /* build fdset to listen to RTP and RTCP packets */
  182. FD_ZERO(&rfds);
  183. fd_max = s->rtp_fd;
  184. FD_SET(s->rtp_fd, &rfds);
  185. if (s->rtcp_fd > fd_max)
  186. fd_max = s->rtcp_fd;
  187. FD_SET(s->rtcp_fd, &rfds);
  188. n = select(fd_max + 1, &rfds, NULL, NULL, NULL);
  189. if (n > 0) {
  190. /* first try RTCP */
  191. if (FD_ISSET(s->rtcp_fd, &rfds)) {
  192. from_len = sizeof(from);
  193. len = recvfrom (s->rtcp_fd, buf, size, 0,
  194. (struct sockaddr *)&from, &from_len);
  195. if (len < 0) {
  196. if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
  197. ff_neterrno() == FF_NETERROR(EINTR))
  198. continue;
  199. return AVERROR(EIO);
  200. }
  201. break;
  202. }
  203. /* then RTP */
  204. if (FD_ISSET(s->rtp_fd, &rfds)) {
  205. from_len = sizeof(from);
  206. len = recvfrom (s->rtp_fd, buf, size, 0,
  207. (struct sockaddr *)&from, &from_len);
  208. if (len < 0) {
  209. if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
  210. ff_neterrno() == FF_NETERROR(EINTR))
  211. continue;
  212. return AVERROR(EIO);
  213. }
  214. break;
  215. }
  216. }
  217. }
  218. #endif
  219. return len;
  220. }
  221. static int rtp_write(URLContext *h, uint8_t *buf, int size)
  222. {
  223. RTPContext *s = h->priv_data;
  224. int ret;
  225. URLContext *hd;
  226. if (buf[1] >= 200 && buf[1] <= 204) {
  227. /* RTCP payload type */
  228. hd = s->rtcp_hd;
  229. } else {
  230. /* RTP payload type */
  231. hd = s->rtp_hd;
  232. }
  233. ret = url_write(hd, buf, size);
  234. #if 0
  235. {
  236. struct timespec ts;
  237. ts.tv_sec = 0;
  238. ts.tv_nsec = 10 * 1000000;
  239. nanosleep(&ts, NULL);
  240. }
  241. #endif
  242. return ret;
  243. }
  244. static int rtp_close(URLContext *h)
  245. {
  246. RTPContext *s = h->priv_data;
  247. url_close(s->rtp_hd);
  248. url_close(s->rtcp_hd);
  249. av_free(s);
  250. return 0;
  251. }
  252. /**
  253. * Return the local port used by the RTP connection
  254. * @param s1 media file context
  255. * @return the local port number
  256. */
  257. int rtp_get_local_port(URLContext *h)
  258. {
  259. RTPContext *s = h->priv_data;
  260. return udp_get_local_port(s->rtp_hd);
  261. }
  262. /**
  263. * Return the rtp and rtcp file handles for select() usage to wait for
  264. * several RTP streams at the same time.
  265. * @param h media file context
  266. */
  267. void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd)
  268. {
  269. RTPContext *s = h->priv_data;
  270. *prtp_fd = s->rtp_fd;
  271. *prtcp_fd = s->rtcp_fd;
  272. }
  273. URLProtocol rtp_protocol = {
  274. "rtp",
  275. rtp_open,
  276. rtp_read,
  277. rtp_write,
  278. NULL, /* seek */
  279. rtp_close,
  280. };