Skip to content

perf(preview): throttler le seek du <video> caché pendant un scrub natif en pause - #210

Closed
EtienneLescot wants to merge 1 commit into
release/v1.8.0from
perf/video-seek-throttle
Closed

perf(preview): throttler le seek du <video> caché pendant un scrub natif en pause#210
EtienneLescot wants to merge 1 commit into
release/v1.8.0from
perf/video-seek-throttle

Conversation

@EtienneLescot

@EtienneLescot EtienneLescot commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Contexte

Le <video> de VirtualPreview ne dessine plus rien : le canvas natif D3D est la seule source de pixels et l'occulte. Le <video> reste monté uniquement pour l'horloge de lecture, le son et la metadata. Or pendant un scrub en pause, l'effet seekTarget posait video.currentTime = … à chaque pas (~60 Hz, cadence du rAF de scrub) → un décodage GPU par pas, pour des pixels jamais montrés et sans son. Ce décodage double exactement celui que fait déjà le compositeur natif (piloté séparément par useNativePlaybackSyncsetNativeTime, depuis le store). Confirmé par instrumentation : le readback natif bloque ~9 ms/frame ; ce <video> fantôme ajoute un décodage complet du même fichier par-dessus, en pure perte.

Le correctif

On throttle ce seek à ~15 Hz (bord de fuite garanti) uniquement dans le cas où il est redondant :

  • LECTURE → le <video> est l'horloge maître + la source audio : seek immédiat, inchangé.
  • natif ABSENT (dev web, addon en échec) → le <video> EST la preview visible : immédiat.
  • scrub en pause + natif actif → throttlé.

Le <video> reste à ≤ ~66 ms de la position — imperceptible pour un Play qui suit, car togglePlay ne re-seek pas, il lit video.currentTime tel quel. Le bord de fuite garantit qu'aucun scrub ne laisse le <video> sur une position périmée après relâchement. Le <video> webcam suit indirectement (son rAF chasse l'horloge de l'écran, qui n'avance plus qu'à ~15 Hz).

Honnêteté sur le gain

Rien de visible ne change : le natif affiche déjà le scrub à pleine cadence. Le gain est de la charge GPU en moins (un décodage dupliqué supprimé aux ¾). Il n'est pas isolable à la sonde — le coût d'un scrub est dominé par les franchissements de clip (voir la PR pool de décodeurs), qui le noient. Ce commit se justifie donc comme suppression d'une redondance prouvée, à downside nul, pas comme un gain de fluidité chiffré. C'est le plus petit des deux leviers ; à prendre ou laisser selon l'appétit pour un diff sûr mais non mesurable.

Vérification

  • tsc --noEmit propre, biome propre (re-vérifié après rebase sur la base courante).
  • 2 tests sur VirtualPreview : coalescence des seeks rapprochés + bord de fuite quand le natif est actif & en pause ; application immédiate sinon (les deux chemins sont bien distingués).

…tif en pause

Le `<video>` de VirtualPreview ne dessine plus rien : le canvas natif D3D est la seule
source de pixels et l'occulte. Le `<video>` reste monté uniquement pour l'horloge de
lecture, le son et la metadata. Or pendant un scrub EN PAUSE, l'effet `seekTarget` posait
`video.currentTime = …` à chaque pas (~60 Hz, cadence du rAF de scrub), donc un décodage
GPU par pas — pour des pixels jamais montrés et sans son. Ce décodage double exactement
celui que fait déjà le compositeur natif (piloté séparément par `useNativePlaybackSync` →
`setNativeTime`, depuis le store). C'est du pur gaspillage, et le vrai coût GPU d'un scrub.

On throttle donc ce seek à ~15 Hz (bord de fuite garanti), ce qui supprime ~3/4 des
décodages dupliqués. Le `<video>` reste à ≤~66 ms de la position — imperceptible pour un
Play qui suit, car `togglePlay` ne re-seek pas : il lit `video.currentTime` tel quel. Le
bord de fuite garantit qu'aucun scrub ne laisse le `<video>` sur une position périmée
après relâchement (sinon départ audio décalé au Play). Le `<video>` webcam suit
indirectement : son rAF chasse l'horloge publiée par l'écran, qui n'avance plus qu'à
~15 Hz → il se re-seek d'autant moins.

Strictement borné au cas où c'est redondant :
- LECTURE → le `<video>` est l'horloge maître + la source audio : seek immédiat, inchangé.
- natif ABSENT (dev web, addon en échec) → le `<video>` EST la preview visible : immédiat.
- seeks SOURCE (rares, discrets) : non throttlés.

Rien de visible ne change : le natif affiche déjà le scrub à pleine cadence. Le gain est
indirect — moins de contention GPU pendant le scrub — à confirmer à la sonde.

Vérifié : tsc, biome, 72/72 src/components/ai-edition dont 2 nouveaux tests
(coalescence + bord de fuite quand natif actif & en pause ; immédiat sinon).
@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: 100f4097-ce6b-456c-8a6b-30599a956e6f

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.

@EtienneLescot

Copy link
Copy Markdown
Collaborator Author

Fermée volontairement. Gain non mesurable : le coût du scrub est dominé par la réouverture des décodeurs au franchissement de clip (voir #209, décodeur pool), que ce throttle ne touche pas. Et le correctif fait dépendre VirtualPreview (jusqu'ici agnostique du natif) du store natif — un couplage qui ne se justifie pas pour une redondance imperceptible. On rouvrira si un profil futur montre le décodage

@EtienneLescot
EtienneLescot deleted the perf/video-seek-throttle branch July 30, 2026 12:57
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