Files
Miguel Ángel 5a77dbcea1 perf(core): the preview loads only the media near the playhead (#4682)
* perf(core): the preview loads only the media on screen or due next

Studios preview bound every timed video and audio at preload=auto and called

* perf(core): a far clip in the preview stays unloaded until it comes due

A trimmed clip outside the window now waits at preload=none, reloaded so a fetch
the parser started stops too; at metadata, 60 clips' header reads still queued
on the origin under a slow link. An untrimmed clip keeps metadata, since its
window is read from the element's duration.

* fix(core): a far preview clip makes no request before it comes due

Chromium keeps fetching a clip once it has started, whatever preload says after,
so the reload at preload=none from the bind only restarted the fetch. In Studio's
preview the runtime now sets preload=none on each trimmed clip after the first
frame as it is parsed, and reloads only a clip the window armed when it leaves.

* perf(core): a playing clip loads the next clip on its track

At 3 MB/s a cold 1080p clip needed about 3.3 s to show a frame, longer than the
2 s look-ahead, so every clip on a one-track film was still empty when it came
due. While the film plays, a clip that starts now arms the next clip on the same
track (authored track index within one composition host, read as the timeline
payload reads it), and the window pass keeps that clip armed. Paused or
scrubbing, only the look-ahead applies.

* chore(core): say in one line why the preview parses later clips at preload none

* fix(core): the Studio timeline stops waiting on clips the preview left unloaded

Studio's timeline readiness scans every media element for canplay, so each far
clip the preview deferred held it until the 8 s timeout. In a document with the
Studio preview mark, a clip the runtime has not set to buffer now counts only
if it is on the first frame, as a lazy image already does.

* fix(core): a clip leaving the preview window closes its fetch on a slow link

Chromium keeps a fetch in flight when preload drops to none and load() runs, so
on a 3 MB/s link each played clip kept its connection and the armed next clip
queued behind them with no bytes. The release now drops src around the reload
and puts the same attribute back, which ends the fetch without a new one.

* refactor(core): name the authored-length check for what it reads

* fix(player): a clip the preview stops preloading drops its parent-frame copy

The player adopts each iframe clip whose preload turns auto into a parent-frame
proxy that fetches the whole file, but never let go when the runtime set the
clip back to none. On a 3 MB/s link those proxies and the thumbnail reads held
all six connections, so the armed next clip got no bytes. A demoted clip now
releases its proxy through the same path a removed clip uses.

* chore(player): keep the proxy adoption note in one place

* perf(studio): pause timeline thumbnails while playing preview media waits

A playing preview clip that fires waiting now holds every thumbnail job and
aborts the ones in flight until the transport stops; they re-run afterwards.
An aborted job frees its slot at once, and a filmstrip decode closes its
range requests on abort.

* Revert "perf(studio): pause timeline thumbnails while playing preview media waits"

This reverts commit 36926ebf22.

* fix(core): preview keeps loop-start clips loaded and drops arms a jump leaves behind

Studio's loop tick now tells the runtime where a wrap lands (window.__hf.setLoopStart), and
while playing the preview keeps the clips due there loaded, so a wrap no longer starts cold.
A next-on-track arm lasts only while the clip that set it plays on screen, so a jump away
releases it. A clip with no authored length stays out of the window and loads as in a
render, so no reload drops its duration. A clip is held until 4 s ahead after it is armed
at 2 s, so a scrub or a pause at the edge does not refetch it. The parse-time watcher is
installed only in the preview, once per page. One helper stops a clip's download, <source>
children included, for released and detached media alike.

* fix(core): a loop wrap also keeps the loop-in clip's next clip loaded

The loop start's clips are held out to the 4 s release distance, as a clip being left is, so
the wrap no longer reloads the clip after the loop-in one from nothing.

* fix(core): the preview leaves clips on <source> children out of its release

Putting a clip's <source> children back after the reload started a new download and moved them
ahead of its other children, which a scene swap reads as an edit. Release now stops only a src
clip's fetch; detached media is dropped as on main. Tests cover the loop hold's playing check,
its time check, and the untrimmed guard on the next-clip arm.

* style(core): drop a release comment the commit message already carries

* fix(core): arm a nested clip timed in root seconds by its real start

* fix(core): keep a clip loaded for a step back across its end in the preview
2026-09-29 18:44:13 +00:00
..