PR #25348 opened by Forgejo_Fairy
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25348
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25348.patch

An RTSP server that stops sending without closing its connection leaves ffplay 
retrying read timeouts indefinitely, even with `-autoexit -timeout 5000000`. 
RTSP manages its transport internally, so ffplay's `ic->pb->error` check cannot 
see those failures.

This series preserves underlying errors when reading interleaved RTP headers 
and payloads, then makes ffplay exit on `AVERROR(ETIMEDOUT)` when autoexit is 
enabled. Nonnegative short packet reads retain `EIO`; ffplay's EOF draining and 
retry paths for other errors remain intact.

Fixes #25212. The TCP regression was verified at f1c8c25832777 against its 
immediate parent 6d42af02f56: preserving the correct RTSP error exposed 
ffplay's missing timeout handling. UDP stalls also reproduce on release/4.4.

Validation on ARM64 Linux with SDL's dummy audio driver: generated local 
RTSP/PCMU playback followed by TCP and UDP stalls, stalls inside interleaved 
headers and payloads, normal TCP EOF, a brief interruption below the timeout, 
and operation without autoexit. Local WAV EOF and two-pass looping also pass. 
With a five-second TCP timeout, unmodified master remains running through 17.50 
seconds after PLAY; the fix exits around 7.81 seconds, including two seconds of 
media and cleanup against a silent server. Build and whitespace checks pass.

The manual reproducer, exact release revisions, historical comparison and 
result logs are preserved on `fairy/issue25212-tooling`, commit 023a924b2987, 
under `tools/issue25212/`. No full FATE or cross-platform run was performed.


>From d77401ffed08b8b21ff9d3e35c4c1bc237df69b4 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Thu, 22 Oct 2026 10:19:25 +0000
Subject: [PATCH 1/2] avformat/rtspdec: preserve errors reading interleaved
 packets

Return the underlying read error when reading the interleaved packet
header or payload fails. In particular, do not replace ETIMEDOUT with EIO:
callers need to distinguish a configured read timeout from other errors.
Keep EIO for a nonnegative short read, as in ff_rtsp_skip_packet().

Assisted-by: Fairy
---
 libavformat/rtspdec.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libavformat/rtspdec.c b/libavformat/rtspdec.c
index 0e592eebaed..d1bacadccf5 100644
--- a/libavformat/rtspdec.c
+++ b/libavformat/rtspdec.c
@@ -926,7 +926,7 @@ redo:
     }
     ret = ffurl_read_complete(rt->rtsp_hd, buf, 3);
     if (ret != 3)
-        return AVERROR(EIO);
+        return ret < 0 ? ret : AVERROR(EIO);
     rt->pending_packet = 0;
     id  = buf[0];
     len = AV_RB16(buf + 1);
@@ -936,7 +936,7 @@ redo:
     /* get the data */
     ret = ffurl_read_complete(rt->rtsp_hd, buf, len);
     if (ret != len)
-        return AVERROR(EIO);
+        return ret < 0 ? ret : AVERROR(EIO);
     if (rt->transport == RTSP_TRANSPORT_RDT &&
         (ret = ff_rdt_parse_header(buf, len, &id, NULL, NULL, NULL, NULL)) < 0)
         return ret;
-- 
2.54.0


>From f6fd4585866ab0280429ba5fea4628b50800b923 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Thu, 22 Oct 2026 10:19:25 +0000
Subject: [PATCH 2/2] ffplay: honor autoexit on read timeouts

RTSP manages its transport internally and has no top-level AVIOContext.
Consequently, checking ic->pb->error misses its read timeouts and ffplay
keeps retrying even with -autoexit enabled.

Exit on AVERROR(ETIMEDOUT) with -autoexit. Leave EOF draining, retryable
errors and playback without -autoexit on their existing paths.

This also fixes the TCP playback regression exposed by f1c8c25832777,
which correctly propagated RTSP read errors instead of reporting EOF.
UDP playback is affected independently of that commit.

Fixes: #25212
Assisted-by: Fairy
---
 fftools/ffplay.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fftools/ffplay.c b/fftools/ffplay.c
index d17aa1c4224..94d5d483335 100644
--- a/fftools/ffplay.c
+++ b/fftools/ffplay.c
@@ -3544,6 +3544,8 @@ static int read_thread(void *arg)
         }
         ret = av_read_frame(ic, pkt);
         if (ret < 0) {
+            if (autoexit && ret == AVERROR(ETIMEDOUT))
+                goto fail;
             if ((ret == AVERROR_EOF || avio_feof(ic->pb)) && !is->eof) {
                 if (is->video_stream >= 0) {
                     ret = do_bsf_flush(ic, is);
-- 
2.54.0

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

Reply via email to