|
|
|
@@ -378,6 +378,27 @@ static int udp_get_file_handle(URLContext *h) |
|
|
|
return s->udp_fd; |
|
|
|
} |
|
|
|
|
|
|
|
static int parse_source_list(char *buf, char **sources, int *num_sources, |
|
|
|
int max_sources) |
|
|
|
{ |
|
|
|
char *source_start; |
|
|
|
|
|
|
|
source_start = buf; |
|
|
|
while (1) { |
|
|
|
char *next = strchr(source_start, ','); |
|
|
|
if (next) |
|
|
|
*next = '\0'; |
|
|
|
sources[*num_sources] = av_strdup(source_start); |
|
|
|
if (!sources[*num_sources]) |
|
|
|
return AVERROR(ENOMEM); |
|
|
|
source_start = next + 1; |
|
|
|
(*num_sources)++; |
|
|
|
if (*num_sources >= max_sources || !next) |
|
|
|
break; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* put it in UDP context */ |
|
|
|
/* return non zero if error */ |
|
|
|
static int udp_open(URLContext *h, const char *uri, int flags) |
|
|
|
@@ -391,8 +412,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; |
|
|
|
h->max_packet_size = 1472; |
|
|
|
@@ -430,24 +451,15 @@ 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)) { |
|
|
|
char *source_start; |
|
|
|
|
|
|
|
source_start = buf; |
|
|
|
while (1) { |
|
|
|
char *next = strchr(source_start, ','); |
|
|
|
if (next) |
|
|
|
*next = '\0'; |
|
|
|
sources[num_sources] = av_strdup(source_start); |
|
|
|
if (!sources[num_sources]) |
|
|
|
goto fail; |
|
|
|
source_start = next + 1; |
|
|
|
num_sources++; |
|
|
|
if (num_sources >= FF_ARRAY_ELEMS(sources) || !next) |
|
|
|
break; |
|
|
|
} |
|
|
|
if (av_find_info_tag(buf, sizeof(buf), "sources", p)) { |
|
|
|
if (parse_source_list(buf, include_sources, &num_include_sources, |
|
|
|
FF_ARRAY_ELEMS(include_sources))) |
|
|
|
goto fail; |
|
|
|
} |
|
|
|
if (av_find_info_tag(buf, sizeof(buf), "block", p)) { |
|
|
|
if (parse_source_list(buf, exclude_sources, &num_exclude_sources, |
|
|
|
FF_ARRAY_ELEMS(exclude_sources))) |
|
|
|
goto fail; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@@ -506,20 +518,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; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@@ -548,16 +560,20 @@ static int udp_open(URLContext *h, const char *uri, int flags) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for (i = 0; i < num_sources; i++) |
|
|
|
av_free(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; |
|
|
|
return 0; |
|
|
|
fail: |
|
|
|
if (udp_fd >= 0) |
|
|
|
closesocket(udp_fd); |
|
|
|
for (i = 0; i < num_sources; i++) |
|
|
|
av_free(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); |
|
|
|
} |
|
|
|
|
|
|
|
|