Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: Peter Enderborg via ffmpeg-devel <ffmpeg-devel@ffmpeg.org>
To: <michael@niedermayer.cc>, <ffmpeg-devel@ffmpeg.org>, <remi@remlab.net>
Cc: Peter Enderborg <peterend@axis.com>
Subject: [FFmpeg-devel] [PATCH v3 4/5] libavformat: add multicast interface
Date: Fri, 29 Aug 2025 16:04:58 +0200
Message-ID: <20250829140459.3220037-5-peterend@axis.com> (raw)
In-Reply-To: <20250829140459.3220037-1-peterend@axis.com>

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

  parent reply	other threads:[~2025-08-29 14:07 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [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   ` Peter Enderborg via ffmpeg-devel [this message]
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
2025-08-30  0:06     ` [FFmpeg-devel] " Marton Balint via ffmpeg-devel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250829140459.3220037-5-peterend@axis.com \
    --to=ffmpeg-devel@ffmpeg.org \
    --cc=michael@niedermayer.cc \
    --cc=peterend@axis.com \
    --cc=remi@remlab.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

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