Fix multi-shot chain preview inSec for scenes 2+.
Preview now uses the same render.inSec + source_in mapping as export for every scene in a shared chain file, including converted video clips.
This commit is contained in:
@@ -182,14 +182,14 @@
|
||||
sceneId: sc.id,
|
||||
startSec,
|
||||
durationSec: clipDur,
|
||||
inSec: sc.source_in || 0,
|
||||
inSec: S.clipSourceInSec ? S.clipSourceInSec(sc, r) : (sc.source_in || 0),
|
||||
fx,
|
||||
vol,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const inSec = (sc.source_in || 0) + (r?.inSec || 0);
|
||||
const inSec = S.clipSourceInSec ? S.clipSourceInSec(sc, r) : ((sc.source_in || 0) + (r?.inSec || 0));
|
||||
if (r && r.media) {
|
||||
out.push({
|
||||
media: r.media, sceneId: sc.id, startSec, durationSec: dur, inSec,
|
||||
@@ -567,14 +567,18 @@
|
||||
return;
|
||||
}
|
||||
const offset = _phSec - clip.startSec;
|
||||
const sameClip = _currentClip === clip
|
||||
|| (_currentClip && clip && _currentClip.sceneId === clip.sceneId && _sameVideoUrl(_currentClip, clip));
|
||||
const sameVideo = !clip.pending && _active && _sameVideoUrl(_currentClip, clip)
|
||||
const prevClip = _currentClip;
|
||||
const sameClip = prevClip === clip
|
||||
|| (prevClip && clip && prevClip.sceneId === clip.sceneId && _sameVideoUrl(prevClip, clip));
|
||||
const sameVideo = !clip.pending && _active && _sameVideoUrl(prevClip || clip, clip)
|
||||
&& (clip.media || clip.binUrl);
|
||||
if (sameVideo && _active.readyState >= 1) {
|
||||
const crossScene = prevClip && clip && prevClip !== clip
|
||||
&& (prevClip.sceneId !== clip.sceneId || Math.abs((prevClip.inSec || 0) - (clip.inSec || 0)) > 0.05);
|
||||
_currentClip = clip;
|
||||
_applyClipUi(clip);
|
||||
const target = (clip.inSec || 0) + Math.max(0, offset);
|
||||
if (crossScene) _flushVideoSeek(true);
|
||||
_scheduleVideoSeek(target, clip, offset);
|
||||
} else if (!sameClip || clip.pending) {
|
||||
_flushVideoSeek(true);
|
||||
|
||||
@@ -1492,7 +1492,7 @@
|
||||
if (separatedTrackForScene(sceneId)) return;
|
||||
_historyRecord();
|
||||
const idx = state.project.scenes.indexOf(sc);
|
||||
const inSec = (r.inSec || 0) + (sc.source_in || 0);
|
||||
const inSec = clipSourceInSec(sc, r);
|
||||
const dur = sc.source_dur != null ? sc.source_dur : sceneDurationSec(sc);
|
||||
const savedVol = sc.audio_volume != null ? sc.audio_volume : 1;
|
||||
state.project.audio_tracks = state.project.audio_tracks || [];
|
||||
@@ -2312,6 +2312,14 @@
|
||||
await _saveBlobAs(API.mediaUrl(mediaId), name, { types });
|
||||
}
|
||||
|
||||
// Source in-point for preview/export: chain segment offset + per-scene trim.
|
||||
function clipSourceInSec(sc, render) {
|
||||
if (!sc) return 0;
|
||||
const trim = sc.source_in || 0;
|
||||
if (render?.media) return trim + (render.inSec || 0);
|
||||
return trim;
|
||||
}
|
||||
|
||||
// Ordered list of rendered clips in timeline order: {media, inSec, durationSec} for
|
||||
// each non-excluded scene that has a render. This is what plays/exports — so splits
|
||||
// and deletes are honoured (deleted scenes simply aren't here).
|
||||
@@ -2324,7 +2332,7 @@
|
||||
const fps = (sc.fps_mode !== "project" && sc.fps != null ? sc.fps : p.frame_rate) || 25;
|
||||
const tFrames = sc.transition_frames || 0;
|
||||
const base = {
|
||||
inSec: (r?.inSec || 0) + (sc.source_in || 0),
|
||||
inSec: clipSourceInSec(sc, r),
|
||||
durationSec: sc.source_dur != null ? sc.source_dur : sceneDurationSec(sc),
|
||||
fx: sc.effects || {}, fps,
|
||||
w: (sc.width != null ? sc.width : p.width) || null,
|
||||
@@ -2431,7 +2439,7 @@
|
||||
filename: r.media.filename,
|
||||
subfolder: r.media.subfolder || "",
|
||||
type: r.media.type || "output",
|
||||
in: (r.inSec || 0) + (sc.source_in || 0),
|
||||
in: clipSourceInSec(sc, r),
|
||||
dur: sc.source_dur != null ? sc.source_dur : sceneDurationSec(sc),
|
||||
},
|
||||
name: `${proj}_scene${idx >= 0 ? idx + 1 : "x"}_${_stamp()}.mp4`,
|
||||
@@ -2866,7 +2874,7 @@
|
||||
sceneCharacterIds, toggleSceneCharacter,
|
||||
genUnitId, isGenSubclip, genUnitRoot, genUnitSceneIds,
|
||||
renderPromptForScene, renderPromptMismatch, renderAnchorMismatch, renderMediaLabel, renderIsStale,
|
||||
buildPreviewSegments, previewTotalSec, segmentDurationSec, sceneDurationSec,
|
||||
buildPreviewSegments, previewTotalSec, segmentDurationSec, sceneDurationSec, clipSourceInSec,
|
||||
addAudioTrack, updateAudioTrack, removeAudioTrack, separateSceneAudio, separatedTrackForScene,
|
||||
separatedTrackMedia, separatedTrackInSec, separatedTrackDurSec,
|
||||
isOverlayAudioTrack, isSeparatedAudioTrack,
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
scenes: (p.scenes || []).map((s) => [
|
||||
s.id, s.excluded, s.frames, s.fps, s.frames_mode, s.fps_mode,
|
||||
s.audio_volume, s.audio_separated, s.source_in, s.source_dur, s.effects,
|
||||
s.source?.type, s.source?.media_ref,
|
||||
]),
|
||||
renders: st.sceneRenders,
|
||||
ghosts: st.sceneGhosts,
|
||||
|
||||
Reference in New Issue
Block a user