3 * Copyright (c) 2002 Fabrice Bellard
5 * This file is part of FFmpeg.
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.
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.
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
27 #include "libavutil/mem.h"
28 #include "libavutil/parseutils.h"
29 #include "libavutil/avstring.h"
30 #include "libavutil/opt.h"
40 #include "os_support.h"
46 typedef struct RTPContext
{
48 URLContext
*rtp_hd
, *rtcp_hd
, *fec_hd
;
50 IPSourceFilters filters
;
52 struct sockaddr_storage last_rtp_source
, last_rtcp_source
;
53 socklen_t last_rtp_source_len
, last_rtcp_source_len
;
56 int rtcp_port
, local_rtpport
, local_rtcpport
;
62 char *fec_options_str
;
67 #define OFFSET(x) offsetof(RTPContext, x)
68 #define D AV_OPT_FLAG_DECODING_PARAM
69 #define E AV_OPT_FLAG_ENCODING_PARAM
70 #define DEPR AV_OPT_FLAG_DEPRECATED
71 static const AVOption options
[] = {
72 { "ttl", "Time to live (multicast only)", OFFSET(ttl
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, 255, .flags
= D
|E
},
73 { "buffer_size", "Send/Receive buffer size (in bytes)", OFFSET(buffer_size
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, INT_MAX
, .flags
= D
|E
},
74 { "rtcp_port", "Custom rtcp port", OFFSET(rtcp_port
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, INT_MAX
, .flags
= D
|E
},
75 { "rtcpport", "Custom rtcp port", OFFSET(rtcp_port
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, INT_MAX
, .flags
= D
|E
},
76 { "local_rtpport", "Local rtp port", OFFSET(local_rtpport
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, INT_MAX
, .flags
= D
|E
},
77 { "localrtpport", "Local rtp port", OFFSET(local_rtpport
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, INT_MAX
, .flags
= D
|E
},
78 { "localport", "Local rtp port", OFFSET(local_rtpport
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, INT_MAX
, .flags
= D
|E
|DEPR
},
79 { "local_rtcpport", "Local rtcp port", OFFSET(local_rtcpport
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, INT_MAX
, .flags
= D
|E
},
80 { "localrtcpport", "Local rtcp port", OFFSET(local_rtcpport
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, INT_MAX
, .flags
= D
|E
},
81 { "connect", "Connect socket", OFFSET(connect
), AV_OPT_TYPE_BOOL
, { .i64
= 0 }, 0, 1, .flags
= D
|E
},
82 { "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
},
83 { "pkt_size", "Maximum packet size", OFFSET(pkt_size
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, INT_MAX
, .flags
= D
|E
},
84 { "dscp", "DSCP class", OFFSET(dscp
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, INT_MAX
, .flags
= D
|E
},
85 { "timeout", "set timeout (in microseconds) of socket I/O operations", OFFSET(rw_timeout
), AV_OPT_TYPE_INT64
, { .i64
= -1 }, -1, INT64_MAX
, .flags
= D
|E
},
86 { "sources", "Source list", OFFSET(sources
), AV_OPT_TYPE_STRING
, { .str
= NULL
}, .flags
= D
|E
},
87 { "block", "Block list", OFFSET(block
), AV_OPT_TYPE_STRING
, { .str
= NULL
}, .flags
= D
|E
},
88 { "fec", "FEC", OFFSET(fec_options_str
), AV_OPT_TYPE_STRING
, { .str
= NULL
}, .flags
= E
},
89 { "localaddr", "Local address", OFFSET(localaddr
), AV_OPT_TYPE_STRING
, { .str
= NULL
}, .flags
= D
|E
},
93 static const AVClass rtp_class
= {
95 .item_name
= av_default_item_name
,
97 .version
= LIBAVUTIL_VERSION_INT
,
101 * If no filename is given to av_open_input_file because you want to
102 * get the local port first, then you must call this function to set
103 * the remote server address.
105 * @param h media file context
106 * @param uri of the remote server
107 * @return zero if no error.
110 int ff_rtp_set_remote_url(URLContext
*h
, const char *uri
)
112 RTPContext
*s
= h
->priv_data
;
120 av_url_split(NULL
, 0, NULL
, 0, hostname
, sizeof(hostname
), &port
,
121 path
, sizeof(path
), uri
);
122 rtcp_port
= port
+ 1;
124 p
= strchr(uri
, '?');
126 if (av_find_info_tag(buf
, sizeof(buf
), "rtcpport", p
)) {
127 rtcp_port
= strtol(buf
, NULL
, 10);
131 ff_url_join(buf
, sizeof(buf
), "udp", NULL
, hostname
, port
, "%s", path
);
132 ff_udp_set_remote_url(s
->rtp_hd
, buf
);
134 ff_url_join(buf
, sizeof(buf
), "udp", NULL
, hostname
, rtcp_port
, "%s", path
);
135 ff_udp_set_remote_url(s
->rtcp_hd
, buf
);
139 static int get_port(const struct sockaddr_storage
*ss
)
141 if (ss
->ss_family
== AF_INET
)
142 return ntohs(((const struct sockaddr_in
*)ss
)->sin_port
);
143 #if HAVE_STRUCT_SOCKADDR_IN6
144 if (ss
->ss_family
== AF_INET6
)
145 return ntohs(((const struct sockaddr_in6
*)ss
)->sin6_port
);
150 static void set_port(struct sockaddr_storage
*ss
, int port
)
152 if (ss
->ss_family
== AF_INET
)
153 ((struct sockaddr_in
*)ss
)->sin_port
= htons(port
);
154 #if HAVE_STRUCT_SOCKADDR_IN6
155 else if (ss
->ss_family
== AF_INET6
)
156 ((struct sockaddr_in6
*)ss
)->sin6_port
= htons(port
);
161 * add option to url of the form:
162 * "http://host:port/path?option1=val1&option2=val2...
165 static av_printf_format(3, 4) void url_add_option(char *buf
, int buf_size
, const char *fmt
, ...)
171 if (strchr(buf
, '?'))
172 av_strlcat(buf
, "&", buf_size
);
174 av_strlcat(buf
, "?", buf_size
);
175 vsnprintf(buf1
, sizeof(buf1
), fmt
, ap
);
176 av_strlcat(buf
, buf1
, buf_size
);
180 static void build_udp_url(RTPContext
*s
,
181 char *buf
, int buf_size
,
182 const char *hostname
,
183 const char *localaddr
,
184 int port
, int local_port
,
185 const char *include_sources
,
186 const char *exclude_sources
)
188 ff_url_join(buf
, buf_size
, "udp", NULL
, hostname
, port
, NULL
);
190 url_add_option(buf
, buf_size
, "localport=%d", local_port
);
192 url_add_option(buf
, buf_size
, "ttl=%d", s
->ttl
);
193 if (s
->buffer_size
>= 0)
194 url_add_option(buf
, buf_size
, "buffer_size=%d", s
->buffer_size
);
195 if (s
->pkt_size
>= 0)
196 url_add_option(buf
, buf_size
, "pkt_size=%d", s
->pkt_size
);
198 url_add_option(buf
, buf_size
, "connect=1");
200 url_add_option(buf
, buf_size
, "dscp=%d", s
->dscp
);
201 url_add_option(buf
, buf_size
, "fifo_size=0");
202 if (include_sources
&& include_sources
[0])
203 url_add_option(buf
, buf_size
, "sources=%s", include_sources
);
204 if (exclude_sources
&& exclude_sources
[0])
205 url_add_option(buf
, buf_size
, "block=%s", exclude_sources
);
206 if (localaddr
&& localaddr
[0])
207 url_add_option(buf
, buf_size
, "localaddr=%s", localaddr
);
211 * url syntax: rtp://host:port[?option=val...]
212 * option: 'ttl=n' : set the ttl value (for multicast only)
213 * 'rtcpport=n' : set the remote rtcp port to n
214 * 'localrtpport=n' : set the local rtp port to n
215 * 'localrtcpport=n' : set the local rtcp port to n
216 * 'pkt_size=n' : set max packet size
217 * 'connect=0/1' : do a connect() on the UDP socket
218 * 'sources=ip[,ip]' : list allowed source IP addresses
219 * 'block=ip[,ip]' : list disallowed source IP addresses
220 * 'write_to_source=0/1' : send packets to the source address of the latest received packet
221 * 'dscp=n' : set DSCP value to n (QoS)
223 * 'localport=n' : set the local port to n
225 * if rtcpport isn't set the rtcp port will be the rtp port + 1
226 * if local rtp port isn't set any available port will be used for the local
228 * if the local rtcp port is not set it will be the local rtp port + 1
231 static int rtp_open(URLContext
*h
, const char *uri
, int flags
)
233 RTPContext
*s
= h
->priv_data
;
234 AVDictionary
*fec_opts
= NULL
;
237 char *fec_protocol
= NULL
;
241 int i
, max_retry_count
= 3;
245 av_url_split(NULL
, 0, NULL
, 0, hostname
, sizeof(hostname
), &rtp_port
,
246 path
, sizeof(path
), uri
);
247 /* extract parameters */
248 if (s
->rtcp_port
< 0)
249 s
->rtcp_port
= rtp_port
+ 1;
251 p
= strchr(uri
, '?');
253 ret
= ff_parse_opts_from_query_string(s
, p
, 1);
258 if ((ret
= ff_ip_parse_sources(h
, s
->sources
, &s
->filters
)) < 0)
262 if ((ret
= ff_ip_parse_blocks(h
, s
->block
, &s
->filters
)) < 0)
265 if (s
->rw_timeout
>= 0)
266 h
->rw_timeout
= s
->rw_timeout
;
268 if (s
->fec_options_str
) {
269 p
= s
->fec_options_str
;
271 if (!(fec_protocol
= av_get_token(&p
, "="))) {
272 av_log(h
, AV_LOG_ERROR
, "Failed to parse the FEC protocol value\n");
273 ret
= AVERROR(EINVAL
);
276 if (strcmp(fec_protocol
, "prompeg")) {
277 av_log(h
, AV_LOG_ERROR
, "Unsupported FEC protocol %s\n", fec_protocol
);
278 ret
= AVERROR(EINVAL
);
282 p
= s
->fec_options_str
+ strlen(fec_protocol
);
283 while (*p
&& *p
== '=') p
++;
285 if (av_dict_parse_string(&fec_opts
, p
, "=", ":", 0) < 0) {
286 av_log(h
, AV_LOG_ERROR
, "Failed to parse the FEC options\n");
287 ret
= AVERROR(EINVAL
);
291 av_dict_set_int(&fec_opts
, "ttl", s
->ttl
, 0);
295 for (i
= 0; i
< max_retry_count
; i
++) {
296 const char *sources
= s
->sources
? s
->sources
: "";
297 const char *block
= s
->block
? s
->block
: "";
298 build_udp_url(s
, buf
, sizeof(buf
),
299 hostname
, s
->localaddr
, rtp_port
, s
->local_rtpport
,
301 ret
= ffurl_open_whitelist(&s
->rtp_hd
, buf
, flags
, &h
->interrupt_callback
,
302 NULL
, h
->protocol_whitelist
, h
->protocol_blacklist
, h
);
305 s
->local_rtpport
= ff_udp_get_local_port(s
->rtp_hd
);
306 if(s
->local_rtpport
== 65535) {
307 s
->local_rtpport
= -1;
310 rtcpflags
= flags
| AVIO_FLAG_WRITE
;
311 if (s
->local_rtcpport
< 0) {
312 s
->local_rtcpport
= s
->local_rtpport
+ 1;
313 build_udp_url(s
, buf
, sizeof(buf
),
314 hostname
, s
->localaddr
, s
->rtcp_port
, s
->local_rtcpport
,
316 if (ffurl_open_whitelist(&s
->rtcp_hd
, buf
, rtcpflags
,
317 &h
->interrupt_callback
, NULL
,
318 h
->protocol_whitelist
, h
->protocol_blacklist
, h
) < 0) {
319 s
->local_rtpport
= s
->local_rtcpport
= -1;
324 build_udp_url(s
, buf
, sizeof(buf
),
325 hostname
, s
->localaddr
, s
->rtcp_port
, s
->local_rtcpport
,
327 ret
= ffurl_open_whitelist(&s
->rtcp_hd
, buf
, rtcpflags
, &h
->interrupt_callback
,
328 NULL
, h
->protocol_whitelist
, h
->protocol_blacklist
, h
);
336 ff_url_join(buf
, sizeof(buf
), fec_protocol
, NULL
, hostname
, rtp_port
, NULL
);
337 ret
= ffurl_open_whitelist(&s
->fec_hd
, buf
, flags
, &h
->interrupt_callback
,
338 &fec_opts
, h
->protocol_whitelist
, h
->protocol_blacklist
, h
);
343 /* just to ease handle access. XXX: need to suppress direct handle
345 s
->rtp_fd
= ffurl_get_file_handle(s
->rtp_hd
);
346 s
->rtcp_fd
= ffurl_get_file_handle(s
->rtcp_hd
);
348 h
->max_packet_size
= s
->rtp_hd
->max_packet_size
;
351 av_free(fec_protocol
);
352 av_dict_free(&fec_opts
);
357 ff_ip_reset_filters(&s
->filters
);
358 ffurl_closep(&s
->rtp_hd
);
359 ffurl_closep(&s
->rtcp_hd
);
360 ffurl_closep(&s
->fec_hd
);
361 av_free(fec_protocol
);
362 av_dict_free(&fec_opts
);
366 static int rtp_read(URLContext
*h
, uint8_t *buf
, int size
)
368 RTPContext
*s
= h
->priv_data
;
370 struct pollfd p
[2] = {{s
->rtp_fd
, POLLIN
, 0}, {s
->rtcp_fd
, POLLIN
, 0}};
371 int poll_delay
= h
->flags
& AVIO_FLAG_NONBLOCK
? 0 : POLLING_TIME
;
372 struct sockaddr_storage
*addrs
[2] = { &s
->last_rtp_source
, &s
->last_rtcp_source
};
373 socklen_t
*addr_lens
[2] = { &s
->last_rtp_source_len
, &s
->last_rtcp_source_len
};
374 int runs
= h
->rw_timeout
/ 1000 / POLLING_TIME
;
377 if (ff_check_interrupt(&h
->interrupt_callback
))
379 n
= poll(p
, 2, poll_delay
);
381 /* first try RTCP, then RTP */
382 for (i
= 1; i
>= 0; i
--) {
383 if (!(p
[i
].revents
& POLLIN
))
385 *addr_lens
[i
] = sizeof(*addrs
[i
]);
386 len
= recvfrom(p
[i
].fd
, buf
, size
, 0,
387 (struct sockaddr
*)addrs
[i
], addr_lens
[i
]);
389 if (ff_neterrno() == AVERROR(EAGAIN
) ||
390 ff_neterrno() == AVERROR(EINTR
))
394 if (ff_ip_check_source_lists(addrs
[i
], &s
->filters
))
398 } else if (n
== 0 && h
->rw_timeout
> 0 && --runs
<= 0) {
399 return AVERROR(ETIMEDOUT
);
401 if (ff_neterrno() == AVERROR(EINTR
))
405 if (h
->flags
& AVIO_FLAG_NONBLOCK
)
406 return AVERROR(EAGAIN
);
410 static int rtp_write(URLContext
*h
, const uint8_t *buf
, int size
)
412 RTPContext
*s
= h
->priv_data
;
417 return AVERROR(EINVAL
);
419 if ((buf
[0] & 0xc0) != (RTP_VERSION
<< 6))
420 av_log(h
, AV_LOG_WARNING
, "Data doesn't look like RTP packets, "
421 "make sure the RTP muxer is used\n");
423 if (s
->write_to_source
) {
425 struct sockaddr_storage
*source
, temp_source
;
426 socklen_t
*source_len
, temp_len
;
427 if (!s
->last_rtp_source
.ss_family
&& !s
->last_rtcp_source
.ss_family
) {
428 av_log(h
, AV_LOG_ERROR
,
429 "Unable to send packet to source, no packets received yet\n");
430 // Intentionally not returning an error here
434 if (RTP_PT_IS_RTCP(buf
[1])) {
436 source
= &s
->last_rtcp_source
;
437 source_len
= &s
->last_rtcp_source_len
;
440 source
= &s
->last_rtp_source
;
441 source_len
= &s
->last_rtp_source_len
;
443 if (!source
->ss_family
) {
444 source
= &temp_source
;
445 source_len
= &temp_len
;
446 if (RTP_PT_IS_RTCP(buf
[1])) {
447 temp_source
= s
->last_rtp_source
;
448 temp_len
= s
->last_rtp_source_len
;
449 set_port(source
, get_port(source
) + 1);
450 av_log(h
, AV_LOG_INFO
,
451 "Not received any RTCP packets yet, inferring peer port "
452 "from the RTP port\n");
454 temp_source
= s
->last_rtcp_source
;
455 temp_len
= s
->last_rtcp_source_len
;
456 set_port(source
, get_port(source
) - 1);
457 av_log(h
, AV_LOG_INFO
,
458 "Not received any RTP packets yet, inferring peer port "
459 "from the RTCP port\n");
463 if (!(h
->flags
& AVIO_FLAG_NONBLOCK
)) {
464 ret
= ff_network_wait_fd(fd
, 1);
468 ret
= sendto(fd
, buf
, size
, 0, (struct sockaddr
*) source
,
471 return ret
< 0 ? ff_neterrno() : ret
;
474 if (RTP_PT_IS_RTCP(buf
[1])) {
475 /* RTCP payload type */
478 /* RTP payload type */
482 if ((ret
= ffurl_write(hd
, buf
, size
)) < 0) {
486 if (s
->fec_hd
&& !RTP_PT_IS_RTCP(buf
[1])) {
487 if ((ret_fec
= ffurl_write(s
->fec_hd
, buf
, size
)) < 0) {
488 av_log(h
, AV_LOG_ERROR
, "Failed to send FEC\n");
496 static int rtp_close(URLContext
*h
)
498 RTPContext
*s
= h
->priv_data
;
500 ff_ip_reset_filters(&s
->filters
);
502 ffurl_closep(&s
->rtp_hd
);
503 ffurl_closep(&s
->rtcp_hd
);
504 ffurl_closep(&s
->fec_hd
);
509 * Return the local rtp port used by the RTP connection
510 * @param h media file context
511 * @return the local port number
514 int ff_rtp_get_local_rtp_port(URLContext
*h
)
516 RTPContext
*s
= h
->priv_data
;
517 return ff_udp_get_local_port(s
->rtp_hd
);
521 * Return the local rtcp port used by the RTP connection
522 * @param h media file context
523 * @return the local port number
526 static int rtp_get_file_handle(URLContext
*h
)
528 RTPContext
*s
= h
->priv_data
;
532 static int rtp_get_multi_file_handle(URLContext
*h
, int **handles
,
535 RTPContext
*s
= h
->priv_data
;
536 int *hs
= *handles
= av_malloc(sizeof(**handles
) * 2);
538 return AVERROR(ENOMEM
);
545 const URLProtocol ff_rtp_protocol
= {
547 .url_open
= rtp_open
,
548 .url_read
= rtp_read
,
549 .url_write
= rtp_write
,
550 .url_close
= rtp_close
,
551 .url_get_file_handle
= rtp_get_file_handle
,
552 .url_get_multi_file_handle
= rtp_get_multi_file_handle
,
553 .priv_data_size
= sizeof(RTPContext
),
554 .flags
= URL_PROTOCOL_FLAG_NETWORK
,
555 .priv_data_class
= &rtp_class
,