Skip to content

fix(preview): seek_to retombe sur un seek complet quand le décode-avant bute sur l'EOF - #211

Merged
EtienneLescot merged 2 commits into
release/v1.8.0from
fix/pooled-reseek-eof
Jul 30, 2026
Merged

fix(preview): seek_to retombe sur un seek complet quand le décode-avant bute sur l'EOF#211
EtienneLescot merged 2 commits into
release/v1.8.0from
fix/pooled-reseek-eof

Conversation

@EtienneLescot

@EtienneLescot EtienneLescot commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Suite du pool de décodeurs (#209).

Le défaut

Dans un scrub réel (logs OPENSCREEN_CLIPSWITCH_TIMING), ~13 % des franchissements restaient à ~190 ms au lieu du POOL_HIT attendu. Cause : un décodeur réactivé depuis le pool est souvent laissé en fin de flux (on venait d'y scruber près de la fin avant de le quitter). Quand on y revient et qu'on le repositionne un peu plus loin, le chemin rapide decode_forward_to bute sur l'EOF et rendait nullswap_clip_pooled jetait la paire poolée et rouvrait tout à neuf (~190 ms). Ce sont les pires à-coups ressentis au franchissement.

Le correctif

Dans seek_to (donc utile aussi à seek_active, pas seulement au pool) : quand le décode-avant atteint l'EOF avant la cible, on ne rend plus null — on retombe sur le seek keyframe complet juste en dessous, qui rembobine + réarme le décodeur et repart proprement. Si la cible est réellement au-delà de l'EOF, le seek complet rend null lui aussi : comportement inchangé pour ce cas. Appliqué aux deux backends (pipeline_windows + pipeline_macos).

Mesures (headless, GPU au repos)

Les reseeks près de l'EOF passent de OPEN ~190 ms → POOL_HIT ~50-80 ms. Jamais pire que l'état d'avant (le pire cas reste le même repli sur ouverture).

Sûreté

La classe « frame sans texture → preview noire » a déjà mordu dans ce fichier. Vérifié avec un harnais qui lit les pixels (pas seulement le compteur de générations) : sur 46 franchissements — sauts, retours locaux, éviction LRU 5 assets, et près de l'EOF0 preview noire, 0 frame stale, chaque franchissement produit une frame fraîche valide.

(Un premier jet signalait des « frames absentes » : c'étaient des faux positifs d'un pump trop court qui expirait avant qu'un seek keyframe près de l'EOF, GPU alors chargé par l'app de test, ait fini. GPU au repos + fenêtre large → 0.)

cargo check OK (Windows) ; le backend macOS est identique, validé par la CI Rust.

Portée honnête

C'est une robustesse marginale au-dessus de #209 : elle supprime les pires spikes (les ~190 ms), pas une transformation ressentie — le scrub reste dominé par le seek keyframe (~30-90 ms, quasi incompressible en H.264 sans proxy).

…nt bute sur l'EOF

Suite du pool de décodeurs (#209). Un décodeur réactivé depuis le pool est souvent laissé en
FIN de flux (on venait d'y scruber près de la fin avant de le quitter). Quand on y revient et
qu'on le repositionne un poil plus loin, le chemin rapide `decode_forward_to` bute sur l'EOF et
rendait `null` — ce qui forçait `swap_clip_pooled` à JETER la paire poolée et à tout ROUVRIR :
mesuré ~190 ms, les pires à-coups ressentis au franchissement (13 % des franchissements dans un
scrub réel, cf. les logs `OPENSCREEN_CLIPSWITCH_TIMING`).

Correctif dans `seek_to` (donc utile aussi à `seek_active`, pas seulement au pool) : quand le
décode-avant atteint l'EOF avant la cible, on NE rend plus `null` — on retombe sur le seek
keyframe complet en dessous, qui rembobine + réarme le décodeur et repart proprement. Si la
cible est réellement au-delà de l'EOF, le seek complet rend `null` lui aussi : comportement
inchangé pour ce cas. Appliqué aux deux backends (`pipeline_windows` + `pipeline_macos`).

Effet mesuré (headless, GPU au repos) : les reseeks près de l'EOF passent de OPEN ~190 ms à
POOL_HIT ~50-80 ms. Jamais pire que l'état d'avant (pire cas identique : même repli ouverture).

Sûreté vérifiée (harnais avec lecture des pixels, pas seulement le compteur de générations) :
sur 46 franchissements — sauts, retours locaux, éviction LRU 5 assets, ET près de l'EOF —
**0 preview noire, 0 frame stale** ; chaque franchissement produit une frame fraîche valide.
(Les "frames absentes" d'un premier jet étaient des faux positifs : un `pump` trop court qui
expirait avant qu'un seek keyframe près de l'EOF, GPU chargé, ait fini.) cargo check OK.
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 983b3389-f426-4767-990b-2907c40a809f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

… une image valide

L'overlay reflétait l'état du `<video>` CACHÉ (source horloge/audio), pas la preview réelle —
le canvas natif D3D, qui affiche déjà une image valide pendant que le `<video>` re-seek. À
chaque scrub/seek, `loadState` passait à « loading » et le panneau « Loading preview… » venait
recouvrir une bonne image, au milieu de l'écran, pour rien — plus gênant qu'utile.

On n'affiche plus que l'erreur (`loadState === "error"`), qui, elle, signale un vrai échec de
chargement (auquel cas le natif ne montre rien non plus). Le reste de `loadState` est conservé
tel quel.
@EtienneLescot
EtienneLescot merged commit 41aa0c3 into release/v1.8.0 Jul 30, 2026
11 checks passed
@EtienneLescot
EtienneLescot deleted the fix/pooled-reseek-eof branch July 30, 2026 13:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant