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

Commit 63b7e4cefa91 removed the page duration scan in vorbis_packet()
that ran when os->lastpts was unset. While that scan previously ran on
every packet of a page and reset parser blocksize state during normal
playback, removing it entirely left os->lastpts unset at the start of
non-BOS pages after ogg_reset().

As a result, ogg_read_timestamp() could not determine a page's start
timestamp until advancing to the following page, and packets read from
the start of a page after a seek were stamped with the seek target's
cur_dts rather than the page start's timestamp.

When os->lastpts is AV_NOPTS_VALUE at os->page_start on a non-BOS,
non-EOS page, scan the remaining packets on the page to set os->lastpts
to os->granule minus the page duration, and restore the parser blocksize
state to the first packet afterwards.

Fixes #24768.


>From 5f878cd0665be7dffaf00fb3c8ab2eb22ffd1d17 Mon Sep 17 00:00:00 2001
From: Dale Curtis <[email protected]>
Date: Thu, 1 Oct 2026 22:23:56 +0000
Subject: [PATCH] lavf/oggparsevorbis: restore page-start timestamp calculation
 after seek

Commit 63b7e4cefa91 removed the page duration scan in vorbis_packet()
that ran when os->lastpts was unset. While that scan previously ran on
every packet of a page and reset parser blocksize state during normal
playback, removing it entirely left os->lastpts unset at the start of
non-BOS pages after ogg_reset().

As a result, ogg_read_timestamp() could not determine a page's start
timestamp until advancing to the following page, and packets read from
the start of a page after a seek were stamped with the seek target's
cur_dts rather than the page start's timestamp.

When os->lastpts is AV_NOPTS_VALUE at os->page_start on a non-BOS,
non-EOS page, scan the remaining packets on the page to set os->lastpts
to os->granule minus the page duration, and restore the parser blocksize
state to the first packet afterwards.

Fixes #24768.
---
 libavformat/oggparsevorbis.c      | 29 ++++++++++++++++++++++++++---
 tests/ref/fate/ogg-vorbis-ts-seek | 30 +++++++++++++++---------------
 2 files changed, 41 insertions(+), 18 deletions(-)

diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c
index a344081527..b4a1cfb509 100644
--- a/libavformat/oggparsevorbis.c
+++ b/libavformat/oggparsevorbis.c
@@ -478,10 +478,10 @@ static int vorbis_packet(AVFormatContext *s, int idx)
 
     bos = os->page_start && os->page_pos == priv->bos_page_pos;
 
-    if (bos) {
+    if (bos || (os->page_start && os->lastpts == AV_NOPTS_VALUE))
         av_vorbis_parse_reset(priv->vp);
+    if (bos)
         priv->last_page_granule = 0;
-    }
 
     duration = av_vorbis_parse_frame_flags(priv->vp, os->buf + os->pstart, 1, 
&flags);
     if (duration < 0) {
@@ -497,12 +497,35 @@ static int vorbis_packet(AVFormatContext *s, int idx)
     if (!priv->ts_offset)
         priv->ts_offset = os->pduration;
 
-    /* Initial position shift to account for encoder delay. */
+    /* Initial position shift to account for encoder delay, or page scan
+     * to recover the page start timestamp after a seek. */
     if (bos) {
         if (os->lastpts != AV_NOPTS_VALUE)
             os->lastpts -= priv->ts_offset;
         if (os->lastdts != AV_NOPTS_VALUE)
             os->lastdts -= priv->ts_offset;
+    } else if (os->page_start && os->lastpts == AV_NOPTS_VALUE &&
+               !(os->flags & OGG_FLAG_EOS) && (int64_t)os->granule >= 0) {
+        int seg, page_duration = os->pduration;
+        uint8_t *last_pkt = os->buf + os->pstart + os->psize;
+        uint8_t *next_pkt = last_pkt;
+
+        for (seg = os->segp; seg < os->nsegs; seg++) {
+            next_pkt += os->segments[seg];
+            if (os->segments[seg] < 255 && next_pkt != last_pkt) {
+                int pkt_flags = 0;
+                int d = av_vorbis_parse_frame_flags(priv->vp, last_pkt, 1, 
&pkt_flags);
+                if (d < 0) {
+                    page_duration = os->granule;
+                    break;
+                }
+                page_duration += d;
+                last_pkt = next_pkt;
+            }
+        }
+        av_vorbis_parse_frame_flags(priv->vp, os->buf + os->pstart, 1, &flags);
+        os->lastpts =
+        os->lastdts = os->granule - page_duration;
     }
 
     /* Broken files may have granule=0 on pages that contain audio data.
diff --git a/tests/ref/fate/ogg-vorbis-ts-seek 
b/tests/ref/fate/ogg-vorbis-ts-seek
index 00fd55dcdf..779dd1e995 100644
--- a/tests/ref/fate/ogg-vorbis-ts-seek
+++ b/tests/ref/fate/ogg-vorbis-ts-seek
@@ -1,31 +1,31 @@
 [PACKET]
-pts=89536
-dts=89536
-duration=128
+pts=44608
+dts=44608
+duration=1024
 flags=K__
 [/PACKET]
 [PACKET]
-pts=89664
-dts=89664
-duration=128
+pts=45632
+dts=45632
+duration=1024
 flags=K__
 [/PACKET]
 [PACKET]
-pts=89792
-dts=89792
-duration=128
+pts=46656
+dts=46656
+duration=1024
 flags=K__
 [/PACKET]
 [PACKET]
-pts=89920
-dts=89920
-duration=128
+pts=47680
+dts=47680
+duration=1024
 flags=K__
 [/PACKET]
 [PACKET]
-pts=90048
-dts=90048
-duration=128
+pts=48704
+dts=48704
+duration=1024
 flags=K__
 [/PACKET]
 [STREAM]
-- 
2.52.0

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

Reply via email to