diff options
Diffstat (limited to 'libavformat/rtpproto.c')
-rw-r--r-- | libavformat/rtpproto.c | 133 |
1 files changed, 110 insertions, 23 deletions
diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c index 21a96d2..0706cae 100644 --- a/libavformat/rtpproto.c +++ b/libavformat/rtpproto.c @@ -2,20 +2,20 @@ * RTP network protocol * Copyright (c) 2002 Fabrice Bellard * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -44,7 +44,7 @@ typedef struct RTPContext { const AVClass *class; - URLContext *rtp_hd, *rtcp_hd; + URLContext *rtp_hd, *rtcp_hd, *fec_hd; int rtp_fd, rtcp_fd, nb_ssm_include_addrs, nb_ssm_exclude_addrs; struct sockaddr_storage **ssm_include_addrs, **ssm_exclude_addrs; int write_to_source; @@ -55,8 +55,10 @@ typedef struct RTPContext { int rtcp_port, local_rtpport, local_rtcpport; int connect; int pkt_size; + int dscp; char *sources; char *block; + char *fec_options_str; } RTPContext; #define OFFSET(x) offsetof(RTPContext, x) @@ -68,11 +70,13 @@ static const AVOption options[] = { { "rtcp_port", "Custom rtcp port", OFFSET(rtcp_port), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "local_rtpport", "Local rtp port", OFFSET(local_rtpport), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "local_rtcpport", "Local rtcp port", OFFSET(local_rtcpport), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, - { "connect", "Connect socket", OFFSET(connect), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E }, - { "write_to_source", "Send packets to the source address of the latest received packet", OFFSET(write_to_source), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E }, + { "connect", "Connect socket", OFFSET(connect), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, .flags = D|E }, + { "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 }, { "pkt_size", "Maximum packet size", OFFSET(pkt_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, + { "dscp", "DSCP class", OFFSET(dscp), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "sources", "Source list", OFFSET(sources), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E }, { "block", "Block list", OFFSET(block), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E }, + { "fec", "FEC", OFFSET(fec_options_str), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = E }, { NULL } }; @@ -239,6 +243,9 @@ static void build_udp_url(RTPContext *s, url_add_option(buf, buf_size, "pkt_size=%d", s->pkt_size); if (s->connect) url_add_option(buf, buf_size, "connect=1"); + if (s->dscp >= 0) + url_add_option(buf, buf_size, "dscp=%d", s->dscp); + url_add_option(buf, buf_size, "fifo_size=0"); if (include_sources && include_sources[0]) url_add_option(buf, buf_size, "sources=%s", include_sources); if (exclude_sources && exclude_sources[0]) @@ -298,6 +305,7 @@ static void rtp_parse_addr_list(URLContext *h, char *buf, * 'sources=ip[,ip]' : list allowed source IP addresses * 'block=ip[,ip]' : list disallowed source IP addresses * 'write_to_source=0/1' : send packets to the source address of the latest received packet + * 'dscp=n' : set DSCP value to n (QoS) * deprecated option: * 'localport=n' : set the local port to n * @@ -310,12 +318,16 @@ static void rtp_parse_addr_list(URLContext *h, char *buf, static int rtp_open(URLContext *h, const char *uri, int flags) { RTPContext *s = h->priv_data; + AVDictionary *fec_opts = NULL; int rtp_port; char hostname[256], include_sources[1024] = "", exclude_sources[1024] = ""; char *sources = include_sources, *block = exclude_sources; + char *fec_protocol = NULL; char buf[1024]; char path[1024]; const char *p; + int i, max_retry_count = 3; + int rtcpflags; av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port, path, sizeof(path), uri); @@ -349,6 +361,9 @@ static int rtp_open(URLContext *h, const char *uri, int flags) if (av_find_info_tag(buf, sizeof(buf), "write_to_source", p)) { s->write_to_source = strtol(buf, NULL, 10); } + if (av_find_info_tag(buf, sizeof(buf), "dscp", p)) { + s->dscp = strtol(buf, NULL, 10); + } if (av_find_info_tag(buf, sizeof(buf), "sources", p)) { av_strlcpy(include_sources, buf, sizeof(include_sources)); @@ -366,19 +381,73 @@ static int rtp_open(URLContext *h, const char *uri, int flags) } } - build_udp_url(s, buf, sizeof(buf), - hostname, rtp_port, s->local_rtpport, sources, block); - if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL, - h->protocols, h) < 0) - goto fail; - if (s->local_rtpport >= 0 && s->local_rtcpport < 0) - s->local_rtcpport = ff_udp_get_local_port(s->rtp_hd) + 1; + if (s->fec_options_str) { + p = s->fec_options_str; + + if (!(fec_protocol = av_get_token(&p, "="))) { + av_log(h, AV_LOG_ERROR, "Failed to parse the FEC protocol value\n"); + goto fail; + } + if (strcmp(fec_protocol, "prompeg")) { + av_log(h, AV_LOG_ERROR, "Unsupported FEC protocol %s\n", fec_protocol); + goto fail; + } + + p = s->fec_options_str + strlen(fec_protocol); + while (*p && *p == '=') p++; - build_udp_url(s, buf, sizeof(buf), - hostname, s->rtcp_port, s->local_rtcpport, sources, block); - if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL, - h->protocols, h) < 0) - goto fail; + if (av_dict_parse_string(&fec_opts, p, "=", ":", 0) < 0) { + av_log(h, AV_LOG_ERROR, "Failed to parse the FEC options\n"); + goto fail; + } + if (s->ttl > 0) { + snprintf(buf, sizeof (buf), "%d", s->ttl); + av_dict_set(&fec_opts, "ttl", buf, 0); + } + } + + for (i = 0; i < max_retry_count; i++) { + build_udp_url(s, buf, sizeof(buf), + hostname, rtp_port, s->local_rtpport, + sources, block); + if (ffurl_open_whitelist(&s->rtp_hd, buf, flags, &h->interrupt_callback, + NULL, h->protocol_whitelist, h->protocol_blacklist, h) < 0) + goto fail; + s->local_rtpport = ff_udp_get_local_port(s->rtp_hd); + if(s->local_rtpport == 65535) { + s->local_rtpport = -1; + continue; + } + rtcpflags = flags | AVIO_FLAG_WRITE; + if (s->local_rtcpport < 0) { + s->local_rtcpport = s->local_rtpport + 1; + build_udp_url(s, buf, sizeof(buf), + hostname, s->rtcp_port, s->local_rtcpport, + sources, block); + if (ffurl_open_whitelist(&s->rtcp_hd, buf, rtcpflags, + &h->interrupt_callback, NULL, + h->protocol_whitelist, h->protocol_blacklist, h) < 0) { + s->local_rtpport = s->local_rtcpport = -1; + continue; + } + break; + } + build_udp_url(s, buf, sizeof(buf), + hostname, s->rtcp_port, s->local_rtcpport, + sources, block); + if (ffurl_open_whitelist(&s->rtcp_hd, buf, rtcpflags, &h->interrupt_callback, + NULL, h->protocol_whitelist, h->protocol_blacklist, h) < 0) + goto fail; + break; + } + + s->fec_hd = NULL; + if (fec_protocol) { + ff_url_join(buf, sizeof(buf), fec_protocol, NULL, hostname, rtp_port, NULL); + if (ffurl_open_whitelist(&s->fec_hd, buf, flags, &h->interrupt_callback, + &fec_opts, h->protocol_whitelist, h->protocol_blacklist, h) < 0) + goto fail; + } /* just to ease handle access. XXX: need to suppress direct handle access */ @@ -387,6 +456,10 @@ static int rtp_open(URLContext *h, const char *uri, int flags) h->max_packet_size = s->rtp_hd->max_packet_size; h->is_streamed = 1; + + av_free(fec_protocol); + av_dict_free(&fec_opts); + return 0; fail: @@ -394,6 +467,9 @@ static int rtp_open(URLContext *h, const char *uri, int flags) ffurl_close(s->rtp_hd); if (s->rtcp_hd) ffurl_close(s->rtcp_hd); + ffurl_closep(&s->fec_hd); + av_free(fec_protocol); + av_dict_free(&fec_opts); return AVERROR(EIO); } @@ -441,7 +517,7 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size) static int rtp_write(URLContext *h, const uint8_t *buf, int size) { RTPContext *s = h->priv_data; - int ret; + int ret, ret_fec; URLContext *hd; if (size < 2) @@ -510,7 +586,17 @@ static int rtp_write(URLContext *h, const uint8_t *buf, int size) hd = s->rtp_hd; } - ret = ffurl_write(hd, buf, size); + if ((ret = ffurl_write(hd, buf, size)) < 0) { + return ret; + } + + if (s->fec_hd && !RTP_PT_IS_RTCP(buf[1])) { + if ((ret_fec = ffurl_write(s->fec_hd, buf, size)) < 0) { + av_log(h, AV_LOG_ERROR, "Failed to send FEC\n"); + return ret_fec; + } + } + return ret; } @@ -520,14 +606,15 @@ static int rtp_close(URLContext *h) int i; for (i = 0; i < s->nb_ssm_include_addrs; i++) - av_free(s->ssm_include_addrs[i]); + av_freep(&s->ssm_include_addrs[i]); av_freep(&s->ssm_include_addrs); for (i = 0; i < s->nb_ssm_exclude_addrs; i++) - av_free(s->ssm_exclude_addrs[i]); + av_freep(&s->ssm_exclude_addrs[i]); av_freep(&s->ssm_exclude_addrs); ffurl_close(s->rtp_hd); ffurl_close(s->rtcp_hd); + ffurl_closep(&s->fec_hd); return 0; } |