[FFmpeg-devel] [PATCH] rtsp: proper implementation of RFC4570
Ed Torbett
ed.torbett at simulation-systems.co.uk
Fri Jul 26 12:38:00 CEST 2013
RFC4570 introduces the source-filter attribute to SDP files.
This patch fully implements this SDP file attribute according
to the syntax defined within the RFC.
Signed-off-by: Edward Torbett <ed.torbett at simulation-systems.co.uk>
---
libavformat/rtpproto.c | 135 ++++++++++++++++++++++++++++++++++++++-----------
libavformat/rtsp.c | 122 ++++++++++++++++++++++++++++++++++++++++----
libavformat/rtsp.h | 9 +++-
libavformat/udp.c | 71 ++++++++++++++++----------
4 files changed, 270 insertions(+), 67 deletions(-)
diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c
index 33affc3..53ad6d0 100644
--- a/libavformat/rtpproto.c
+++ b/libavformat/rtpproto.c
@@ -42,8 +42,8 @@
typedef struct RTPContext {
URLContext *rtp_hd, *rtcp_hd;
- int rtp_fd, rtcp_fd, ssm;
- struct sockaddr_storage ssm_addr;
+ int rtp_fd, rtcp_fd, nb_ssm_include_addrs, nb_ssm_exclude_addrs;
+ struct sockaddr_storage **ssm_include_addrs, **ssm_exclude_addrs;
} RTPContext;
/**
@@ -95,13 +95,13 @@ static struct addrinfo* rtp_resolve_host(const char *hostname, int port,
return res;
}
-static int compare_addr(const struct sockaddr_storage *a,
+static int rtp_compare_addr(const struct sockaddr_storage *a,
const struct sockaddr_storage *b)
{
if (a->ss_family != b->ss_family)
- return 1;
+ return 0;
if (a->ss_family == AF_INET) {
- return (((const struct sockaddr_in *)a)->sin_addr.s_addr !=
+ return (((const struct sockaddr_in *)a)->sin_addr.s_addr ==
((const struct sockaddr_in *)b)->sin_addr.s_addr);
}
@@ -109,10 +109,30 @@ static int compare_addr(const struct sockaddr_storage *a,
if (a->ss_family == AF_INET6) {
const uint8_t *s6_addr_a = ((const struct sockaddr_in6 *)a)->sin6_addr.s6_addr;
const uint8_t *s6_addr_b = ((const struct sockaddr_in6 *)b)->sin6_addr.s6_addr;
- return memcmp(s6_addr_a, s6_addr_b, 16);
+ return (0 == memcmp(s6_addr_a, s6_addr_b, 16));
}
#endif
- return 1;
+ return 0;
+}
+
+static int rtp_check_source_lists(RTPContext *s, struct sockaddr_storage *source_addr_ptr) {
+ int i;
+ if (s->nb_ssm_exclude_addrs) {
+ for (i = 0; i < s->nb_ssm_exclude_addrs; i++) {
+ if (rtp_compare_addr(source_addr_ptr, s->ssm_exclude_addrs[i]))
+ return 1;
+ }
+ }
+ if (s->nb_ssm_include_addrs) {
+ int no_match = 1;
+ for (i = 0; no_match && i < s->nb_ssm_include_addrs; i++) {
+ if (rtp_compare_addr(source_addr_ptr, s->ssm_include_addrs[i]))
+ no_match = 0;
+ }
+ if (no_match)
+ return 1;
+ }
+ return 0;
}
/**
@@ -139,7 +159,8 @@ static void build_udp_url(char *buf, int buf_size,
const char *hostname, int port,
int local_port, int ttl,
int max_packet_size, int connect,
- const char* sources)
+ const char* include_sources,
+ const char* exclude_sources)
{
ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL);
if (local_port >= 0)
@@ -151,8 +172,10 @@ static void build_udp_url(char *buf, int buf_size,
if (connect)
url_add_option(buf, buf_size, "connect=1");
url_add_option(buf, buf_size, "fifo_size=0");
- if (sources && sources[0])
- url_add_option(buf, buf_size, "sources=%s", sources);
+ if (include_sources && include_sources[0])
+ url_add_option(buf, buf_size, "sources=%s", include_sources);
+ if (exclude_sources && exclude_sources[0])
+ url_add_option(buf, buf_size, "block=%s", exclude_sources);
}
/**
@@ -173,17 +196,56 @@ static void build_udp_url(char *buf, int buf_size,
* if the local rtcp port is not set it will be the local rtp port + 1
*/
+static void rtp_parse_addr_list(char *buf, struct sockaddr_storage ***address_list_ptr, int *address_list_size_ptr) {
+ struct addrinfo *sourceaddr = NULL;
+ struct sockaddr_storage *source_addr;
+ char tmp = '\0', *p = buf, *next;
+
+ /* Resolve all of the IPs */
+
+ while (p && p[0]) {
+ next = strchr(p, ',');
+
+ if (next) {
+ tmp = *next;
+ *next = '\0';
+ }
+
+ source_addr = av_mallocz(sizeof(struct sockaddr_storage));
+ if (!source_addr)
+ break;
+
+ sourceaddr = rtp_resolve_host(p, 0,
+ SOCK_DGRAM, AF_UNSPEC,
+ 0);
+
+ memcpy(source_addr, sourceaddr->ai_addr, sourceaddr->ai_addrlen);
+ freeaddrinfo(sourceaddr);
+
+ dynarray_add(address_list_ptr, address_list_size_ptr, source_addr);
+
+ if (next) {
+ *next = tmp;
+ p = next + 1;
+ } else {
+ p = 0;
+ }
+ }
+}
+
static int rtp_open(URLContext *h, const char *uri, int flags)
{
RTPContext *s = h->priv_data;
int rtp_port, rtcp_port,
ttl, connect,
local_rtp_port, local_rtcp_port, max_packet_size;
- char hostname[256], sources[1024] = "";
+ char hostname[256], include_sources[1024] = "", exclude_sources[1024] = "";
char buf[1024];
char path[1024];
const char *p;
+ av_log(h, AV_LOG_DEBUG, "Opening URL: %s\n", uri);
+
av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
path, sizeof(path), uri);
/* extract parameters */
@@ -218,26 +280,18 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
connect = strtol(buf, NULL, 10);
}
if (av_find_info_tag(buf, sizeof(buf), "sources", p)) {
- struct addrinfo *sourceaddr = NULL;
- av_strlcpy(sources, buf, sizeof(sources));
-
- /* Try resolving the IP if only one IP is specified - we don't
- * support manually checking more than one IP. */
- if (!strchr(sources, ','))
- sourceaddr = rtp_resolve_host(sources, 0,
- SOCK_DGRAM, AF_UNSPEC,
- AI_NUMERICHOST);
- if (sourceaddr) {
- s->ssm = 1;
- memcpy(&s->ssm_addr, sourceaddr->ai_addr, sourceaddr->ai_addrlen);
- freeaddrinfo(sourceaddr);
- }
+ av_strlcpy(include_sources, buf, sizeof(include_sources));
+ rtp_parse_addr_list(buf, &s->ssm_include_addrs, &s->nb_ssm_include_addrs);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "block", p)) {
+ av_strlcpy(exclude_sources, buf, sizeof(exclude_sources));
+ rtp_parse_addr_list(buf, &s->ssm_exclude_addrs, &s->nb_ssm_exclude_addrs);
}
}
build_udp_url(buf, sizeof(buf),
hostname, rtp_port, local_rtp_port, ttl, max_packet_size,
- connect, sources);
+ connect, include_sources, exclude_sources);
if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
goto fail;
if (local_rtp_port>=0 && local_rtcp_port<0)
@@ -245,7 +299,7 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
build_udp_url(buf, sizeof(buf),
hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size,
- connect, sources);
+ connect, include_sources, exclude_sources);
if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
goto fail;
@@ -291,8 +345,9 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size)
continue;
return AVERROR(EIO);
}
- if (s->ssm && compare_addr(&from, &s->ssm_addr))
+ if (rtp_check_source_lists(s, &from))
continue;
+
break;
}
/* then RTP */
@@ -306,8 +361,9 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size)
continue;
return AVERROR(EIO);
}
- if (s->ssm && compare_addr(&from, &s->ssm_addr))
+ if (rtp_check_source_lists(s, &from))
continue;
+
break;
}
} else if (n < 0) {
@@ -340,6 +396,27 @@ static int rtp_write(URLContext *h, const uint8_t *buf, int size)
static int rtp_close(URLContext *h)
{
RTPContext *s = h->priv_data;
+ struct sockaddr_storage *source_addr;
+ int i;
+ if (s->nb_ssm_include_addrs) {
+ for (i = 0; i < s->nb_ssm_include_addrs; i++) {
+ source_addr = s->ssm_include_addrs[i];
+ if (source_addr)
+ av_free(source_addr);
+ }
+ av_freep(&s->ssm_include_addrs);
+ s->nb_ssm_include_addrs = 0;
+ }
+
+ if (s->nb_ssm_exclude_addrs) {
+ for (i = 0; i < s->nb_ssm_exclude_addrs; i++) {
+ source_addr = s->ssm_exclude_addrs[i];
+ if (source_addr)
+ av_free(source_addr);
+ }
+ av_freep(&s->ssm_exclude_addrs);
+ s->nb_ssm_exclude_addrs = 0;
+ }
ffurl_close(s->rtp_hd);
ffurl_close(s->rtcp_hd);
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index af574f1..ddc7d88 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -289,6 +289,10 @@ typedef struct SDPParseState {
struct sockaddr_storage default_ip;
int default_ttl;
int skip_media; ///< set if an unknown m= line occurs
+ int nb_default_include_source_addrs; /**< Number of source-specific multicast include source IP address (from SDP content) */
+ struct RTSPSource **default_include_source_addrs; /**< Source-specific multicast include source IP address (from SDP content) */
+ int nb_default_exclude_source_addrs; /**< Number of source-specific multicast exclude source IP address (from SDP content) */
+ struct RTSPSource **default_exclude_source_addrs; /**< Source-specific multicast exclude source IP address (from SDP content) */
} SDPParseState;
static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
@@ -301,6 +305,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
int payload_type, i;
AVStream *st;
RTSPStream *rtsp_st;
+ RTSPSource *rtsp_src, *rtsp_src2;
struct sockaddr_storage sdp_ip;
int ttl;
@@ -369,6 +374,21 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
rtsp_st->sdp_ip = s1->default_ip;
rtsp_st->sdp_ttl = s1->default_ttl;
+ for (i = 0; i < s1->nb_default_include_source_addrs; i++) {
+ rtsp_src = s1->default_include_source_addrs[i];
+ if (rtsp_src) {
+ rtsp_src2 = av_memdup(rtsp_src, sizeof(RTSPSource));
+ dynarray_add(&rtsp_st->include_source_addrs, &rtsp_st->nb_include_source_addrs, rtsp_src2);
+ }
+ }
+ for (i = 0; i < s1->nb_default_exclude_source_addrs; i++) {
+ rtsp_src = s1->default_exclude_source_addrs[i];
+ if (rtsp_src) {
+ rtsp_src2 = av_memdup(rtsp_src, sizeof(RTSPSource));
+ dynarray_add(&rtsp_st->exclude_source_addrs, &rtsp_st->nb_exclude_source_addrs, rtsp_src2);
+ }
+ }
+
get_word(buf1, sizeof(buf1), &p); /* port */
rtsp_st->sdp_port = atoi(buf1);
@@ -498,22 +518,41 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
p += strspn(p, SPACE_CHARS);
if (av_strstart(p, "inline:", &p))
get_word(rtsp_st->crypto_params, sizeof(rtsp_st->crypto_params), &p);
- } else if (av_strstart(p, "source-filter:", &p) && s->nb_streams > 0) {
+ } else if (av_strstart(p, "source-filter:", &p)) {
+ int exclude = 0;
get_word(buf1, sizeof(buf1), &p);
- if (strcmp(buf1, "incl"))
+ if(strcmp(buf1, "incl") && strcmp(buf1, "excl"))
return;
+ exclude = (0 == strcmp(buf1, "excl"));
get_word(buf1, sizeof(buf1), &p);
if (strcmp(buf1, "IN") != 0)
return;
get_word(buf1, sizeof(buf1), &p);
- if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6"))
+ if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6") && strcmp(buf1, "*"))
return;
- // not checking that the destination address actually matches
+ // not checking that the destination address actually matches or is wildcard
get_word(buf1, sizeof(buf1), &p);
- rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
- get_word(rtsp_st->source_addr, sizeof(rtsp_st->source_addr), &p);
+ while (*p != '\0') {
+ rtsp_src = av_mallocz(sizeof(RTSPSource));
+ get_word(rtsp_src->addr, sizeof(rtsp_src->addr), &p);
+ if (exclude) {
+ if (s->nb_streams == 0) {
+ dynarray_add(&s1->default_exclude_source_addrs, &s1->nb_default_exclude_source_addrs, rtsp_src);
+ } else {
+ rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
+ dynarray_add(&rtsp_st->exclude_source_addrs, &rtsp_st->nb_exclude_source_addrs, rtsp_src);
+ }
+ } else {
+ if (s->nb_streams == 0) {
+ dynarray_add(&s1->default_include_source_addrs, &s1->nb_default_include_source_addrs, rtsp_src);
+ } else {
+ rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
+ dynarray_add(&rtsp_st->include_source_addrs, &rtsp_st->nb_include_source_addrs, rtsp_src);
+ }
+ }
+ }
} else {
if (rt->server_type == RTSP_SERVER_WMS)
ff_wms_parse_sdp_a_line(s, p);
@@ -538,7 +577,7 @@ int ff_sdp_parse(AVFormatContext *s, const char *content)
{
RTSPState *rt = s->priv_data;
const char *p;
- int letter;
+ int letter, i;
/* Some SDP lines, particularly for Realmedia or ASF RTSP streams,
* contain long SDP lines containing complete ASF Headers (several
* kB) or arrays of MDPR (RM stream descriptor) headers plus
@@ -549,6 +588,7 @@ int ff_sdp_parse(AVFormatContext *s, const char *content)
* in rtpdec_xiph.c. */
char buf[16384], *q;
SDPParseState sdp_parse_state = { { 0 } }, *s1 = &sdp_parse_state;
+ RTSPSource *rtsp_src;
p = content;
for (;;) {
@@ -575,6 +615,28 @@ int ff_sdp_parse(AVFormatContext *s, const char *content)
if (*p == '\n')
p++;
}
+
+ if (s1->nb_default_include_source_addrs) {
+ for (i = 0; i < s1->nb_default_include_source_addrs; i++) {
+ rtsp_src = s1->default_include_source_addrs[i];
+ if (rtsp_src) {
+ av_free(rtsp_src);
+ }
+ }
+ av_freep(&s1->default_include_source_addrs);
+ s1->nb_default_include_source_addrs = 0;
+ }
+ if (s1->nb_default_exclude_source_addrs) {
+ for (i = 0; i < s1->nb_default_exclude_source_addrs; i++) {
+ rtsp_src = s1->default_exclude_source_addrs[i];
+ if (rtsp_src) {
+ av_free(rtsp_src);
+ }
+ }
+ av_freep(&s1->default_exclude_source_addrs);
+ s1->nb_default_exclude_source_addrs = 0;
+ }
+
rt->p = av_malloc(sizeof(struct pollfd)*2*(rt->nb_rtsp_streams+1));
if (!rt->p) return AVERROR(ENOMEM);
return 0;
@@ -618,8 +680,9 @@ void ff_rtsp_undo_setup(AVFormatContext *s)
void ff_rtsp_close_streams(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
- int i;
+ int i, j;
RTSPStream *rtsp_st;
+ RTSPSource *rtsp_src;
ff_rtsp_undo_setup(s);
for (i = 0; i < rt->nb_rtsp_streams; i++) {
@@ -628,6 +691,25 @@ void ff_rtsp_close_streams(AVFormatContext *s)
if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context)
rtsp_st->dynamic_handler->free(
rtsp_st->dynamic_protocol_context);
+ if (rtsp_st->nb_include_source_addrs) {
+ for (j = 0; j < rtsp_st->nb_include_source_addrs; j++) {
+ rtsp_src = rtsp_st->include_source_addrs[j];
+ if (rtsp_src)
+ av_free(rtsp_src);
+ }
+ av_freep(&rtsp_st->include_source_addrs);
+ rtsp_st->nb_include_source_addrs = 0;
+ }
+ if (rtsp_st->nb_exclude_source_addrs) {
+ for (j = 0; j < rtsp_st->nb_exclude_source_addrs; j++) {
+ rtsp_src = rtsp_st->exclude_source_addrs[j];
+ if (rtsp_src)
+ av_free(rtsp_src);
+ }
+ av_freep(&rtsp_st->exclude_source_addrs);
+ rtsp_st->nb_exclude_source_addrs = 0;
+ }
+
av_free(rtsp_st);
}
}
@@ -2061,9 +2143,10 @@ static int sdp_read_header(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
RTSPStream *rtsp_st;
- int size, i, err;
+ int size, i, j, err;
char *content;
char url[1024];
+ RTSPSource *rtsp_src;
if (!ff_network_init())
return AVERROR(EIO);
@@ -2100,8 +2183,25 @@ static int sdp_read_header(AVFormatContext *s)
"?localport=%d&ttl=%d&connect=%d", rtsp_st->sdp_port,
rtsp_st->sdp_ttl,
rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0);
- if (rtsp_st->source_addr[0])
- av_strlcatf(url, sizeof(url), "&sources=%s", rtsp_st->source_addr);
+
+ if (rtsp_st->nb_include_source_addrs) {
+ rtsp_src = rtsp_st->include_source_addrs[0];
+ av_strlcatf(url, sizeof(url), "&sources=%s", rtsp_src->addr);
+ for (j = 1; j < rtsp_st->nb_include_source_addrs; j++) {
+ rtsp_src = rtsp_st->include_source_addrs[j];
+ if (rtsp_src)
+ av_strlcatf(url, sizeof(url), ",%s", rtsp_src->addr);
+ }
+ }
+ if (rtsp_st->nb_exclude_source_addrs) {
+ rtsp_src = rtsp_st->exclude_source_addrs[0];
+ av_strlcatf(url, sizeof(url), "&block=%s", rtsp_src->addr);
+ for (j = 1; j < rtsp_st->nb_exclude_source_addrs; j++) {
+ rtsp_src = rtsp_st->exclude_source_addrs[j];
+ if (rtsp_src)
+ av_strlcatf(url, sizeof(url), ",%s", rtsp_src->addr);
+ }
+ }
if (ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
&s->interrupt_callback, NULL) < 0) {
err = AVERROR_INVALIDDATA;
diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h
index e4b1cd6..cdb9848 100644
--- a/libavformat/rtsp.h
+++ b/libavformat/rtsp.h
@@ -412,6 +412,10 @@ typedef struct RTSPState {
#define RTSP_FLAG_LISTEN 0x2 /**< Wait for incoming connections. */
#define RTSP_FLAG_CUSTOM_IO 0x4 /**< Do all IO via the AVIOContext. */
+typedef struct RTSPSource {
+ char addr[128]; /**< Source-specific multicast include source IP address (from SDP content) */
+} RTSPSource;
+
/**
* Describe a single stream, as identified by a single m= line block in the
* SDP content. In the case of RDT, one RTSPStream can represent multiple
@@ -435,7 +439,10 @@ typedef struct RTSPStream {
//@{
int sdp_port; /**< port (from SDP content) */
struct sockaddr_storage sdp_ip; /**< IP address (from SDP content) */
- char source_addr[100]; /**< Source-specific multicast source IP address (from SDP content) */
+ int nb_include_source_addrs; /**< Number of source-specific multicast include source IP address (from SDP content) */
+ struct RTSPSource **include_source_addrs; /**< Source-specific multicast include source IP address (from SDP content) */
+ int nb_exclude_source_addrs; /**< Number of source-specific multicast exclude source IP address (from SDP content) */
+ struct RTSPSource **exclude_source_addrs; /**< Source-specific multicast exclude source IP address (from SDP content) */
int sdp_ttl; /**< IP Time-To-Live (from SDP content) */
int sdp_payload_type; /**< payload type */
//@}
diff --git a/libavformat/udp.c b/libavformat/udp.c
index 744b990..259043f 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -237,7 +237,7 @@ static int udp_set_multicast_sources(int sockfd, struct sockaddr *addr,
int level = addr->sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
struct addrinfo *sourceaddr = udp_resolve_host(sources[i], 0,
SOCK_DGRAM, AF_UNSPEC,
- AI_NUMERICHOST);
+ 0);
if (!sourceaddr)
return AVERROR(ENOENT);
@@ -267,7 +267,7 @@ static int udp_set_multicast_sources(int sockfd, struct sockaddr *addr,
struct ip_mreq_source mreqs;
struct addrinfo *sourceaddr = udp_resolve_host(sources[i], 0,
SOCK_DGRAM, AF_UNSPEC,
- AI_NUMERICHOST);
+ 0);
if (!sourceaddr)
return AVERROR(ENOENT);
if (sourceaddr->ai_addr->sa_family != AF_INET) {
@@ -507,8 +507,8 @@ static int udp_open(URLContext *h, const char *uri, int flags)
struct sockaddr_storage my_addr;
socklen_t len;
int reuse_specified = 0;
- int i, include = 0, num_sources = 0;
- char *sources[32];
+ int i, num_include_sources = 0, num_exclude_sources = 0;
+ char *include_sources[32], *exclude_sources[32];
h->is_streamed = 1;
@@ -562,9 +562,7 @@ static int udp_open(URLContext *h, const char *uri, int flags)
if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) {
av_strlcpy(localaddr, buf, sizeof(localaddr));
}
- if (av_find_info_tag(buf, sizeof(buf), "sources", p))
- include = 1;
- if (include || av_find_info_tag(buf, sizeof(buf), "block", p)) {
+ if (av_find_info_tag(buf, sizeof(buf), "sources", p)) {
char *source_start;
source_start = buf;
@@ -572,12 +570,29 @@ static int udp_open(URLContext *h, const char *uri, int flags)
char *next = strchr(source_start, ',');
if (next)
*next = '\0';
- sources[num_sources] = av_strdup(source_start);
- if (!sources[num_sources])
+ include_sources[num_include_sources] = av_strdup(source_start);
+ if (!include_sources[num_include_sources])
goto fail;
source_start = next + 1;
- num_sources++;
- if (num_sources >= FF_ARRAY_ELEMS(sources) || !next)
+ num_include_sources++;
+ if (num_include_sources >= FF_ARRAY_ELEMS(include_sources) || !next)
+ break;
+ }
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "block", p)) {
+ char *source_start;
+
+ source_start = buf;
+ while (1) {
+ char *next = strchr(source_start, ',');
+ if (next)
+ *next = '\0';
+ exclude_sources[num_exclude_sources] = av_strdup(source_start);
+ if (!exclude_sources[num_exclude_sources])
+ goto fail;
+ source_start = next + 1;
+ num_exclude_sources++;
+ if (num_exclude_sources >= FF_ARRAY_ELEMS(exclude_sources) || !next)
break;
}
}
@@ -648,20 +663,20 @@ static int udp_open(URLContext *h, const char *uri, int flags)
}
if (h->flags & AVIO_FLAG_READ) {
/* input */
- if (num_sources == 0 || !include) {
+ if (num_include_sources && num_exclude_sources) {
+ av_log(h, AV_LOG_ERROR, "Simultaneously including and excluding multicast sources is not supported\n");
+ goto fail;
+ }
+ if (num_include_sources) {
+ if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, include_sources, num_include_sources, 1) < 0)
+ goto fail;
+ } else {
if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0)
goto fail;
-
- if (num_sources) {
- if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, sources, num_sources, 0) < 0)
- goto fail;
- }
- } else if (include && num_sources) {
- if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, sources, num_sources, 1) < 0)
+ }
+ if (num_exclude_sources) {
+ if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, exclude_sources, num_exclude_sources, 0) < 0)
goto fail;
- } else {
- av_log(NULL, AV_LOG_ERROR, "invalid udp settings: inclusive multicast but no sources given\n");
- goto fail;
}
}
}
@@ -690,8 +705,10 @@ static int udp_open(URLContext *h, const char *uri, int flags)
}
}
- for (i = 0; i < num_sources; i++)
- av_freep(&sources[i]);
+ for (i = 0; i < num_include_sources; i++)
+ av_freep(&include_sources[i]);
+ for (i = 0; i < num_exclude_sources; i++)
+ av_freep(&exclude_sources[i]);
s->udp_fd = udp_fd;
@@ -731,8 +748,10 @@ static int udp_open(URLContext *h, const char *uri, int flags)
if (udp_fd >= 0)
closesocket(udp_fd);
av_fifo_free(s->fifo);
- for (i = 0; i < num_sources; i++)
- av_freep(&sources[i]);
+ for (i = 0; i < num_include_sources; i++)
+ av_freep(&include_sources[i]);
+ for (i = 0; i < num_exclude_sources; i++)
+ av_freep(&exclude_sources[i]);
return AVERROR(EIO);
}
--
1.8.3.3
More information about the ffmpeg-devel
mailing list