diff --git a/libavformat/udp.c b/libavformat/udp.c index cfc5ae51db..72ff7905d5 100644 --- a/libavformat/udp.c +++ b/libavformat/udp.c @@ -35,6 +35,16 @@ #include #include "internal.h" #include "network.h" + + +#ifdef WIN32 +# define if_nametoindex( str ) atoi( str ) +#else +# include +# include +#endif + + #include "os_support.h" #include "url.h" @@ -100,11 +110,12 @@ static int udp_set_multicast_ttl(int sockfd, int mcastTTL, return 0; } -static int udp_join_multicast_group(int sockfd, struct sockaddr *addr) +static int udp_join_multicast_group(int sockfd, struct sockaddr *addr, int miface_nr) { #ifdef IP_ADD_MEMBERSHIP if (addr->sa_family == AF_INET) { struct ip_mreq mreq; + struct group_req gr; mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; mreq.imr_interface.s_addr= INADDR_ANY; @@ -112,6 +123,16 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr) av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno)); return -1; } + +#ifdef MCAST_JOIN_GROUP + memset(&gr, 0, sizeof(struct group_req)); + gr.gr_interface = miface_nr; + memcpy(&gr.gr_group, addr, sizeof(struct sockaddr_in)); + if (setsockopt(sockfd, SOL_IP, MCAST_JOIN_GROUP, &gr, sizeof(struct group_req)) < 0) { + av_log(NULL, AV_LOG_ERROR, "setsockopt(MCAST_JOIN_GROUP): %s\n", strerror(errno)); + return -1; + } +#endif } #endif #if HAVE_STRUCT_IPV6_MREQ && defined(IPPROTO_IPV6) @@ -259,6 +280,7 @@ static int udp_port(struct sockaddr_storage *addr, int addr_len) * option: 'ttl=n' : set the ttl value (for multicast only) * 'localport=n' : set the local port * 'pkt_size=n' : set max packet size + * 'miface=if' : set multicast input interface * 'reuse=1' : enable reusing the socket * * @param h media file context @@ -401,6 +423,7 @@ static int udp_open(URLContext *h, const char *uri, int flags) struct sockaddr_storage my_addr; int len; int reuse_specified = 0; + int miface_nr = 0; h->is_streamed = 1; h->max_packet_size = 1472; @@ -443,6 +466,9 @@ 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), "miface", p)) { + miface_nr = if_nametoindex (buf); + } } /* fill the dest addr */ @@ -500,7 +526,7 @@ static int udp_open(URLContext *h, const char *uri, int flags) } if (h->flags & AVIO_FLAG_READ) { /* input */ - if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0) + if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr, miface_nr) < 0) goto fail; } }