[PATCH] es_out: scale preroll clock-origin compensation by the playback rate
Ismail Degani <[email protected]> Tue, 7 Jul 2026 19:26:13 -0400
| Newsgroups | gmane.comp.video.videolan.vlc.devel |
|---|---|
| Message-ID | <CAEvQf=RHiNc=65L5QeSoy44D_FwNbYR3YZ+SbaCzU7PaN18_kQ@mail.gmail.com> |
--00000000000028c2b106560db87b Content-Type: multipart/alternative; boundary="00000000000028c2b006560db879" --00000000000028c2b006560db879 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi devs, Submitting my first vlc patch for an issue I've had for years (reported 7 years ago! #21890) which Claude gave me the superpowers to finally fix =3D) If you slow a video down =E2=80=94 say to 0.25x =E2=80=94 and then seek, VL= C freezes at the target position for a long time before playback resumes: several seconds with short-GOP files, and 30 seconds or more with the 5-10 second GOPs typical of phone recordings and web video. The slower the rate, the longer the freeze. What happens: after a precise seek, the demuxer restarts at the previous keyframe, and EsOutDecodersStopBuffering() rebases the clock origin by subtracting i_buffering_duration =E2=80=94 a stream-time quantity =E2=80=94= from a system-time date, without scaling by the playback rate. Timestamp conversion then stretches the keyframe-to-target preroll by 1/rate, so playback stalls for exactly preroll * (1/rate - 1). The pts_delay part of that compensation is fine as-is (the input clock already compensates it on every conversion via ClockGetTsOffset(), which is also why caching settings don't affect the stall), so the fix scales only the preroll term. At 1.0x the added term is zero and nothing changes; at rates above 1x the same math currently makes the first post-seek frames late by the mirrored amount, which this also fixes. A note on the filing of #21890: it is labeled Demux: Adaptive because it was reported against an HLS stream in 2019, but the stall reproduces on a plain local mp4 =E2=80=94 the root cause is in core es_out/clock code, not = the adaptive demuxer. That mislabeling may be part of why it has sat unfixed for so long. The same defect is behind the slow-motion seek freezes reported against VLC-Android. Measured with a headless libvlc driver polling media_player_get_time() every 250 ms around a seek to 60s (local mp4, 1.67 s preroll, file-caching 1000; "stall" =3D wall time until the reported time advanced 200 ms past th= e target): master (8115e53): unpatched patched 1.0x 1.75 s 1.75 s (unchanged) 2.0x 1.50 s 1.50 s (unchanged) 0.25x 6.25 s 2.25 s 0.1x 18.0 s 2.5 s The patched residual at slow rates is the measurement floor itself: advancing 200 ms of stream time takes 0.8 s / 2 s of wall time at 0.25x / 0.1x. The same fix was also verified on the 3.0.x branch with a rebuilt libvlccore 3.0.20: the 0.25x stall dropped from ~5-6 s to under 1 s, and 0.1x from ~15-17 s to under 2 s. A formatted 3.0.x backport is ready =E2=80= =94 happy to send it as a follow-up patch or open a [3.0] merge request. Quick repro: generate a two-minute test clip with "ffmpeg -f lavfi -i testsrc2=3Dduration=3D120:size=3D640x360:rate=3D30 -f lavfi -i sine=3Dfrequency=3D440:duration=3D120 -c:v libx264 -preset ultrafast -c:a a= ac test120.mp4", play it, set rate 0.25, seek to ~60s. Running with --input-fast-seek avoids the stall entirely (keyframe seeks have no preroll), which isolates the preroll term. The patch is attached (git format-patch against master 8115e53) rather than inline because this message is sent through a mailer that can't guarantee inline whitespace survives; the full commit message and measurements are inside it, and I can resend inline via git send-email if that's preferred. Two disclosures: I prepared and validated this with AI assistance (noted in a Co-authored-by trailer), and I have reviewed the change and the measurements myself. I also have a https://www.google.com/url?q=3Dhttp://code.videolan.org&source=3Dgmail&ust= =3D1783552830165000&sa=3DE account pending administrator approval =E2=80=94 if a merge request is more convenient for review, I'd gladly resubmit there once it's approved. Thanks! Ismail --00000000000028c2b006560db879 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable <div dir=3D"auto"><div><div dir=3D"auto">Hi devs,</div><div dir=3D"auto"><b= r></div><div dir=3D"auto">Submitting my first vlc patch for an issue I'= ve had for years (reported 7 years ago! #21890) which Claude gave me the su= perpowers to finally fix =3D)<br><br>If you slow a video down =E2=80=94 say= to 0.25x =E2=80=94 and then seek, VLC freezes at the target position for a= long time before playback resumes: several seconds with short-GOP files, a= nd 30 seconds or more with the 5-10 second GOPs typical of phone recordings= and web video. The slower the rate, the longer the freeze.=C2=A0<br><br>Wh= at happens: after a precise seek, the demuxer restarts at the previous keyf= rame, and EsOutDecodersStopBuffering() rebases the clock origin by subtract= ing i_buffering_duration =E2=80=94 a stream-time quantity =E2=80=94 from a = system-time date, without scaling by the playback rate. Timestamp conversio= n then stretches the keyframe-to-target preroll by 1/rate, so playback stal= ls for exactly preroll * (1/rate - 1). The pts_delay part of that compensat= ion is fine as-is (the input clock already compensates it on every conversi= on via ClockGetTsOffset(), which is also why caching settings don't aff= ect the stall), so the fix scales only the preroll term. At 1.0x the added = term is zero and nothing changes; at rates above 1x the same math currently= makes the first post-seek frames late by the mirrored amount, which this a= lso fixes.<br><br>A note on the filing of #21890: it is labeled Demux: Adap= tive because it was reported against an HLS stream in 2019, but the stall r= eproduces on a plain local mp4 =E2=80=94 the root cause is in core es_out/c= lock code, not the adaptive demuxer. That mislabeling may be part of why it= has sat unfixed for so long. The same defect is behind the slow-motion see= k freezes reported against VLC-Android.<br><br>Measured with a headless lib= vlc driver polling media_player_get_time() every 250 ms around a seek to 60= s (local mp4, 1.67 s preroll, file-caching 1000; "stall" =3D wall= time until the reported time advanced 200 ms past the target):<br><br> ma= ster (8115e53): unpatched patched<br> 1.0x 1.75 s = 1.75 s (unchanged)<br> 2.0x 1.50 s 1.50 s (unchang= ed)<br> 0.25x 6.25 s 2.25 s<br> 0.1x 18= .0 s 2.5 s<br><br>The patched residual at slow rates is the measuremen= t floor itself: advancing 200 ms of stream time takes 0.8 s / 2 s of wall t= ime at 0.25x / 0.1x. The same fix was also verified on the 3.0.x branch wit= h a rebuilt libvlccore 3.0.20: the 0.25x stall dropped from ~5-6 s to under= 1 s, and 0.1x from ~15-17 s to under 2 s. A formatted 3.0.x backport is re= ady =E2=80=94 happy to send it as a follow-up patch or open a [3.0] merge r= equest.<br><br>Quick repro: generate a two-minute test clip with "ffmp= eg -f lavfi -i testsrc2=3Dduration=3D120:size=3D640x360:rate=3D30 -f lavfi = -i sine=3Dfrequency=3D440:duration=3D120 -c:v libx264 -preset ultrafast -c:= a aac test120.mp4", play it, set rate 0.25, seek to ~60s. Running with= --input-fast-seek avoids the stall entirely (keyframe seeks have no prerol= l), which isolates the preroll term.<br><br>The patch is attached (git form= at-patch against master 8115e53) rather than inline because this message is= sent through a mailer that can't guarantee inline whitespace survives;= the full commit message and measurements are inside it, and I can resend i= nline via git send-email if that's preferred.<br><br>Two disclosures: I= prepared and validated this with AI assistance (noted in a Co-authored-by = trailer), and I have reviewed the change and the measurements myself. I als= o have a <a href=3D"https://www.google.com/url?q=3Dhttp://code.videolan.org= &source=3Dgmail&ust=3D1783552830165000&sa=3DE" target=3D"_blank= " rel=3D"noreferrer">https://www.google.com/url?q=3Dhttp://code.videolan.or= g&source=3Dgmail&ust=3D1783552830165000&sa=3DE</a> account pend= ing administrator approval =E2=80=94 if a merge request is more convenient = for review, I'd gladly resubmit there once it's approved.<br><br>Th= anks!<br>Ismail<br></div></div></div> --00000000000028c2b006560db879-- --00000000000028c2b106560db87b Content-Type: text/x-patch; charset="US-ASCII"; name="0001-es_out-scale-preroll-master.patch" Content-Disposition: attachment; filename="0001-es_out-scale-preroll-master.patch" Content-Transfer-Encoding: base64 Content-ID: <> X-Attachment-Id: RnJvbSA4MjdlMDZjY2MzYzY2ZjcwZmI4YjVjMjhhNzI3NzIxZWI5MzNmMWNmIE1vbiBTZXAgMTcg MDA6MDA6MDAgMjAwMQpGcm9tOiBJc21haWwgRGVnYW5pIDxkZWdhbmlpQGdtYWlsLmNvbT4KRGF0 ZTogU3VuLCA1IEp1bCAyMDI2IDAxOjM4OjAxICswMDAwClN1YmplY3Q6IFtQQVRDSF0gZXNfb3V0 OiBzY2FsZSBwcmVyb2xsIGNsb2NrLW9yaWdpbiBjb21wZW5zYXRpb24gYnkgdGhlCiBwbGF5YmFj ayByYXRlCgpBZnRlciBhIHNlZWssIEVzT3V0RGVjb2RlcnNTdG9wQnVmZmVyaW5nKCkgcmViYXNl cyB0aGUgY2xvY2sgc3lzdGVtCm9yaWdpbiBieSBzdWJ0cmFjdGluZyBpX2J1ZmZlcmluZ19kdXJh dGlvbiwgYSBzdHJlYW0tdGltZSBkdXJhdGlvbiwgZnJvbQphIHN5c3RlbS10aW1lIGRhdGUgd2l0 aG91dCBhY2NvdW50aW5nIGZvciB0aGUgcGxheWJhY2sgcmF0ZS4gVGltZXN0YW1wCmNvbnZlcnNp b24gdGhlbiBzdHJldGNoZXMgdGhlIHByZXJvbGwgcG9ydGlvbiBieSAxL3JhdGUsIHNvIGF0IHJh dGVzCmJlbG93IDEuMCBldmVyeSBwcmVjaXNlIHNlZWsgc3RhbGxzIHBsYXliYWNrIGZvcgppX3By ZXJvbGxfZHVyYXRpb24gKiAoMS9yYXRlIC0gMSkgd2hpbGUgdGhlIHByZXJvbGwgaXMgcmVwbGF5 ZWQgaW4Kc3RyZXRjaGVkIHdhbGwgdGltZS4KCldpdGggYSAxLjY3cyBwcmVyb2xsIHRoaXMgbWVh c3VyZXMgYXMgYSB+NXMgZnJlZXplIGF0IDAuMjV4IGFuZCBhIH4xNnMKZnJlZXplIGF0IDAuMXg7 IHdpdGggdHlwaWNhbCA1LTEwcyBHT1BzIHRoZSBmcmVlemUgcmVhY2hlcyAxNS02MHMsCm1ha2lu ZyBzZWVraW5nIGVmZmVjdGl2ZWx5IHVudXNhYmxlIGluIHNsb3cgbW90aW9uIChpc3N1ZSAjMjE4 OTAsIGFsc28KcmVwb3J0ZWQgYWdhaW5zdCB2bGMtYW5kcm9pZCkuCgpTY2FsZSBvbmx5IHRoZSBw cmVyb2xsIHBhcnQgb2YgdGhlIGNvbXBlbnNhdGlvbiBieSB0aGUgcmF0ZS4gVGhlCnB0c19kZWxh eSBwYXJ0IG11c3Qgc3RheSB1bnNjYWxlZCBiZWNhdXNlIHRoZSBpbnB1dCBjbG9jayBhbHJlYWR5 CmNvbXBlbnNhdGVzIGl0IG9uIGV2ZXJ5IGNvbnZlcnNpb24gdmlhIENsb2NrR2V0VHNPZmZzZXQo KTsgc2NhbGluZyBpdApoZXJlIHRvbyB3b3VsZCBtYWtlIHRoZSBmaXJzdCBmcmFtZXMgbGF0ZSBi eSBwdHNfZGVsYXkgKiAoMS9yYXRlIC0gMSkuCgpWZXJpZmllZCBvbiBtYXN0ZXIgKDgxMTVlNTMp IHdpdGggYSBoZWFkbGVzcyBsaWJ2bGMgZHJpdmVyIHBvbGxpbmcKbWVkaWFfcGxheWVyX2dldF90 aW1lKCkgZXZlcnkgMjUwbXMgYXJvdW5kIGEgc2V0X3RpbWUoKSB0byA2MHMgb24gYQpsb2NhbCBt cDQgKDEuNjdzIHByZXJvbGwsIGZpbGUtY2FjaGluZyAxMDAwKS4gV2FsbCB0aW1lIHVudGlsIHRo ZQpyZXBvcnRlZCB0aW1lIGFkdmFuY2VkIDIwMG1zIHBhc3QgdGhlIHNlZWsgdGFyZ2V0OgoKICBy YXRlICAgIGJlZm9yZSAgICAgIGFmdGVyCiAgMS4weCAgICAxLjc1cyAgICAgICAxLjc1cyAgICh1 bmNoYW5nZWQpCiAgMi4weCAgICAxLjUwcyAgICAgICAxLjUwcyAgICh1bmNoYW5nZWQpCiAgMC4y NXggICA2LjI1cyAgICAgICAyLjI1cwogIDAuMXggICAgMTguMHMgICAgICAgMi41cwoKKHRoZSBy ZXNpZHVhbCBhdCBzbG93IHJhdGVzIGlzIHRoZSBtZWFzdXJlbWVudCBpdHNlbGY6IGFkdmFuY2lu ZyAyMDBtcwpvZiBzdHJlYW0gdGltZSB0YWtlcyAwLjhzIC8gMnMgb2Ygd2FsbCB0aW1lIGF0IDAu MjV4IC8gMC4xeC4pCgpUaGUgc2FtZSBmaXggd2FzIHByZXZpb3VzbHkgdmVyaWZpZWQgYWdhaW5z dCB0aGUgMy4wLnggYnJhbmNoIHdpdGggYQpwYXRjaGVkIGxpYnZsY2NvcmUgMy4wLjIwOiBzdGFs bCBhdCAwLjI1eCBkcm9wcGVkIGZyb20gfjUtNnMgdG8gdW5kZXIKMXMsIGF0IDAuMXggZnJvbSB+ MTUtMTdzIHRvIHVuZGVyIDJzLgoKQ28tYXV0aG9yZWQtYnk6IENsYXVkZSA8bm9yZXBseUBhbnRo cm9waWMuY29tPgotLS0KIHNyYy9pbnB1dC9lc19vdXQuYyB8IDEwICsrKysrKysrKy0KIDEgZmls ZSBjaGFuZ2VkLCA5IGluc2VydGlvbnMoKyksIDEgZGVsZXRpb24oLSkKCmRpZmYgLS1naXQgYS9z cmMvaW5wdXQvZXNfb3V0LmMgYi9zcmMvaW5wdXQvZXNfb3V0LmMKaW5kZXggZGIyZmY5MC4uOTA4 MDc4ZCAxMDA2NDQKLS0tIGEvc3JjL2lucHV0L2VzX291dC5jCisrKyBiL3NyYy9pbnB1dC9lc19v dXQuYwpAQCAtMTIxOCw3ICsxMjE4LDE1IEBAIHN0YXRpYyB2b2lkIEVzT3V0RGVjb2RlcnNTdG9w QnVmZmVyaW5nKGVzX291dF9zeXNfdCAqcF9zeXMsIGJvb2wgYl9mb3JjZWQpCiAgICAgLyogKi8K ICAgICBjb25zdCB2bGNfdGlja190IGlfY3VycmVudF9kYXRlID0gcF9zeXMtPmJfcGF1c2VkID8g cF9zeXMtPmlfcGF1c2VfZGF0ZSA6IHZsY190aWNrX25vdygpOwogCi0gICAgY29uc3QgdmxjX3Rp Y2tfdCB1cGRhdGUgPSBpX2N1cnJlbnRfZGF0ZSAtIGlfYnVmZmVyaW5nX2R1cmF0aW9uOworICAg IC8qIFRoZSBidWZmZXJlZCBkYXRhIHdpbGwgYmUgY29uc3VtZWQgYXQgdGhlIGN1cnJlbnQgcGxh eWJhY2sgcmF0ZTogc2NhbGUKKyAgICAgKiB0aGUgb3JpZ2luIGNvbXBlbnNhdGlvbiBmb3IgdGhl IHByZXJvbGwgcGFydCBhY2NvcmRpbmdseSwgb3RoZXJ3aXNlIGEKKyAgICAgKiBwcmVjaXNlIHNl ZWsgYXQgcmF0ZSAhPSAxLjAgcmVwbGF5cyB0aGUgcHJlcm9sbCAoa2V5ZnJhbWUgLT4gc2Vlawor ICAgICAqIHRhcmdldCkgc3RyZXRjaGVkIGJ5IDEvcmF0ZSBpbiB3YWxsIHRpbWUsIHN0YWxsaW5n IHBsYXliYWNrIGZvcgorICAgICAqIGlfcHJlcm9sbF9kdXJhdGlvbiAqICgxL3JhdGUgLSAxKSAo c2VlIGlzc3VlICMyMTg5MCkuIFRoZSBwdHNfZGVsYXkKKyAgICAgKiBwYXJ0IG11c3QgTk9UIGJl IHNjYWxlZCBoZXJlOiB0aGUgaW5wdXQgY2xvY2sgYWxyZWFkeSBjb21wZW5zYXRlcyBpdAorICAg ICAqIG9uIHRpbWVzdGFtcCBjb252ZXJzaW9uIChDbG9ja0dldFRzT2Zmc2V0KS4gKi8KKyAgICBj b25zdCB2bGNfdGlja190IHVwZGF0ZSA9IGlfY3VycmVudF9kYXRlIC0gaV9idWZmZXJpbmdfZHVy YXRpb24KKyAgICAgICAgLSAodmxjX3RpY2tfdCkoaV9wcmVyb2xsX2R1cmF0aW9uICogKDEuMCAv IHBfc3lzLT5yYXRlIC0gMS4wKSk7CiAKICAgICAvKiBUaGUgY2FsbCBvcmRlciBvZiB0aGVzZSAz IGlucHV0X2Nsb2NrX3QvdmxjX2Nsb2NrX21haW5fdCBmdW5jdGlvbnMgaXMKICAgICAgKiBpbXBv cnRhbnQ6Ci0tIAoyLjQzLjAKCg== --00000000000028c2b106560db87b Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ vlc-devel mailing list To unsubscribe or modify your subscription options: https://mailman.videolan.org/listinfo/vlc-devel --00000000000028c2b106560db87b--