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/** 23 * @file 24 * RTP protocol 25 */ 26 27#include "libavutil/avstring.h" 28#include "avformat.h" 29#include "rtpdec.h" 30 31#include <unistd.h> 32#include <stdarg.h> 33#include "internal.h" 34#include "network.h" 35#include "os_support.h" 36#include <fcntl.h> 37#if HAVE_SYS_SELECT_H 38#include <sys/select.h> 39#endif 40#include <sys/time.h> 41 42#define RTP_TX_BUF_SIZE (64 * 1024) 43#define RTP_RX_BUF_SIZE (128 * 1024) 44 45typedef struct RTPContext { 46 URLContext *rtp_hd, *rtcp_hd; 47 int rtp_fd, rtcp_fd; 48} RTPContext; 49 50/** 51 * If no filename is given to av_open_input_file because you want to 52 * get the local port first, then you must call this function to set 53 * the remote server address. 54 * 55 * @param s1 media file context 56 * @param uri of the remote server 57 * @return zero if no error. 58 */ 59 60int rtp_set_remote_url(URLContext *h, const char *uri) 61{ 62 RTPContext *s = h->priv_data; 63 char hostname[256]; 64 int port; 65 66 char buf[1024]; 67 char path[1024]; 68 69 ff_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, 70 path, sizeof(path), uri); 71 72 ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port, "%s", path); 73 udp_set_remote_url(s->rtp_hd, buf); 74 75 ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port + 1, "%s", path); 76 udp_set_remote_url(s->rtcp_hd, buf); 77 return 0; 78} 79 80 81/** 82 * add option to url of the form: 83 * "http://host:port/path?option1=val1&option2=val2... 84 */ 85 86static void url_add_option(char *buf, int buf_size, const char *fmt, ...) 87{ 88 char buf1[1024]; 89 va_list ap; 90 91 va_start(ap, fmt); 92 if (strchr(buf, '?')) 93 av_strlcat(buf, "&", buf_size); 94 else 95 av_strlcat(buf, "?", buf_size); 96 vsnprintf(buf1, sizeof(buf1), fmt, ap); 97 av_strlcat(buf, buf1, buf_size); 98 va_end(ap); 99} 100 101static void build_udp_url(char *buf, int buf_size, 102 const char *hostname, int port, 103 int local_port, int ttl, 104 int max_packet_size) 105{ 106 ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL); 107 if (local_port >= 0) 108 url_add_option(buf, buf_size, "localport=%d", local_port); 109 if (ttl >= 0) 110 url_add_option(buf, buf_size, "ttl=%d", ttl); 111 if (max_packet_size >=0) 112 url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size); 113} 114 115/** 116 * url syntax: rtp://host:port[?option=val...] 117 * option: 'ttl=n' : set the ttl value (for multicast only) 118 * 'rtcpport=n' : set the remote rtcp port to n 119 * 'localrtpport=n' : set the local rtp port to n 120 * 'localrtcpport=n' : set the local rtcp port to n 121 * 'pkt_size=n' : set max packet size 122 * deprecated option: 123 * 'localport=n' : set the local port to n 124 * 125 * if rtcpport isn't set the rtcp port will be the rtp port + 1 126 * if local rtp port isn't set any available port will be used for the local 127 * rtp and rtcp ports 128 * if the local rtcp port is not set it will be the local rtp port + 1 129 */ 130 131static int rtp_open(URLContext *h, const char *uri, int flags) 132{ 133 RTPContext *s; 134 int rtp_port, rtcp_port, 135 is_output, ttl, 136 local_rtp_port, local_rtcp_port, max_packet_size; 137 char hostname[256]; 138 char buf[1024]; 139 char path[1024]; 140 const char *p; 141 142 is_output = (flags & URL_WRONLY); 143 144 s = av_mallocz(sizeof(RTPContext)); 145 if (!s) 146 return AVERROR(ENOMEM); 147 h->priv_data = s; 148 149 ff_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port, 150 path, sizeof(path), uri); 151 /* extract parameters */ 152 ttl = -1; 153 rtcp_port = rtp_port+1; 154 local_rtp_port = -1; 155 local_rtcp_port = -1; 156 max_packet_size = -1; 157 158 p = strchr(uri, '?'); 159 if (p) { 160 if (find_info_tag(buf, sizeof(buf), "ttl", p)) { 161 ttl = strtol(buf, NULL, 10); 162 } 163 if (find_info_tag(buf, sizeof(buf), "rtcpport", p)) { 164 rtcp_port = strtol(buf, NULL, 10); 165 } 166 if (find_info_tag(buf, sizeof(buf), "localport", p)) { 167 local_rtp_port = strtol(buf, NULL, 10); 168 } 169 if (find_info_tag(buf, sizeof(buf), "localrtpport", p)) { 170 local_rtp_port = strtol(buf, NULL, 10); 171 } 172 if (find_info_tag(buf, sizeof(buf), "localrtcpport", p)) { 173 local_rtcp_port = strtol(buf, NULL, 10); 174 } 175 if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) { 176 max_packet_size = strtol(buf, NULL, 10); 177 } 178 } 179 180 build_udp_url(buf, sizeof(buf), 181 hostname, rtp_port, local_rtp_port, ttl, max_packet_size); 182 if (url_open(&s->rtp_hd, buf, flags) < 0) 183 goto fail; 184 if (local_rtp_port>=0 && local_rtcp_port<0) 185 local_rtcp_port = udp_get_local_port(s->rtp_hd) + 1; 186 187 build_udp_url(buf, sizeof(buf), 188 hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size); 189 if (url_open(&s->rtcp_hd, buf, flags) < 0) 190 goto fail; 191 192 /* just to ease handle access. XXX: need to suppress direct handle 193 access */ 194 s->rtp_fd = url_get_file_handle(s->rtp_hd); 195 s->rtcp_fd = url_get_file_handle(s->rtcp_hd); 196 197 h->max_packet_size = url_get_max_packet_size(s->rtp_hd); 198 h->is_streamed = 1; 199 return 0; 200 201 fail: 202 if (s->rtp_hd) 203 url_close(s->rtp_hd); 204 if (s->rtcp_hd) 205 url_close(s->rtcp_hd); 206 av_free(s); 207 return AVERROR(EIO); 208} 209 210static int rtp_read(URLContext *h, uint8_t *buf, int size) 211{ 212 RTPContext *s = h->priv_data; 213 struct sockaddr_in from; 214 socklen_t from_len; 215 int len, fd_max, n; 216 fd_set rfds; 217 struct timeval tv; 218#if 0 219 for(;;) { 220 from_len = sizeof(from); 221 len = recvfrom (s->rtp_fd, buf, size, 0, 222 (struct sockaddr *)&from, &from_len); 223 if (len < 0) { 224 if (ff_neterrno() == FF_NETERROR(EAGAIN) || 225 ff_neterrno() == FF_NETERROR(EINTR)) 226 continue; 227 return AVERROR(EIO); 228 } 229 break; 230 } 231#else 232 for(;;) { 233 if (url_interrupt_cb()) 234 return AVERROR(EINTR); 235 /* build fdset to listen to RTP and RTCP packets */ 236 FD_ZERO(&rfds); 237 fd_max = s->rtp_fd; 238 FD_SET(s->rtp_fd, &rfds); 239 if (s->rtcp_fd > fd_max) 240 fd_max = s->rtcp_fd; 241 FD_SET(s->rtcp_fd, &rfds); 242 tv.tv_sec = 0; 243 tv.tv_usec = 100 * 1000; 244 n = select(fd_max + 1, &rfds, NULL, NULL, &tv); 245 if (n > 0) { 246 /* first try RTCP */ 247 if (FD_ISSET(s->rtcp_fd, &rfds)) { 248 from_len = sizeof(from); 249 len = recvfrom (s->rtcp_fd, buf, size, 0, 250 (struct sockaddr *)&from, &from_len); 251 if (len < 0) { 252 if (ff_neterrno() == FF_NETERROR(EAGAIN) || 253 ff_neterrno() == FF_NETERROR(EINTR)) 254 continue; 255 return AVERROR(EIO); 256 } 257 break; 258 } 259 /* then RTP */ 260 if (FD_ISSET(s->rtp_fd, &rfds)) { 261 from_len = sizeof(from); 262 len = recvfrom (s->rtp_fd, buf, size, 0, 263 (struct sockaddr *)&from, &from_len); 264 if (len < 0) { 265 if (ff_neterrno() == FF_NETERROR(EAGAIN) || 266 ff_neterrno() == FF_NETERROR(EINTR)) 267 continue; 268 return AVERROR(EIO); 269 } 270 break; 271 } 272 } else if (n < 0) { 273 if (ff_neterrno() == FF_NETERROR(EINTR)) 274 continue; 275 return AVERROR(EIO); 276 } 277 } 278#endif 279 return len; 280} 281 282static int rtp_write(URLContext *h, uint8_t *buf, int size) 283{ 284 RTPContext *s = h->priv_data; 285 int ret; 286 URLContext *hd; 287 288 if (buf[1] >= 200 && buf[1] <= 204) { 289 /* RTCP payload type */ 290 hd = s->rtcp_hd; 291 } else { 292 /* RTP payload type */ 293 hd = s->rtp_hd; 294 } 295 296 ret = url_write(hd, buf, size); 297#if 0 298 { 299 struct timespec ts; 300 ts.tv_sec = 0; 301 ts.tv_nsec = 10 * 1000000; 302 nanosleep(&ts, NULL); 303 } 304#endif 305 return ret; 306} 307 308static int rtp_close(URLContext *h) 309{ 310 RTPContext *s = h->priv_data; 311 312 url_close(s->rtp_hd); 313 url_close(s->rtcp_hd); 314 av_free(s); 315 return 0; 316} 317 318/** 319 * Return the local rtp port used by the RTP connection 320 * @param s1 media file context 321 * @return the local port number 322 */ 323 324int rtp_get_local_rtp_port(URLContext *h) 325{ 326 RTPContext *s = h->priv_data; 327 return udp_get_local_port(s->rtp_hd); 328} 329 330/** 331 * Return the local rtp port used by the RTP connection 332 * @param s1 media file context 333 * @return the local port number 334 */ 335 336int rtp_get_local_port(URLContext *h) 337{ 338 RTPContext *s = h->priv_data; 339 return udp_get_local_port(s->rtp_hd); 340} 341 342/** 343 * Return the local rtcp port used by the RTP connection 344 * @param s1 media file context 345 * @return the local port number 346 */ 347 348int rtp_get_local_rtcp_port(URLContext *h) 349{ 350 RTPContext *s = h->priv_data; 351 return udp_get_local_port(s->rtcp_hd); 352} 353 354#if (LIBAVFORMAT_VERSION_MAJOR <= 52) 355/** 356 * Return the rtp and rtcp file handles for select() usage to wait for 357 * several RTP streams at the same time. 358 * @param h media file context 359 */ 360 361void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd) 362{ 363 RTPContext *s = h->priv_data; 364 365 *prtp_fd = s->rtp_fd; 366 *prtcp_fd = s->rtcp_fd; 367} 368#endif 369 370static int rtp_get_file_handle(URLContext *h) 371{ 372 RTPContext *s = h->priv_data; 373 return s->rtp_fd; 374} 375 376URLProtocol rtp_protocol = { 377 "rtp", 378 rtp_open, 379 rtp_read, 380 rtp_write, 381 NULL, /* seek */ 382 rtp_close, 383 .url_get_file_handle = rtp_get_file_handle, 384}; 385