PR #23259 opened by Kaarle Ritvanen (kunkku)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23259
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23259.patch

Sending of RTCP Receiver Reports has been broken for a decade. This PR remedies 
the situation with the following changes:

* Mark the RTP URL as writable in `sdp_read_header`. This fixes a regression in 
commit 6f5048f4a0f702d92794dda7752c20ed6033233b that made the RTP stream
  read-only while unsuccessfully trying to keep the RTCP stream writable.
* Revert commit 9faee5bc148fdf4d5340cdcf7e464078972dc72c, which further broke 
RTCP sending by binding the socket to a multicast address.
* As suggested in the commit message of 
b56fc18b20d62c3d2a134b53738deaabfd491e89, make `rtcp_to_source` the default 
behavior in case of unicast.


>From c7dc586fdfbe38a959436da5250939780dec6741 Mon Sep 17 00:00:00 2001
From: Kaarle Ritvanen <[email protected]>
Date: Wed, 13 May 2026 22:47:15 +0300
Subject: [PATCH 1/3] Revert "avformat/udp: modify the not write-only to
 read-only mode."

This reverts commit 9faee5bc148fdf4d5340cdcf7e464078972dc72c. This
change was incorrect due to the reason stated in the above comment:
nothing can be sent if the socket is bound to a multicast address.

Signed-off-by: Kaarle Ritvanen <[email protected]>
---
 libavformat/udp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavformat/udp.c b/libavformat/udp.c
index 0874d18397..ba78a91808 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -820,7 +820,7 @@ static int udp_open(URLContext *h, const char *uri, int 
flags)
      * receiving UDP packets from other sources aimed at the same UDP
      * port. This fails on windows. This makes sending to the same address
      * using sendto() fail, so only do it if we're opened in read-only mode. */
-    if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) {
+    if (s->is_multicast && !(h->flags & AVIO_FLAG_WRITE)) {
         bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len);
     }
     /* bind to the local address if not multicast or if the multicast
-- 
2.52.0


>From 69b7127e2af97fc33060f40e728b7486e84921c4 Mon Sep 17 00:00:00 2001
From: Kaarle Ritvanen <[email protected]>
Date: Wed, 13 May 2026 13:55:11 +0300
Subject: [PATCH 2/3] rtsp: mark URL as writable to allow RTCP RRs

ffurl_write2 fails if the RTP URL is marked read-only, blocking any
outgoing RTCP packets. This fixes a regression in commit
6f5048f4a0f702d92794dda7752c20ed6033233b.

Signed-off-by: Kaarle Ritvanen <[email protected]>
---
 libavformat/rtsp.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index 45b62c4188..9b5f39aa2c 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -2645,6 +2645,9 @@ static int sdp_read_header(AVFormatContext *s)
                 err = AVERROR_INVALIDDATA;
                 goto fail;
             }
+
+            if (rt->rtsp_flags & RTSP_FLAG_RTCP_TO_SOURCE)
+                rtsp_st->rtp_handle->flags |= AVIO_FLAG_WRITE;
         }
         if ((err = ff_rtsp_open_transport_ctx(s, rtsp_st)))
             goto fail;
-- 
2.52.0


>From 61725754647b672639bdc2c3bff23fae5e0c806b Mon Sep 17 00:00:00 2001
From: Kaarle Ritvanen <[email protected]>
Date: Wed, 13 May 2026 22:58:59 +0300
Subject: [PATCH 3/3] rtsp: send RTCP RR to unicast source by default

The rctp_to_source flag is converted to a tri-state boolean, where the
default is true for unicast and false for multicast sources. The
original flag is deprecated. This change was inspired by the message of
commit b56fc18b20d62c3d2a134b53738deaabfd491e89.

Signed-off-by: Kaarle Ritvanen <[email protected]>
---
 libavformat/rtsp.c | 15 ++++++++++-----
 libavformat/rtsp.h |  1 +
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index 9b5f39aa2c..7a2d592ee8 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -113,7 +113,8 @@ const AVOption ff_rtsp_options[] = {
 static const AVOption sdp_options[] = {
     RTSP_FLAG_OPTS("sdp_flags", "SDP flags"),
     { "custom_io", "use custom I/O", 0, AV_OPT_TYPE_CONST, {.i64 = 
RTSP_FLAG_CUSTOM_IO}, 0, 0, DEC, .unit = "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, 
.unit = "rtsp_flags" },
+    { "rtcp_to_source", "send RTCP packets to the source address of received 
packets (deprecated; use rtcp_to_source option)", 0, AV_OPT_TYPE_CONST, {.i64 = 
RTSP_FLAG_RTCP_TO_SOURCE}, 0, 0, DEC|AV_OPT_FLAG_DEPRECATED, .unit = 
"rtsp_flags" },
+    { "rtcp_to_source", "send RTCP packets to the source address of received 
packets", OFFSET(rtcp_to_source), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, DEC },
     { "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"),
@@ -2606,11 +2607,15 @@ static int sdp_read_header(AVFormatContext *s)
 
         if (!(rt->rtsp_flags & RTSP_FLAG_CUSTOM_IO)) {
             AVDictionary *opts = map_to_opts(rt);
+            int rtcp_to_source = rt->rtcp_to_source;
             char buf[MAX_URL_SIZE];
             const char *p;
 
-            err = getnameinfo((struct sockaddr*) &rtsp_st->sdp_ip,
-                              sizeof(rtsp_st->sdp_ip),
+            struct sockaddr *addr = (struct sockaddr*) &rtsp_st->sdp_ip;
+            if (rtcp_to_source < 0)
+                rtcp_to_source = rt->rtsp_flags & RTSP_FLAG_RTCP_TO_SOURCE || 
!ff_is_multicast_address(addr);
+
+            err = getnameinfo(addr, sizeof(rtsp_st->sdp_ip),
                               namebuf, sizeof(namebuf), NULL, 0, 
NI_NUMERICHOST);
             if (err) {
                 av_log(s, AV_LOG_ERROR, "getnameinfo: %s\n", 
gai_strerror(err));
@@ -2623,7 +2628,7 @@ static int sdp_read_header(AVFormatContext *s)
                         
"?localrtpport=%d&ttl=%d&connect=%d&write_to_source=%d",
                         rtsp_st->sdp_port, rtsp_st->sdp_ttl,
                         rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0,
-                        rt->rtsp_flags & RTSP_FLAG_RTCP_TO_SOURCE ? 1 : 0);
+                        rtcp_to_source);
 
             p = strchr(s->url, '?');
             if (p && av_find_info_tag(buf, sizeof(buf), "localaddr", p))
@@ -2646,7 +2651,7 @@ static int sdp_read_header(AVFormatContext *s)
                 goto fail;
             }
 
-            if (rt->rtsp_flags & RTSP_FLAG_RTCP_TO_SOURCE)
+            if (rtcp_to_source)
                 rtsp_st->rtp_handle->flags |= AVIO_FLAG_WRITE;
         }
         if ((err = ff_rtsp_open_transport_ctx(s, rtsp_st)))
diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h
index 3c9c2c842d..fd5ecf7dd3 100644
--- a/libavformat/rtsp.h
+++ b/libavformat/rtsp.h
@@ -441,6 +441,7 @@ typedef struct RTSPState {
     int buffer_size;
     int pkt_size;
     char *localaddr;
+    int rtcp_to_source;
 
     /**
      * Options used for TLS based RTSP streams.
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to