Commit e4b1a53fea for ffmpeg

commit e4b1a53feae92cb46204692513eef6c2db437e9f
Author: Romain Beauxis <romain.beauxis@gmail.com>
Date:   Sat Oct 17 12:58:09 2026 +0200

    avformat/seek: keep the target inside the range when rescaling it

    ff_rescale_interval() rounds the bounds of the range inwards and the
    target to the nearest, so a target close to a bound could fall outside
    the range, which the seek then rejects. A seek through the concat
    demuxer to 0.53 s in a file starting at -2112 samples fails this way:
    the file it reads gets a target one tick after the end of the range.

    Clamp the target to the range, and use ff_rescale_interval() for the
    same conversion done for read_seek2() with a single stream.

    The seek through concat now lands at the target instead of failing and
    reading from the start. The rescaled targets of the interval test stay
    within their range: 10 instead of 11, and 4 instead of 3.

diff --git a/libavformat/demux.h b/libavformat/demux.h
index 73ecd494b8..4fdf3fdf27 100644
--- a/libavformat/demux.h
+++ b/libavformat/demux.h
@@ -309,8 +309,8 @@ void ff_rfps_calculate(AVFormatContext *ic);
  *
  * The upper (lower) bound of the output interval is rounded up (down) such that
  * the output interval always falls within the input interval. The timestamp is
- * rounded to the nearest integer and halfway cases away from zero, and can
- * therefore fall outside of the output interval.
+ * rounded to the nearest integer and halfway cases away from zero, then
+ * clamped to the output interval.
  *
  * Useful to simplify the rescaling of the arguments of FFInputFormat::read_seek2()
  *
diff --git a/libavformat/seek.c b/libavformat/seek.c
index 31e3e6dd69..82875483b5 100644
--- a/libavformat/seek.c
+++ b/libavformat/seek.c
@@ -684,14 +684,8 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts,
         ff_read_frame_flush(s);

         if (stream_index == -1 && s->nb_streams == 1) {
-            AVRational time_base = s->streams[0]->time_base;
-            ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base);
-            min_ts = av_rescale_rnd(min_ts, time_base.den,
-                                    time_base.num * (int64_t)AV_TIME_BASE,
-                                    AV_ROUND_UP   | AV_ROUND_PASS_MINMAX);
-            max_ts = av_rescale_rnd(max_ts, time_base.den,
-                                    time_base.num * (int64_t)AV_TIME_BASE,
-                                    AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
+            ff_rescale_interval(AV_TIME_BASE_Q, s->streams[0]->time_base,
+                                &min_ts, &ts, &max_ts);
             stream_index = 0;
         }

@@ -760,4 +754,6 @@ void ff_rescale_interval(AVRational tb_in, AVRational tb_out,
                                AV_ROUND_UP   | AV_ROUND_PASS_MINMAX);
     *max_ts = av_rescale_q_rnd(*max_ts, tb_in, tb_out,
                                AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
+    // Rounding to the nearest can take the target out of the interval.
+    *ts     = FFMAX(FFMIN(*ts, *max_ts), *min_ts);
 }
diff --git a/tests/ref/fate/preroll-aac-concat-seek b/tests/ref/fate/preroll-aac-concat-seek
index 77f874610f..08cadd8280 100644
--- a/tests/ref/fate/preroll-aac-concat-seek
+++ b/tests/ref/fate/preroll-aac-concat-seek
@@ -1,32 +1,107 @@
+ret: 0         st: 0 flags:1 dts: 0.509388 pts: 0.509388 pos:   2416 size:    27
+ret: 0         st: 0 flags:1 dts: 0.532608 pts: 0.532608 pos:   2443 size:    28
+ret: 0         st: 0 flags:1 dts: 0.555828 pts: 0.555828 pos:   2471 size:    27
+ret: 0         st:-1 flags:0  ts:-1.000000
+ret: 0         st: 0 flags:1 dts:-0.047891 pts:-0.047891 pos:   1366 size:     6 skip:2112 discard:0
 ret: 0         st: 0 flags:1 dts:-0.024671 pts:-0.024671 pos:   1372 size:   251
 ret: 0         st: 0 flags:1 dts:-0.001451 pts:-0.001451 pos:   1623 size:   168
-ret: 0         st: 0 flags:1 dts: 0.021769 pts: 0.021769 pos:   1791 size:    89
-ret: 0         st:-1 flags:0  ts:-1.000000
+ret: 0         st:-1 flags:1  ts:-0.105833
+ret: 0         st: 0 flags:1 dts:-0.047891 pts:-0.047891 pos:   1366 size:     6 skip:2112 discard:0
+ret: 0         st: 0 flags:1 dts:-0.024671 pts:-0.024671 pos:   1372 size:   251
+ret: 0         st: 0 flags:1 dts:-0.001451 pts:-0.001451 pos:   1623 size:   168
+ret: 0         st: 0 flags:0  ts: 0.788345
+ret: 0         st: 0 flags:1 dts: 0.811247 pts: 0.811247 pos:   2774 size:    27
+ret: 0         st: 0 flags:1 dts: 0.834467 pts: 0.834467 pos:   2801 size:    28
+ret: 0         st: 0 flags:1 dts: 0.857687 pts: 0.857687 pos:   2829 size:    28
+ret: 0         st: 0 flags:1  ts: 1.682494
+ret: 0         st: 0 flags:1 dts: 1.670385 pts: 1.670385 pos:   3984 size:    41
+ret: 0         st: 0 flags:1 dts: 1.693605 pts: 1.693605 pos:   4025 size:    41
+ret: 0         st: 0 flags:1 dts: 1.716825 pts: 1.716825 pos:   4066 size:    41
+ret: 0         st:-1 flags:0  ts:-0.423332
+ret: 0         st: 0 flags:1 dts:-0.047891 pts:-0.047891 pos:   1366 size:     6 skip:2112 discard:0
+ret: 0         st: 0 flags:1 dts:-0.024671 pts:-0.024671 pos:   1372 size:   251
+ret: 0         st: 0 flags:1 dts:-0.001451 pts:-0.001451 pos:   1623 size:   168
+ret: 0         st:-1 flags:1  ts: 0.470835
+ret: 0         st: 0 flags:1 dts: 0.462948 pts: 0.462948 pos:   2363 size:    26
+ret: 0         st: 0 flags:1 dts: 0.486168 pts: 0.486168 pos:   2389 size:    27
+ret: 0         st: 0 flags:1 dts: 0.509388 pts: 0.509388 pos:   2416 size:    27
+ret: 0         st: 0 flags:0  ts: 1.365011
+ret: 0         st: 0 flags:1 dts: 1.368526 pts: 1.368526 pos:   3465 size:    30
+ret: 0         st: 0 flags:1 dts: 1.391746 pts: 1.391746 pos:   3495 size:    39
+ret: 0         st: 0 flags:1 dts: 1.414966 pts: 1.414966 pos:   3534 size:    42
+ret: 0         st: 0 flags:1  ts:-0.740839
+ret: 0         st: 0 flags:1 dts:-0.047891 pts:-0.047891 pos:   1366 size:     6 skip:2112 discard:0
+ret: 0         st: 0 flags:1 dts:-0.024671 pts:-0.024671 pos:   1372 size:   251
+ret: 0         st: 0 flags:1 dts:-0.001451 pts:-0.001451 pos:   1623 size:   168
+ret: 0         st:-1 flags:0  ts: 0.153336
+ret: 0         st: 0 flags:1 dts: 0.161088 pts: 0.161088 pos:   2014 size:    27
+ret: 0         st: 0 flags:1 dts: 0.184308 pts: 0.184308 pos:   2041 size:    27
+ret: 0         st: 0 flags:1 dts: 0.207528 pts: 0.207528 pos:   2068 size:    27
+ret: 0         st:-1 flags:1  ts: 1.047503
+ret: 0         st: 0 flags:1 dts: 1.043447 pts: 1.043447 pos:   3052 size:    27
+ret: 0         st: 0 flags:1 dts: 1.066667 pts: 1.066667 pos:   3079 size:    28
+ret: 0         st: 0 flags:1 dts: 1.089887 pts: 1.089887 pos:   3107 size:    30
+ret: 0         st: 0 flags:0  ts: 1.941678
+ret: 0         st: 0 flags:1 dts: 1.949025 pts: 1.949025 pos:   4474 size:    41
+ret: 0         st: 0 flags:1 dts: 1.972245 pts: 1.972245 pos:   4515 size:    39
+ret: 0         st: 0 flags:1 dts: 1.995465 pts: 1.995465 pos:   4554 size:    42
+ret: 0         st: 0 flags:1  ts:-0.164172
+ret: 0         st: 0 flags:1 dts:-0.047891 pts:-0.047891 pos:   1366 size:     6 skip:2112 discard:0
+ret: 0         st: 0 flags:1 dts:-0.024671 pts:-0.024671 pos:   1372 size:   251
+ret: 0         st: 0 flags:1 dts:-0.001451 pts:-0.001451 pos:   1623 size:   168
+ret: 0         st:-1 flags:0  ts: 0.730004
+ret: 0         st: 0 flags:1 dts: 0.741587 pts: 0.741587 pos:   2691 size:    28
+ret: 0         st: 0 flags:1 dts: 0.764807 pts: 0.764807 pos:   2719 size:    28
+ret: 0         st: 0 flags:1 dts: 0.788027 pts: 0.788027 pos:   2747 size:    27
+ret: 0         st:-1 flags:1  ts: 1.624171
+ret: 0         st: 0 flags:1 dts: 1.623946 pts: 1.623946 pos:   3903 size:    39
+ret: 0         st: 0 flags:1 dts: 1.647166 pts: 1.647166 pos:   3942 size:    42
+ret: 0         st: 0 flags:1 dts: 1.670385 pts: 1.670385 pos:   3984 size:    41
+ret: 0         st: 0 flags:0  ts:-0.481655
+ret: 0         st: 0 flags:1 dts:-0.047891 pts:-0.047891 pos:   1366 size:     6 skip:2112 discard:0
+ret: 0         st: 0 flags:1 dts:-0.024671 pts:-0.024671 pos:   1372 size:   251
+ret: 0         st: 0 flags:1 dts:-0.001451 pts:-0.001451 pos:   1623 size:   168
+ret: 0         st: 0 flags:1  ts: 0.412494
+ret: 0         st: 0 flags:1 dts: 0.393288 pts: 0.393288 pos:   2282 size:    27
+ret: 0         st: 0 flags:1 dts: 0.416508 pts: 0.416508 pos:   2309 size:    27
+ret: 0         st: 0 flags:1 dts: 0.439728 pts: 0.439728 pos:   2336 size:    27
+ret: 0         st:-1 flags:0  ts: 1.306672
+ret: 0         st: 0 flags:1 dts: 1.322086 pts: 1.322086 pos:   3405 size:    30
+ret: 0         st: 0 flags:1 dts: 1.345306 pts: 1.345306 pos:   3435 size:    30
+ret: 0         st: 0 flags:1 dts: 1.368526 pts: 1.368526 pos:   3465 size:    30
+ret: 0         st:-1 flags:1  ts:-0.799161
+ret: 0         st: 0 flags:1 dts:-0.047891 pts:-0.047891 pos:   1366 size:     6 skip:2112 discard:0
+ret: 0         st: 0 flags:1 dts:-0.024671 pts:-0.024671 pos:   1372 size:   251
+ret: 0         st: 0 flags:1 dts:-0.001451 pts:-0.001451 pos:   1623 size:   168
+ret: 0         st: 0 flags:0  ts: 0.095011
+ret: 0         st: 0 flags:1 dts: 0.114649 pts: 0.114649 pos:   1961 size:    26
+ret: 0         st: 0 flags:1 dts: 0.137868 pts: 0.137868 pos:   1987 size:    27
+ret: 0         st: 0 flags:1 dts: 0.161088 pts: 0.161088 pos:   2014 size:    27
+ret: 0         st: 0 flags:1  ts: 0.989184
+ret: 0         st: 0 flags:1 dts: 0.973787 pts: 0.973787 pos:   2968 size:    28
+ret: 0         st: 0 flags:1 dts: 0.997007 pts: 0.997007 pos:   2996 size:    28
+ret: 0         st: 0 flags:1 dts: 1.020227 pts: 1.020227 pos:   3024 size:    28
+ret: 0         st:-1 flags:0  ts: 1.883340
+ret: 0         st: 0 flags:1 dts: 1.902585 pts: 1.902585 pos:   4392 size:    41
+ret: 0         st: 0 flags:1 dts: 1.925805 pts: 1.925805 pos:   4433 size:    41
+ret: 0         st: 0 flags:1 dts: 1.949025 pts: 1.949025 pos:   4474 size:    41
+ret: 0         st:-1 flags:1  ts:-0.222493
+ret: 0         st: 0 flags:1 dts:-0.047891 pts:-0.047891 pos:   1366 size:     6 skip:2112 discard:0
+ret: 0         st: 0 flags:1 dts:-0.024671 pts:-0.024671 pos:   1372 size:   251
+ret: 0         st: 0 flags:1 dts:-0.001451 pts:-0.001451 pos:   1623 size:   168
+ret: 0         st: 0 flags:0  ts: 0.671678
+ret: 0         st: 0 flags:1 dts: 0.671927 pts: 0.671927 pos:   2609 size:    27
+ret: 0         st: 0 flags:1 dts: 0.695147 pts: 0.695147 pos:   2636 size:    27
+ret: 0         st: 0 flags:1 dts: 0.718367 pts: 0.718367 pos:   2663 size:    28
+ret: 0         st: 0 flags:1  ts: 1.565850
+ret: 0         st: 0 flags:1 dts: 1.554286 pts: 1.554286 pos:   3780 size:    41
+ret: 0         st: 0 flags:1 dts: 1.577506 pts: 1.577506 pos:   3821 size:    41
+ret: 0         st: 0 flags:1 dts: 1.600726 pts: 1.600726 pos:   3862 size:    41
+ret: 0         st:-1 flags:0  ts:-0.539992
 ret: 0         st: 0 flags:1 dts:-0.047891 pts:-0.047891 pos:   1366 size:     6 skip:2112 discard:0
 ret: 0         st: 0 flags:1 dts:-0.024671 pts:-0.024671 pos:   1372 size:   251
 ret: 0         st: 0 flags:1 dts:-0.001451 pts:-0.001451 pos:   1623 size:   168
-ret:-1         st:-1 flags:1  ts:-0.105833
-ret:-1         st: 0 flags:0  ts: 0.788345
-ret:-1         st: 0 flags:1  ts: 1.682494
-ret:-1         st:-1 flags:0  ts:-0.423332
-ret:-1         st:-1 flags:1  ts: 0.470835
-ret:-1         st: 0 flags:0  ts: 1.365011
-ret:-1         st: 0 flags:1  ts:-0.740839
-ret:-1         st:-1 flags:0  ts: 0.153336
-ret:-1         st:-1 flags:1  ts: 1.047503
-ret:-1         st: 0 flags:0  ts: 1.941678
-ret:-1         st: 0 flags:1  ts:-0.164172
-ret:-1         st:-1 flags:0  ts: 0.730004
-ret:-1         st:-1 flags:1  ts: 1.624171
-ret:-1         st: 0 flags:0  ts:-0.481655
-ret:-1         st: 0 flags:1  ts: 0.412494
-ret:-1         st:-1 flags:0  ts: 1.306672
-ret:-1         st:-1 flags:1  ts:-0.799161
-ret:-1         st: 0 flags:0  ts: 0.095011
-ret:-1         st: 0 flags:1  ts: 0.989184
-ret:-1         st:-1 flags:0  ts: 1.883340
-ret:-1         st:-1 flags:1  ts:-0.222493
-ret:-1         st: 0 flags:0  ts: 0.671678
-ret:-1         st: 0 flags:1  ts: 1.565850
-ret:-1         st:-1 flags:0  ts:-0.539992
-ret:-1         st:-1 flags:1  ts: 0.354175
+ret: 0         st:-1 flags:1  ts: 0.354175
+ret: 0         st: 0 flags:1 dts: 0.346848 pts: 0.346848 pos:   2229 size:    26
+ret: 0         st: 0 flags:1 dts: 0.370068 pts: 0.370068 pos:   2255 size:    27
+ret: 0         st: 0 flags:1 dts: 0.393288 pts: 0.393288 pos:   2282 size:    27
diff --git a/tests/ref/fate/seek_utils b/tests/ref/fate/seek_utils
index ddb0517a45..4d7f12564c 100644
--- a/tests/ref/fate/seek_utils
+++ b/tests/ref/fate/seek_utils
@@ -1,3 +1,3 @@
 1/1 -> 10/1: [10, 20, 30] -> [1, 2, 3]
-1/1 -> 3/1: [10, 32, 32] -> [4, 11, 10]
-1/1 -> 3/1: [10, 10, 32] -> [4, 3, 10]
+1/1 -> 3/1: [10, 32, 32] -> [4, 10, 10]
+1/1 -> 3/1: [10, 10, 32] -> [4, 4, 10]