Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH v3 0/5] Select output interfaces for ipv6 multicast
       [not found] <0250811223419.GF29660@pb2>
@ 2025-08-29 14:04 ` Peter Enderborg via ffmpeg-devel
  2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 1/5] configure: Add test_ioctl and test for SIOCGIFINDEX Peter Enderborg via ffmpeg-devel
                     ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Peter Enderborg via ffmpeg-devel @ 2025-08-29 14:04 UTC (permalink / raw)
  To: michael, ffmpeg-devel, remi; +Cc: Peter Enderborg

History:
v2 Added configure script to disable interface selection for systems that
do not support ioctl SIOCGIFINDEX for mapping name to index-id.

v2.1 rebase

v3 Added patches for command-line options to select interface and
maximum number of interfaces.
Spited iterate function to use a helper function.

Peter Enderborg (5):
  configure: Add test_ioctl and test for SIOCGIFINDEX
  avformat/udp: Select output interfaces for ipv6 multicast
  libavformat: udp.c Add support for multi or single join
  libavformat: add multicast interface
  doc/protocols: Add command-line description for ipv6 options

 configure              |  16 ++++
 doc/protocols.texi     |  17 +++-
 libavformat/rtpproto.c |   7 ++
 libavformat/rtsp.c     |   6 +-
 libavformat/rtsp.h     |   2 +
 libavformat/udp.c      | 173 +++++++++++++++++++++++++++++++++++++++--
 6 files changed, 211 insertions(+), 10 deletions(-)

-- 
2.34.1

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [FFmpeg-devel] [PATCH v3 1/5] configure: Add test_ioctl and test for SIOCGIFINDEX
  2025-08-29 14:04 ` [FFmpeg-devel] [PATCH v3 0/5] Select output interfaces for ipv6 multicast Peter Enderborg via ffmpeg-devel
@ 2025-08-29 14:04   ` Peter Enderborg via ffmpeg-devel
  2025-08-29 17:38     ` [FFmpeg-devel] " Rémi Denis-Courmont via ffmpeg-devel
  2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 2/5] avformat/udp: Select output interfaces for ipv6 multicast Peter Enderborg via ffmpeg-devel
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 7+ messages in thread
From: Peter Enderborg via ffmpeg-devel @ 2025-08-29 14:04 UTC (permalink / raw)
  To: michael, ffmpeg-devel, remi; +Cc: Peter Enderborg

Adds a generic ioctl tester and a specific test  SIOCGIFINDEX
that sets ioctl_gifindex. It is a network specific feature
and the tests are run only in network context.

Signed-off-by: Peter Enderborg <peterend@axis.com>
---
 configure | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/configure b/configure
index 9fe28c5af4..b379a6bc92 100755
--- a/configure
+++ b/configure
@@ -1282,6 +1282,20 @@ int x;
 EOF
 }
 
+test_ioctl(){
+    log test_ioctl "$@"
+    ctl=$1
+    shift 1
+    test_cc "$@" <<EOF
+#include <stddef.h>
+#include <sys/ioctl.h>
+int f;
+void x(){
+ioctl(f, $ctl, NULL);
+}
+EOF
+}
+
 check_cflags(){
     log check_cflags "$@"
     test_cflags "$@" && add_cflags "$@"
@@ -2542,6 +2556,7 @@ HAVE_LIST="
     $TOOLCHAIN_FEATURES
     $TYPES_LIST
     gzip
+    ioctl_gifindex
     ioctl_posix
     libdrm_getfb2
     makeinfo
@@ -6658,6 +6673,7 @@ if ! disabled network; then
     else
         disable network
     fi
+    test_ioctl SIOCGIFINDEX && enable ioctl_gifindex
 fi
 
 check_builtin MemoryBarrier windows.h "MemoryBarrier()"
-- 
2.34.1

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [FFmpeg-devel] [PATCH v3 2/5] avformat/udp: Select output interfaces for ipv6 multicast
  2025-08-29 14:04 ` [FFmpeg-devel] [PATCH v3 0/5] Select output interfaces for ipv6 multicast Peter Enderborg via ffmpeg-devel
  2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 1/5] configure: Add test_ioctl and test for SIOCGIFINDEX Peter Enderborg via ffmpeg-devel
@ 2025-08-29 14:04   ` Peter Enderborg via ffmpeg-devel
  2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 3/5] libavformat: udp.c Add support for multi or single join Peter Enderborg via ffmpeg-devel
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Peter Enderborg via ffmpeg-devel @ 2025-08-29 14:04 UTC (permalink / raw)
  To: michael, ffmpeg-devel, remi; +Cc: Peter Enderborg

This fixes two old TODO's in ipv6 multicast handling.
If the system as SIOCGIFINDEX ioctl a helper function to iterate over
all interfaces added to join the multicast group on interface if approperite.

The default value is IN6ADDR_ANY (::) and it then joins all interfaces
that are up and have multicast support. Local address can be
specified and then it join ALL interfaces that use that specific
local address.

Limitations (TODO's)
Handling when network configuration is changed. if up/down etc.

Change-Id: Ifea9c0504469b108de94643a525d9b55fad5466f
Signed-off-by: Peter Enderborg <peterend@axis.com>
---
 libavformat/udp.c | 101 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 99 insertions(+), 2 deletions(-)

diff --git a/libavformat/udp.c b/libavformat/udp.c
index 84f9d3e62e..9ffd55e017 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -68,6 +68,13 @@
 #include "libavutil/thread.h"
 #endif
 
+#if HAVE_STRUCT_IPV6_MREQ && HAVE_IOCTL_GIFINDEX && defined(IPPROTO_IPV6)
+#include <sys/types.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <ifaddrs.h>
+#endif
+
 #ifndef IPV6_ADD_MEMBERSHIP
 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
 #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
@@ -205,6 +212,82 @@ static int udp_set_multicast_ttl(int sockfd, int mcastTTL,
 
     return 0;
 }
+#if HAVE_STRUCT_IPV6_MREQ && HAVE_IOCTL_GIFINDEX && defined(IPPROTO_IPV6)
+static int udp_ipv6_mc_devname_membership(int mop, const char *name,
+                                          int iindex_fd,struct in6_addr *mca,
+                                          int sockfd,void *logctx)
+{
+    struct ifreq if_req;
+    strncpy(if_req.ifr_name,name , IFNAMSIZ);
+
+    if (ioctl(iindex_fd, SIOCGIFINDEX, &if_req) != -1) {
+        struct ipv6_mreq mreq6;
+        memcpy(&mreq6.ipv6mr_multiaddr, mca, sizeof(struct in6_addr));
+        mreq6.ipv6mr_interface = if_req.ifr_ifindex;
+
+        switch (mop) {
+        case IPV6_JOIN_GROUP:
+            if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) == 0) {
+                return 1;
+            } else {
+                /* Subscribe for all ipv6 addresses belong to a
+                   interface.It can generate EADDRINUSE but
+                   is accaptable. */
+                if (errno != EADDRINUSE)
+                    ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP)");
+            }
+            break;
+        case IPV6_LEAVE_GROUP:
+            if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) == 0) {
+                return 1;
+            } else {
+                /* Unsubscribe for all ipv6 addresses belong to a
+                   interface. Ignore EADDRNOTAVAIL. */
+                if (errno != EADDRNOTAVAIL)
+                    ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP)");
+            }
+            break;
+        default:
+            av_log(logctx, AV_LOG_ERROR, "unknown multicast operation\n");
+        }
+    }
+    return -1;
+}
+
+static int udp_ipv6_multicast_iterate(int sockfd, struct sockaddr_in6 *addr,
+                                      struct sockaddr_in6 *local_addr, int mop, void *logctx)
+{
+    struct in6_addr anyipv6 = IN6ADDR_ANY_INIT;
+    struct ifaddrs *ifal=NULL,*ife=NULL;
+    int iindex_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+    int membership_changed = 0;
+
+    if (iindex_fd >= 0 && !getifaddrs(&ifal)) {
+        for(ife=ifal; ife!=NULL; ife=ife->ifa_next) {
+            if (ife->ifa_addr &&
+                (ife->ifa_addr->sa_family == AF_INET6) &&
+                (ife->ifa_flags & IFF_MULTICAST) &&
+                (ife->ifa_flags & IFF_UP)) {
+                if ((!memcmp(&local_addr->sin6_addr, &anyipv6, sizeof(struct in6_addr))) ||
+                    (!memcmp(&local_addr->sin6_addr, &((struct sockaddr_in6 *)ife->ifa_addr)->sin6_addr, sizeof(struct in6_addr)))) {
+                    if (udp_ipv6_mc_devname_membership(mop,ife->ifa_name,
+                                                       iindex_fd, &addr->sin6_addr,
+                                                       sockfd, logctx) == 1)
+                        membership_changed = 1;
+                }
+            }
+        }
+    }
+    freeifaddrs(ifal);
+    close(iindex_fd);
+
+    if (!membership_changed) {
+        av_log(logctx, AV_LOG_ERROR, "no valid interfaces found\n");
+        return AVERROR(EINVAL);
+    }
+    return 0;
+}
+#endif
 
 static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
                                     struct sockaddr *local_addr, void *logctx)
@@ -226,15 +309,22 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
 #endif
 #if HAVE_STRUCT_IPV6_MREQ && defined(IPPROTO_IPV6)
     if (addr->sa_family == AF_INET6) {
+#if HAVE_IOCTL_GIFINDEX
+        return udp_ipv6_multicast_iterate(sockfd,
+                                          (struct sockaddr_in6 *)addr,
+                                          (struct sockaddr_in6 *)local_addr,
+                                          IPV6_JOIN_GROUP,
+                                          logctx);
+#else
         struct ipv6_mreq mreq6;
 
         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
-        //TODO: Interface index should be looked up from local_addr
         mreq6.ipv6mr_interface = 0;
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP)");
             return ff_neterrno();
         }
+#endif
     }
 #endif
     return 0;
@@ -260,15 +350,22 @@ static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
 #endif
 #if HAVE_STRUCT_IPV6_MREQ && defined(IPPROTO_IPV6)
     if (addr->sa_family == AF_INET6) {
+#if HAVE_IOCTL_GIFINDEX
+        return udp_ipv6_multicast_iterate(sockfd,
+                                          (struct sockaddr_in6 *)addr,
+                                          (struct sockaddr_in6 *)local_addr,
+                                          IPV6_LEAVE_GROUP,
+                                          logctx);
+#else
         struct ipv6_mreq mreq6;
 
         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
-        //TODO: Interface index should be looked up from local_addr
         mreq6.ipv6mr_interface = 0;
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP)");
             return -1;
         }
+#endif
     }
 #endif
     return 0;
-- 
2.34.1

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [FFmpeg-devel] [PATCH v3 3/5] libavformat: udp.c Add support for multi or single join
  2025-08-29 14:04 ` [FFmpeg-devel] [PATCH v3 0/5] Select output interfaces for ipv6 multicast Peter Enderborg via ffmpeg-devel
  2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 1/5] configure: Add test_ioctl and test for SIOCGIFINDEX Peter Enderborg via ffmpeg-devel
  2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 2/5] avformat/udp: Select output interfaces for ipv6 multicast Peter Enderborg via ffmpeg-devel
@ 2025-08-29 14:04   ` Peter Enderborg via ffmpeg-devel
  2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 4/5] libavformat: add multicast interface Peter Enderborg via ffmpeg-devel
  2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 5/5] doc/protocols: Add command-line description for ipv6 options Peter Enderborg via ffmpeg-devel
  4 siblings, 0 replies; 7+ messages in thread
From: Peter Enderborg via ffmpeg-devel @ 2025-08-29 14:04 UTC (permalink / raw)
  To: michael, ffmpeg-devel, remi; +Cc: Peter Enderborg

A new commandline option to set for joining multiple
interfaces. The default is one, and it is also a
special case falling back to output routing table
for selecting interface on group join. On group
join it search over all interfaces.

Change-Id: Idbf88c3ecd7d27cba0a236a8fa2451a85143d068
Signed-off-by: Peter Enderborg <peterend@axis.com>
---
 libavformat/rtpproto.c |  3 ++
 libavformat/rtsp.c     |  3 +-
 libavformat/rtsp.h     |  1 +
 libavformat/udp.c      | 82 +++++++++++++++++++++++++++++++-----------
 4 files changed, 67 insertions(+), 22 deletions(-)

diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c
index 15d0050936..c6abd7a02c 100644
--- a/libavformat/rtpproto.c
+++ b/libavformat/rtpproto.c
@@ -61,6 +61,7 @@ typedef struct RTPContext {
     char *fec_options_str;
     int64_t rw_timeout;
     char *localaddr;
+    int multicast_max_join;
 } RTPContext;
 
 #define OFFSET(x) offsetof(RTPContext, x)
@@ -81,6 +82,7 @@ static const AVOption options[] = {
     { "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 },
     { "localaddr",          "Local address",                                                    OFFSET(localaddr),       AV_OPT_TYPE_STRING, { .str = NULL },               .flags = D|E },
+    { "multicast_max_join", "Number of ipv6 network intefaces to join multicast group",         OFFSET(multicast_max_join), AV_OPT_TYPE_INT,    { .i64 = 1 }, 1, INT_MAX, .flags = D|E },
     { NULL }
 };
 
@@ -199,6 +201,7 @@ static void build_udp_url(RTPContext *s,
         url_add_option(buf, buf_size, "block=%s", exclude_sources);
     if (localaddr && localaddr[0])
         url_add_option(buf, buf_size, "localaddr=%s", localaddr);
+    url_add_option(buf, buf_size, "multicast_max_join=%d", s->multicast_max_join);
 }
 
 /**
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index 10355b89b8..08ce628b0c 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -81,6 +81,7 @@
 #define COMMON_OPTS() \
     { "reorder_queue_size", "set number of packets to buffer for handling of reordered packets", OFFSET(reordering_queue_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC }, \
     { "buffer_size",        "Underlying protocol send/receive buffer size",                  OFFSET(buffer_size),           AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC|ENC }, \
+    { "multicast_max_join", "Number of ipv6 network intefaces to join multicast group",      OFFSET(multicast_max_join),           AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, ENC }, \
     { "pkt_size",           "Underlying protocol send packet size",                          OFFSET(pkt_size),              AV_OPT_TYPE_INT, { .i64 = 1472 }, -1, INT_MAX, ENC } \
 
 
@@ -139,7 +140,7 @@ static AVDictionary *map_to_opts(RTSPState *rt)
     av_dict_set_int(&opts, "pkt_size",    rt->pkt_size,    0);
     if (rt->localaddr && rt->localaddr[0])
         av_dict_set(&opts, "localaddr", rt->localaddr, 0);
-
+    av_dict_set_int(&opts, "multicast_max_join", rt->multicast_max_join, 0);
     return opts;
 }
 
diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h
index ca278acd43..626114fb5a 100644
--- a/libavformat/rtsp.h
+++ b/libavformat/rtsp.h
@@ -419,6 +419,7 @@ typedef struct RTSPState {
     int buffer_size;
     int pkt_size;
     char *localaddr;
+    int multicast_max_join;
 
     /**
      * Options used for TLS based RTSP streams.
diff --git a/libavformat/udp.c b/libavformat/udp.c
index 9ffd55e017..9c2f904e50 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -74,6 +74,7 @@
 #include <sys/ioctl.h>
 #include <ifaddrs.h>
 #endif
+#define IPV6_DEFAULT_JOIN 1
 
 #ifndef IPV6_ADD_MEMBERSHIP
 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
@@ -124,6 +125,7 @@ typedef struct UDPContext {
     uint8_t tmp[UDP_MAX_PKT_SIZE + sizeof(UDPQueuedPacketHeader)];
     int remaining_in_dg;
     char *localaddr;
+    int multicast_max_join;
     int timeout;
     struct sockaddr_storage local_addr_storage;
     char *sources;
@@ -143,6 +145,7 @@ static const AVOption options[] = {
     { "localport",      "Local port",                                      OFFSET(local_port),     AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, D|E },
     { "local_port",     "Local port",                                      OFFSET(local_port),     AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
     { "localaddr",      "Local address",                                   OFFSET(localaddr),      AV_OPT_TYPE_STRING, { .str = NULL },               .flags = D|E },
+    { "multicast_max_join", "Number of ipv6 network intefaces to join multicast group", OFFSET(multicast_max_join), AV_OPT_TYPE_INT, { .i64 = IPV6_DEFAULT_JOIN }, -1, INT_MAX, .flags = D|E },
     { "udplite_coverage", "choose UDPLite head size which should be validated by checksum", OFFSET(udplite_coverage), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E },
     { "pkt_size",       "Maximum UDP packet size",                         OFFSET(pkt_size),       AV_OPT_TYPE_INT,    { .i64 = 1472 },  -1, INT_MAX, .flags = D|E },
     { "reuse",          "explicitly allow reusing UDP sockets",            OFFSET(reuse_socket),   AV_OPT_TYPE_BOOL,   { .i64 = -1 },    -1, 1,       D|E },
@@ -255,7 +258,8 @@ static int udp_ipv6_mc_devname_membership(int mop, const char *name,
 }
 
 static int udp_ipv6_multicast_iterate(int sockfd, struct sockaddr_in6 *addr,
-                                      struct sockaddr_in6 *local_addr, int mop, void *logctx)
+                                      struct sockaddr_in6 *local_addr, int mop,
+                                      int multicast_max_join, void *logctx)
 {
     struct in6_addr anyipv6 = IN6ADDR_ANY_INIT;
     struct ifaddrs *ifal=NULL,*ife=NULL;
@@ -267,13 +271,16 @@ static int udp_ipv6_multicast_iterate(int sockfd, struct sockaddr_in6 *addr,
             if (ife->ifa_addr &&
                 (ife->ifa_addr->sa_family == AF_INET6) &&
                 (ife->ifa_flags & IFF_MULTICAST) &&
-                (ife->ifa_flags & IFF_UP)) {
+                (ife->ifa_flags & IFF_UP) &&
+                multicast_max_join ) {
                 if ((!memcmp(&local_addr->sin6_addr, &anyipv6, sizeof(struct in6_addr))) ||
                     (!memcmp(&local_addr->sin6_addr, &((struct sockaddr_in6 *)ife->ifa_addr)->sin6_addr, sizeof(struct in6_addr)))) {
                     if (udp_ipv6_mc_devname_membership(mop,ife->ifa_name,
                                                        iindex_fd, &addr->sin6_addr,
-                                                       sockfd, logctx) == 1)
+                                                       sockfd, logctx) == 1) {
                         membership_changed = 1;
+                        multicast_max_join--;
+                    }
                 }
             }
         }
@@ -290,7 +297,8 @@ static int udp_ipv6_multicast_iterate(int sockfd, struct sockaddr_in6 *addr,
 #endif
 
 static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
-                                    struct sockaddr *local_addr, void *logctx)
+                                    struct sockaddr *local_addr,
+                                    int multicast_max_join, void *logctx)
 {
 #ifdef IP_ADD_MEMBERSHIP
     if (addr->sa_family == AF_INET) {
@@ -305,19 +313,33 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP)");
             return ff_neterrno();
         }
+        if (multicast_max_join)
+            ff_log_net_error(logctx, AV_LOG_WARNING, "multicast_max_join is not used in ip4");
     }
 #endif
 #if HAVE_STRUCT_IPV6_MREQ && defined(IPPROTO_IPV6)
     if (addr->sa_family == AF_INET6) {
+        struct ipv6_mreq mreq6;
 #if HAVE_IOCTL_GIFINDEX
-        return udp_ipv6_multicast_iterate(sockfd,
-                                          (struct sockaddr_in6 *)addr,
-                                          (struct sockaddr_in6 *)local_addr,
-                                          IPV6_JOIN_GROUP,
-                                          logctx);
+        /* Fallback to use multicast output routing if we do not have
+           multiple interface join or a interface name or a local address */
+        if (multicast_max_join == IPV6_DEFAULT_JOIN && !local_addr) {
+            memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
+            mreq6.ipv6mr_interface = 0;
+            if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
+                ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP)");
+                return ff_neterrno();
+            }
+        }
+        else {
+            return udp_ipv6_multicast_iterate(sockfd,
+                                              (struct sockaddr_in6 *)addr,
+                                              (struct sockaddr_in6 *)local_addr,
+                                              IPV6_JOIN_GROUP,
+                                              multicast_max_join,
+                                              logctx);
+        }
 #else
-        struct ipv6_mreq mreq6;
-
         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
         mreq6.ipv6mr_interface = 0;
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
@@ -331,7 +353,8 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
 }
 
 static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
-                                     struct sockaddr *local_addr, void *logctx)
+                                     struct sockaddr *local_addr,
+                                     int multicast_max_join, void *logctx)
 {
 #ifdef IP_DROP_MEMBERSHIP
     if (addr->sa_family == AF_INET) {
@@ -350,15 +373,27 @@ static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
 #endif
 #if HAVE_STRUCT_IPV6_MREQ && defined(IPPROTO_IPV6)
     if (addr->sa_family == AF_INET6) {
+        struct ipv6_mreq mreq6;
 #if HAVE_IOCTL_GIFINDEX
-        return udp_ipv6_multicast_iterate(sockfd,
-                                          (struct sockaddr_in6 *)addr,
-                                          (struct sockaddr_in6 *)local_addr,
-                                          IPV6_LEAVE_GROUP,
-                                          logctx);
+        /* Fallback to use multicast output routing if we do not have
+           multiple interface join or a interface name or a local address */
+        if (multicast_max_join == IPV6_DEFAULT_JOIN && !local_addr) {
+            memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
+            mreq6.ipv6mr_interface = 0;
+            if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
+                ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP)");
+                return ff_neterrno();
+            }
+        }
+        else {
+            return udp_ipv6_multicast_iterate(sockfd,
+                                              (struct sockaddr_in6 *)addr,
+                                              (struct sockaddr_in6 *)local_addr,
+                                              IPV6_LEAVE_GROUP,
+                                              multicast_max_join,
+                                              logctx);
+        }
 #else
-        struct ipv6_mreq mreq6;
-
         memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
         mreq6.ipv6mr_interface = 0;
         if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
@@ -847,6 +882,9 @@ static int udp_open(URLContext *h, const char *uri, int flags)
         if (av_find_info_tag(buf, sizeof(buf), "localport", p)) {
             s->local_port = strtol(buf, NULL, 10);
         }
+        if (av_find_info_tag(buf, sizeof(buf), "multicast_max_join", p)) {
+            s->multicast_max_join = strtol(buf, NULL, 10);
+        }
         if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
             s->pkt_size = strtol(buf, NULL, 10);
         }
@@ -1012,7 +1050,8 @@ static int udp_open(URLContext *h, const char *uri, int flags)
                     goto fail;
             } else {
                 if ((ret = udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr,
-                                                    (struct sockaddr *)&s->local_addr_storage, h)) < 0)
+                                                    (struct sockaddr *)&s->local_addr_storage,
+                                                    s->multicast_max_join, h)) < 0)
                     goto fail;
             }
             if (s->filters.nb_exclude_addrs) {
@@ -1266,7 +1305,8 @@ static int udp_close(URLContext *h)
 
     if (s->is_multicast && (h->flags & AVIO_FLAG_READ))
         udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr,
-                                  (struct sockaddr *)&s->local_addr_storage, h);
+                                  (struct sockaddr *)&s->local_addr_storage,
+                                  s->multicast_max_join, h);
 #if HAVE_PTHREAD_CANCEL
     if (s->thread_started) {
         int ret;
-- 
2.34.1

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [FFmpeg-devel] [PATCH v3 4/5] libavformat: add multicast interface
  2025-08-29 14:04 ` [FFmpeg-devel] [PATCH v3 0/5] Select output interfaces for ipv6 multicast Peter Enderborg via ffmpeg-devel
                     ` (2 preceding siblings ...)
  2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 3/5] libavformat: udp.c Add support for multi or single join Peter Enderborg via ffmpeg-devel
@ 2025-08-29 14:04   ` Peter Enderborg via ffmpeg-devel
  2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 5/5] doc/protocols: Add command-line description for ipv6 options Peter Enderborg via ffmpeg-devel
  4 siblings, 0 replies; 7+ messages in thread
From: Peter Enderborg via ffmpeg-devel @ 2025-08-29 14:04 UTC (permalink / raw)
  To: michael, ffmpeg-devel, remi; +Cc: Peter Enderborg

Add a commandline option for selecting interface by name.
This is useful when your multicast routing table for
sending multicast does not match the interface reciving
is wanted.

Signed-off-by: Peter Enderborg <peterend@axis.com>
---
 libavformat/rtpproto.c |  4 ++++
 libavformat/rtsp.c     |  3 +++
 libavformat/rtsp.h     |  1 +
 libavformat/udp.c      | 40 ++++++++++++++++++++++++++++++----------
 4 files changed, 38 insertions(+), 10 deletions(-)

diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c
index c6abd7a02c..74c920ddc8 100644
--- a/libavformat/rtpproto.c
+++ b/libavformat/rtpproto.c
@@ -61,6 +61,7 @@ typedef struct RTPContext {
     char *fec_options_str;
     int64_t rw_timeout;
     char *localaddr;
+    char *multicast_interface;
     int multicast_max_join;
 } RTPContext;
 
@@ -83,6 +84,7 @@ static const AVOption options[] = {
     { "fec",                "FEC",                                                              OFFSET(fec_options_str), AV_OPT_TYPE_STRING, { .str = NULL },               .flags = E },
     { "localaddr",          "Local address",                                                    OFFSET(localaddr),       AV_OPT_TYPE_STRING, { .str = NULL },               .flags = D|E },
     { "multicast_max_join", "Number of ipv6 network intefaces to join multicast group",         OFFSET(multicast_max_join), AV_OPT_TYPE_INT,    { .i64 = 1 }, 1, INT_MAX, .flags = D|E },
+    { "multicast_interface", "Name of network inteface to join multicast group",                OFFSET(multicast_interface), AV_OPT_TYPE_STRING, { .str = NULL },           .flags = D|E },
     { NULL }
 };
 
@@ -202,6 +204,8 @@ static void build_udp_url(RTPContext *s,
     if (localaddr && localaddr[0])
         url_add_option(buf, buf_size, "localaddr=%s", localaddr);
     url_add_option(buf, buf_size, "multicast_max_join=%d", s->multicast_max_join);
+    if (s->multicast_interface)
+          url_add_option(buf, buf_size, "multicast_interface=%s", s->multicast_interface);
 }
 
 /**
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index 08ce628b0c..59e39fa97c 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -82,6 +82,7 @@
     { "reorder_queue_size", "set number of packets to buffer for handling of reordered packets", OFFSET(reordering_queue_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC }, \
     { "buffer_size",        "Underlying protocol send/receive buffer size",                  OFFSET(buffer_size),           AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC|ENC }, \
     { "multicast_max_join", "Number of ipv6 network intefaces to join multicast group",      OFFSET(multicast_max_join),           AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, ENC }, \
+    { "multicast_interface", "Name of network inteface to join multicast group",             OFFSET(multicast_interface), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, \
     { "pkt_size",           "Underlying protocol send packet size",                          OFFSET(pkt_size),              AV_OPT_TYPE_INT, { .i64 = 1472 }, -1, INT_MAX, ENC } \
 
 
@@ -141,6 +142,8 @@ static AVDictionary *map_to_opts(RTSPState *rt)
     if (rt->localaddr && rt->localaddr[0])
         av_dict_set(&opts, "localaddr", rt->localaddr, 0);
     av_dict_set_int(&opts, "multicast_max_join", rt->multicast_max_join, 0);
+    if (rt->multicast_interface)
+        av_dict_set(&opts, "multicast_interface", rt->multicast_interface, 0);
     return opts;
 }
 
diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h
index 626114fb5a..e48af2feca 100644
--- a/libavformat/rtsp.h
+++ b/libavformat/rtsp.h
@@ -420,6 +420,7 @@ typedef struct RTSPState {
     int pkt_size;
     char *localaddr;
     int multicast_max_join;
+    char *multicast_interface;
 
     /**
      * Options used for TLS based RTSP streams.
diff --git a/libavformat/udp.c b/libavformat/udp.c
index 9c2f904e50..004d2a6a1c 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -126,6 +126,7 @@ typedef struct UDPContext {
     int remaining_in_dg;
     char *localaddr;
     int multicast_max_join;
+    char *multicast_interface;
     int timeout;
     struct sockaddr_storage local_addr_storage;
     char *sources;
@@ -146,6 +147,7 @@ static const AVOption options[] = {
     { "local_port",     "Local port",                                      OFFSET(local_port),     AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
     { "localaddr",      "Local address",                                   OFFSET(localaddr),      AV_OPT_TYPE_STRING, { .str = NULL },               .flags = D|E },
     { "multicast_max_join", "Number of ipv6 network intefaces to join multicast group", OFFSET(multicast_max_join), AV_OPT_TYPE_INT, { .i64 = IPV6_DEFAULT_JOIN }, -1, INT_MAX, .flags = D|E },
+    { "multicast_interface", "Name of network inteface to join multicast group", OFFSET(multicast_interface), AV_OPT_TYPE_STRING, { .str = NULL },         .flags = D|E },
     { "udplite_coverage", "choose UDPLite head size which should be validated by checksum", OFFSET(udplite_coverage), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E },
     { "pkt_size",       "Maximum UDP packet size",                         OFFSET(pkt_size),       AV_OPT_TYPE_INT,    { .i64 = 1472 },  -1, INT_MAX, .flags = D|E },
     { "reuse",          "explicitly allow reusing UDP sockets",            OFFSET(reuse_socket),   AV_OPT_TYPE_BOOL,   { .i64 = -1 },    -1, 1,       D|E },
@@ -259,7 +261,8 @@ static int udp_ipv6_mc_devname_membership(int mop, const char *name,
 
 static int udp_ipv6_multicast_iterate(int sockfd, struct sockaddr_in6 *addr,
                                       struct sockaddr_in6 *local_addr, int mop,
-                                      int multicast_max_join, void *logctx)
+                                      int multicast_max_join,
+                                      char *interfacename, void *logctx)
 {
     struct in6_addr anyipv6 = IN6ADDR_ANY_INIT;
     struct ifaddrs *ifal=NULL,*ife=NULL;
@@ -275,11 +278,13 @@ static int udp_ipv6_multicast_iterate(int sockfd, struct sockaddr_in6 *addr,
                 multicast_max_join ) {
                 if ((!memcmp(&local_addr->sin6_addr, &anyipv6, sizeof(struct in6_addr))) ||
                     (!memcmp(&local_addr->sin6_addr, &((struct sockaddr_in6 *)ife->ifa_addr)->sin6_addr, sizeof(struct in6_addr)))) {
-                    if (udp_ipv6_mc_devname_membership(mop,ife->ifa_name,
-                                                       iindex_fd, &addr->sin6_addr,
-                                                       sockfd, logctx) == 1) {
-                        membership_changed = 1;
-                        multicast_max_join--;
+                    if (!interfacename || !strncmp(interfacename, ife->ifa_name, IFNAMSIZ)) {
+                        if (udp_ipv6_mc_devname_membership(mop,ife->ifa_name,
+                                                           iindex_fd, &addr->sin6_addr,
+                                                           sockfd, logctx) == 1) {
+                            membership_changed = 1;
+                            multicast_max_join--;
+                        }
                     }
                 }
             }
@@ -298,7 +303,8 @@ static int udp_ipv6_multicast_iterate(int sockfd, struct sockaddr_in6 *addr,
 
 static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
                                     struct sockaddr *local_addr,
-                                    int multicast_max_join, void *logctx)
+                                    int multicast_max_join,
+                                    char *multicast_interface,void *logctx)
 {
 #ifdef IP_ADD_MEMBERSHIP
     if (addr->sa_family == AF_INET) {
@@ -313,6 +319,8 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
             ff_log_net_error(logctx, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP)");
             return ff_neterrno();
         }
+        if (multicast_interface)
+            ff_log_net_error(logctx, AV_LOG_WARNING, "multicast_inteface is not used in ip4");
         if (multicast_max_join)
             ff_log_net_error(logctx, AV_LOG_WARNING, "multicast_max_join is not used in ip4");
     }
@@ -337,6 +345,7 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
                                               (struct sockaddr_in6 *)local_addr,
                                               IPV6_JOIN_GROUP,
                                               multicast_max_join,
+                                              multicast_interface,
                                               logctx);
         }
 #else
@@ -354,7 +363,8 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,
 
 static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
                                      struct sockaddr *local_addr,
-                                     int multicast_max_join, void *logctx)
+                                     int multicast_max_join,
+                                     char *multicast_interface,void *logctx)
 {
 #ifdef IP_DROP_MEMBERSHIP
     if (addr->sa_family == AF_INET) {
@@ -391,6 +401,7 @@ static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,
                                               (struct sockaddr_in6 *)local_addr,
                                               IPV6_LEAVE_GROUP,
                                               multicast_max_join,
+                                              multicast_interface,
                                               logctx);
         }
 #else
@@ -922,6 +933,14 @@ static int udp_open(URLContext *h, const char *uri, int flags)
                 goto fail;
             }
         }
+        if (av_find_info_tag(buf, sizeof(buf), "multicast_interface", p)) {
+            av_freep(&s->multicast_interface);
+            s->multicast_interface = av_strdup(buf);
+            if (!s->multicast_interface) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+        }
         if (av_find_info_tag(buf, sizeof(buf), "sources", p)) {
             if ((ret = ff_ip_parse_sources(h, buf, &s->filters)) < 0)
                 goto fail;
@@ -1051,7 +1070,8 @@ static int udp_open(URLContext *h, const char *uri, int flags)
             } else {
                 if ((ret = udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr,
                                                     (struct sockaddr *)&s->local_addr_storage,
-                                                    s->multicast_max_join, h)) < 0)
+                                                    s->multicast_max_join,
+                                                    s->multicast_interface, h)) < 0)
                     goto fail;
             }
             if (s->filters.nb_exclude_addrs) {
@@ -1306,7 +1326,7 @@ static int udp_close(URLContext *h)
     if (s->is_multicast && (h->flags & AVIO_FLAG_READ))
         udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr,
                                   (struct sockaddr *)&s->local_addr_storage,
-                                  s->multicast_max_join, h);
+                                  s->multicast_max_join, s->multicast_interface, h);
 #if HAVE_PTHREAD_CANCEL
     if (s->thread_started) {
         int ret;
-- 
2.34.1

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [FFmpeg-devel] [PATCH v3 5/5] doc/protocols: Add command-line description for ipv6 options
  2025-08-29 14:04 ` [FFmpeg-devel] [PATCH v3 0/5] Select output interfaces for ipv6 multicast Peter Enderborg via ffmpeg-devel
                     ` (3 preceding siblings ...)
  2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 4/5] libavformat: add multicast interface Peter Enderborg via ffmpeg-devel
@ 2025-08-29 14:04   ` Peter Enderborg via ffmpeg-devel
  4 siblings, 0 replies; 7+ messages in thread
From: Peter Enderborg via ffmpeg-devel @ 2025-08-29 14:04 UTC (permalink / raw)
  To: michael, ffmpeg-devel, remi; +Cc: Peter Enderborg

Two new options added for receive IPv6 multicast streams.
1 multicast_max_joins
2 multicast_interface

Change-Id: Ief0389815cff3edf26f7db5cbff033ce8bb24639
Signed-off-by: Peter Enderborg <peterend@axis.com>
---
 doc/protocols.texi | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/doc/protocols.texi b/doc/protocols.texi
index 6b582fde30..3def969dbe 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -1207,7 +1207,15 @@ This is a deprecated option. Instead, @option{localrtpport} should be
 used.
 
 @item localaddr=@var{addr}
-Local IP address of a network interface used for sending packets or joining
+Local IP address of a network interface used for sending or receiving packets or joining
+multicast groups.
+
+@item multicast_interface=@var{interfacename}
+Local IP address of a network interface used for receiving packets or joining
+multicast groups.
+
+@item multicast_max_join=@var{n}
+Local IP address of a network interface used for receiving packets or joining
 multicast groups.
 
 @item timeout=@var{n}
@@ -1229,6 +1237,13 @@ port will be used for the local RTP and RTCP ports.
 @item
 If @option{localrtcpport} (the local RTCP port) is not set it will be
 set to the local RTP port value plus 1.
+
+@item
+On IPv6 the default receive behavior is using outgoing routing table for selection of
+a interface for multicast streams. With @option{multicast_max_join} receiving
+can be added for multiple interfaces. With @option{multicast_interface} a
+interface is directly selected for receiving.
+
 @end enumerate
 
 @section rtsp
-- 
2.34.1

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [FFmpeg-devel] Re: [PATCH v3 1/5] configure: Add test_ioctl and test for SIOCGIFINDEX
  2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 1/5] configure: Add test_ioctl and test for SIOCGIFINDEX Peter Enderborg via ffmpeg-devel
@ 2025-08-29 17:38     ` Rémi Denis-Courmont via ffmpeg-devel
  0 siblings, 0 replies; 7+ messages in thread
From: Rémi Denis-Courmont via ffmpeg-devel @ 2025-08-29 17:38 UTC (permalink / raw)
  To: Peter Enderborg, ffmpeg-devel; +Cc: Rémi Denis-Courmont



Le 29 août 2025 17:04:55 GMT+03:00, Peter Enderborg <peterend@axis.com> a écrit :
>Adds a generic ioctl tester and a specific test  SIOCGIFINDEX
>that sets ioctl_gifindex. It is a network specific feature
>and the tests are run only in network context.

`if_nametoindex` is the prescribed standard function to do this (`atoi` can be used on Windows).

>Signed-off-by: Peter Enderborg <peterend@axis.com>
>---
> configure | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
>diff --git a/configure b/configure
>index 9fe28c5af4..b379a6bc92 100755
>--- a/configure
>+++ b/configure
>@@ -1282,6 +1282,20 @@ int x;
> EOF
> }
> 
>+test_ioctl(){
>+    log test_ioctl "$@"
>+    ctl=$1
>+    shift 1
>+    test_cc "$@" <<EOF
>+#include <stddef.h>
>+#include <sys/ioctl.h>
>+int f;
>+void x(){
>+ioctl(f, $ctl, NULL);
>+}
>+EOF
>+}
>+
> check_cflags(){
>     log check_cflags "$@"
>     test_cflags "$@" && add_cflags "$@"
>@@ -2542,6 +2556,7 @@ HAVE_LIST="
>     $TOOLCHAIN_FEATURES
>     $TYPES_LIST
>     gzip
>+    ioctl_gifindex
>     ioctl_posix
>     libdrm_getfb2
>     makeinfo
>@@ -6658,6 +6673,7 @@ if ! disabled network; then
>     else
>         disable network
>     fi
>+    test_ioctl SIOCGIFINDEX && enable ioctl_gifindex
> fi
> 
> check_builtin MemoryBarrier windows.h "MemoryBarrier()"
_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2025-08-29 17:39 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <0250811223419.GF29660@pb2>
2025-08-29 14:04 ` [FFmpeg-devel] [PATCH v3 0/5] Select output interfaces for ipv6 multicast Peter Enderborg via ffmpeg-devel
2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 1/5] configure: Add test_ioctl and test for SIOCGIFINDEX Peter Enderborg via ffmpeg-devel
2025-08-29 17:38     ` [FFmpeg-devel] " Rémi Denis-Courmont via ffmpeg-devel
2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 2/5] avformat/udp: Select output interfaces for ipv6 multicast Peter Enderborg via ffmpeg-devel
2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 3/5] libavformat: udp.c Add support for multi or single join Peter Enderborg via ffmpeg-devel
2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 4/5] libavformat: add multicast interface Peter Enderborg via ffmpeg-devel
2025-08-29 14:04   ` [FFmpeg-devel] [PATCH v3 5/5] doc/protocols: Add command-line description for ipv6 options Peter Enderborg via ffmpeg-devel

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git