Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion crates/compositor/src/pipeline_macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,13 @@ impl Decoder {
// 2) La cible est DEVANT et à portée : dérouler depuis ici plutôt que de
// repartir d'une image clé (cf. `pipeline_windows::SEEK_FORWARD_MAX_SEC`).
if cur < seconds && seconds - cur <= SEEK_FORWARD_MAX_SEC {
return self.decode_forward_to(seconds, tb_sec);
let f = self.decode_forward_to(seconds, tb_sec)?;
if !f.is_null() {
return Ok(f);
}
// EOF atteint avant la cible (décodeur réactivé depuis le pool, laissé en fin
// de flux) : on retombe sur le seek keyframe complet au lieu de rendre `null`
// — qui forçait une réouverture complète. Voir `pipeline_windows::seek_to`.
}
}
}
Expand Down
13 changes: 12 additions & 1 deletion crates/compositor/src/pipeline_windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,18 @@ impl Decoder {
// repartir d'une image clé redevient moins cher — un seek coûte en moyenne
// un demi-GOP, soit ~0,5 s sur nos captures.
if cur < seconds && seconds - cur <= SEEK_FORWARD_MAX_SEC {
return self.decode_forward_to(seconds, tb_sec);
let f = self.decode_forward_to(seconds, tb_sec)?;
if !f.is_null() {
return Ok(f);
}
// `decode_forward_to` a atteint l'EOF avant la cible — typiquement un
// décodeur réactivé depuis le pool (`live::swap_clip_pooled`), laissé en fin
// de flux (`sent_eof`), qui ne peut plus avancer. On NE rend PAS `null` : ça
// forçait l'appelant à tout ROUVRIR (~190 ms mesurés), le pire à-coup ressenti
// au franchissement. On retombe sur le seek keyframe complet ci-dessous, qui
// rembobine + réarme le décodeur et repart proprement. Si la cible est
// réellement au-delà de l'EOF, ce seek complet rendra `null` lui aussi :
// comportement inchangé pour ce cas.
}
}
}
Expand Down
11 changes: 7 additions & 4 deletions src/components/ai-edition/VirtualPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -619,10 +619,13 @@ export function VirtualPreview({
// handles clip-end advancement, so dropping the event
// handler here is safe.
/>
{loadState !== "ready" && (
<div className={styles.overlay}>
{loadState === "error" ? "Video preview could not be loaded." : "Loading preview…"}
</div>
{/* Plus d'overlay « Loading preview… » : il reflétait l'état du <video>
CACHÉ (source horloge/audio), pas la preview RÉELLE — le canvas natif,
qui montre déjà une image valide pendant que le <video> re-seek. Il
recouvrait donc une bonne image à chaque scrub, pour rien. On garde
seulement l'erreur, qui, elle, signale un vrai échec de chargement. */}
{loadState === "error" && (
<div className={styles.overlay}>Video preview could not be loaded.</div>
)}
</div>
{/* The native D3D canvas already draws the recorded-cursor sprite as part
Expand Down
Loading