From 7bf4c06809296820f084fd5b3e362621ac99c3f4 Mon Sep 17 00:00:00 2001 From: Limin Wang Date: Fri, 26 Nov 2021 16:55:08 +0800 Subject: [PATCH] avformat/rtp: add localaddr for network interface selection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Martin Storsjö Signed-off-by: Limin Wang --- doc/protocols.texi | 4 ++++ libavformat/rtpproto.c | 17 ++++++++++++++--- libavformat/rtsp.c | 11 +++++++++++ libavformat/rtsp.h | 1 + 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/doc/protocols.texi b/doc/protocols.texi index c100f23f17..d207df0b52 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -1087,6 +1087,10 @@ set to 1) or to a default remote address (if set to 0). @item localport=@var{n} Set the local RTP port to @var{n}. +@item localaddr=@var{addr} +Local IP address of a network interface used for sending packets or joining +multicast groups. + @item timeout=@var{n} Set timeout (in microseconds) of socket I/O operations to @var{n}. diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c index 7dd6042158..c92cda63bb 100644 --- a/libavformat/rtpproto.c +++ b/libavformat/rtpproto.c @@ -61,6 +61,7 @@ typedef struct RTPContext { char *block; char *fec_options_str; int64_t rw_timeout; + char *localaddr; } RTPContext; #define OFFSET(x) offsetof(RTPContext, x) @@ -80,6 +81,7 @@ static const AVOption options[] = { { "sources", "Source list", OFFSET(sources), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E }, { "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 }, { NULL } }; @@ -173,6 +175,7 @@ static av_printf_format(3, 4) void url_add_option(char *buf, int buf_size, const static void build_udp_url(RTPContext *s, char *buf, int buf_size, const char *hostname, + const char *localaddr, int port, int local_port, const char *include_sources, const char *exclude_sources) @@ -195,6 +198,8 @@ static void build_udp_url(RTPContext *s, 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); + if (localaddr && localaddr[0]) + url_add_option(buf, buf_size, "localaddr=%s", localaddr); } /** @@ -284,6 +289,12 @@ static int rtp_open(URLContext *h, const char *uri, int flags) ff_ip_parse_blocks(h, s->block, &s->filters); block = s->block; } + if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) { + av_freep(&s->localaddr); + s->localaddr = av_strdup(buf); + if (!s->localaddr) + goto fail; + } } if (s->rw_timeout >= 0) h->rw_timeout = s->rw_timeout; @@ -314,7 +325,7 @@ static int rtp_open(URLContext *h, const char *uri, int flags) for (i = 0; i < max_retry_count; i++) { build_udp_url(s, buf, sizeof(buf), - hostname, rtp_port, s->local_rtpport, + hostname, s->localaddr, rtp_port, s->local_rtpport, sources, block); if (ffurl_open_whitelist(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL, h->protocol_whitelist, h->protocol_blacklist, h) < 0) @@ -328,7 +339,7 @@ static int rtp_open(URLContext *h, const char *uri, int flags) if (s->local_rtcpport < 0) { s->local_rtcpport = s->local_rtpport + 1; build_udp_url(s, buf, sizeof(buf), - hostname, s->rtcp_port, s->local_rtcpport, + hostname, s->localaddr, s->rtcp_port, s->local_rtcpport, sources, block); if (ffurl_open_whitelist(&s->rtcp_hd, buf, rtcpflags, &h->interrupt_callback, NULL, @@ -339,7 +350,7 @@ static int rtp_open(URLContext *h, const char *uri, int flags) break; } build_udp_url(s, buf, sizeof(buf), - hostname, s->rtcp_port, s->local_rtcpport, + hostname, s->localaddr, s->rtcp_port, s->local_rtcpport, sources, block); if (ffurl_open_whitelist(&s->rtcp_hd, buf, rtcpflags, &h->interrupt_callback, NULL, h->protocol_whitelist, h->protocol_blacklist, h) < 0) diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index a1aa969cad..e6a4993acd 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -105,6 +105,7 @@ static const AVOption sdp_options[] = { { "custom_io", "use custom I/O", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_CUSTOM_IO}, 0, 0, DEC, "rtsp_flags" }, { "rtcp_to_source", "send RTCP packets to the source address of received packets", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_RTCP_TO_SOURCE}, 0, 0, DEC, "rtsp_flags" }, { "listen_timeout", "set maximum timeout (in seconds) to wait for incoming connections", OFFSET(stimeout), AV_OPT_TYPE_DURATION, {.i64 = READ_PACKET_TIMEOUT_S*1000000}, INT_MIN, INT64_MAX, DEC }, + { "localaddr", "local address", OFFSET(localaddr),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, \ RTSP_MEDIATYPE_OPTS("allowed_media_types", "set media types to accept from the server"), COMMON_OPTS(), { NULL }, @@ -113,6 +114,7 @@ static const AVOption sdp_options[] = { static const AVOption rtp_options[] = { RTSP_FLAG_OPTS("rtp_flags", "set RTP flags"), { "listen_timeout", "set maximum timeout (in seconds) to wait for incoming connections", OFFSET(stimeout), AV_OPT_TYPE_DURATION, {.i64 = READ_PACKET_TIMEOUT_S*1000000}, INT_MIN, INT64_MAX, DEC }, + { "localaddr", "local address", OFFSET(localaddr),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, \ RTSP_MEDIATYPE_OPTS("allowed_media_types", "set media types to accept from the server"), COMMON_OPTS(), { NULL }, @@ -125,6 +127,8 @@ static AVDictionary *map_to_opts(RTSPState *rt) av_dict_set_int(&opts, "buffer_size", rt->buffer_size, 0); 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); return opts; } @@ -2407,6 +2411,8 @@ static int sdp_read_header(AVFormatContext *s) if (!(rt->rtsp_flags & RTSP_FLAG_CUSTOM_IO)) { AVDictionary *opts = map_to_opts(rt); + char buf[MAX_URL_SIZE]; + const char *p; err = getnameinfo((struct sockaddr*) &rtsp_st->sdp_ip, sizeof(rtsp_st->sdp_ip), @@ -2424,6 +2430,11 @@ static int sdp_read_header(AVFormatContext *s) rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0, rt->rtsp_flags & RTSP_FLAG_RTCP_TO_SOURCE ? 1 : 0); + p = strchr(s->url, '?'); + if (p && av_find_info_tag(buf, sizeof(buf), "localaddr", p)) + av_strlcatf(url, sizeof(url), "&localaddr=%s", buf); + else if (rt->localaddr && rt->localaddr[0]) + av_strlcatf(url, sizeof(url), "&localaddr=%s", rt->localaddr); append_source_addrs(url, sizeof(url), "sources", rtsp_st->nb_include_source_addrs, rtsp_st->include_source_addrs); diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h index 4ec974ed73..d6fdfe069c 100644 --- a/libavformat/rtsp.h +++ b/libavformat/rtsp.h @@ -419,6 +419,7 @@ typedef struct RTSPState { char default_lang[4]; int buffer_size; int pkt_size; + char *localaddr; } RTSPState; #define RTSP_FLAG_FILTER_SRC 0x1 /**< Filter incoming UDP packets -