forked from jsl/video_editing_poc
fix(render): loop a bounded music bed so long reels render (MusicGen CPU cap)
A multi-segment reel needs music as long as the reel, but MusicGen-small stalls on CPU past ~45s (confirmed on the 49s downhill/soccer reels). Decouple music-generation length from reel length: generate a bounded bed (music-gen-max-seconds, default 15s) and loop it across the timeline (-stream_loop -1 on the music input; the existing atrim bounds it to the cue). Reel length stays uncapped; music generation stays feasible. Verified: 7-segment 45s downhill reel now renders (14.9s bed looped, 1080x1920/24fps/yuv420p/-15.6 LUFS). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
5b98c0538f
commit
e6a7aecd97
|
|
@ -545,6 +545,13 @@ public class VideoClippingProperties {
|
|||
/** R12 cinematic motion blur (light frame blend) in styled shots. Emulates shutter-angle blur. */
|
||||
private boolean cinematicMotionBlur = true;
|
||||
|
||||
/**
|
||||
* Max seconds of music to GENERATE. Local MusicGen can't reliably produce long scores on CPU (it stalls
|
||||
* ~45s+), so a longer reel generates a bounded bed and the renderer loops it to fill the timeline. This
|
||||
* decouples reel length from music-generation feasibility — the reel itself stays uncapped.
|
||||
*/
|
||||
private double musicGenMaxSeconds = 15.0;
|
||||
|
||||
/** R13 snap montage cut boundaries onto the generated score's beat grid (cut-to-the-music). */
|
||||
private boolean beatSyncEnabled = false;
|
||||
|
||||
|
|
@ -787,6 +794,14 @@ public class VideoClippingProperties {
|
|||
this.cinematicMotionBlur = cinematicMotionBlur;
|
||||
}
|
||||
|
||||
public double getMusicGenMaxSeconds() {
|
||||
return musicGenMaxSeconds;
|
||||
}
|
||||
|
||||
public void setMusicGenMaxSeconds(double musicGenMaxSeconds) {
|
||||
this.musicGenMaxSeconds = musicGenMaxSeconds;
|
||||
}
|
||||
|
||||
public boolean isBeatSyncEnabled() {
|
||||
return beatSyncEnabled;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ public class HighlightAssetPreparationService {
|
|||
private final EditAssetProvider assetProvider;
|
||||
private final EditAssetLibrary assetLibrary;
|
||||
private final VideoClippingProperties.Editing.Assets assets;
|
||||
private final double musicGenMaxSeconds;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public HighlightAssetPreparationService(VideoClippingProperties properties, HighlightProjectStore store,
|
||||
|
|
@ -35,6 +36,7 @@ public class HighlightAssetPreparationService {
|
|||
this.assetProvider = assetProvider;
|
||||
this.assetLibrary = assetLibrary;
|
||||
this.assets = properties.getEditing().getAssets();
|
||||
this.musicGenMaxSeconds = properties.getEditing().getMusicGenMaxSeconds();
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
|
|
@ -61,9 +63,12 @@ public class HighlightAssetPreparationService {
|
|||
copy(Path.of(music.get().path()), target);
|
||||
resolvedAssets.add(target.toString());
|
||||
} else {
|
||||
// Generate a BOUNDED music bed (MusicGen stalls on long scores); the renderer loops it to fill the
|
||||
// reel. The reel length itself is unaffected.
|
||||
double musicSeconds = Math.min(highlight.targetDurationSeconds(), musicGenMaxSeconds);
|
||||
requestFiles.add(writeRequest(requestDirectory, projectId, highlight.highlightId(), "music",
|
||||
"music_bed", highlight.musicDirection(), musicDirectory.resolve("music.wav"),
|
||||
highlight.targetDurationSeconds(), false));
|
||||
musicSeconds, false));
|
||||
}
|
||||
|
||||
if (!highlight.voiceover().isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -631,7 +631,9 @@ public class HighlightFfmpegRenderer {
|
|||
}
|
||||
}
|
||||
if (music != null) {
|
||||
command.addAll(List.of("-i", music.toString()));
|
||||
// Loop the (bounded) generated bed so it fills the whole reel; the atrim below bounds it to the cue.
|
||||
// Lets a long reel use a short, feasible-to-generate score instead of one impractically-long score.
|
||||
command.addAll(List.of("-stream_loop", "-1", "-i", music.toString()));
|
||||
filters.append("[").append(input).append(":a]");
|
||||
if (musicCue != null) {
|
||||
double duration = musicCue.timelineEndSeconds() - musicCue.timelineStartSeconds();
|
||||
|
|
|
|||
Loading…
Reference in New Issue