Commit Graph

104 Commits

Author SHA1 Message Date
JSLMPR 30c832e9d5 Accurate loudness mastering: measure the finished file and correct to target
Single-pass loudnorm in the mix is only ~+/-2 LUFS accurate, so the auto-rendered
output could land quiet (e.g. -18.7 LUFS vs the -16 target). After the mix,
probeIntegratedLoudness measures the file, loudnessGainDb computes the corrective
gain, and masterLoudness applies it with a brickwall limiter for true peak. No-ops
when already on target or when the measurement is implausible; handles MusicGen
loudness variance. loudnessGainDb unit-tested.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MPuJXQyAeWpFcTtcnxo1UN
2026-07-23 23:09:06 +02:00
JSLMPR 1da0661eea Automatic two-tier highlight director + source-adaptive rendering
Rendering (whole service, driven by source measurements, not constants):
- Orientation-aware geometry: FfmpegClipInspector reads display rotation and
  stores effective dims; HighlightFfmpegRenderer.outputGeometry renders portrait
  sources portrait and skips the 2.39 letterbox on portrait (landscape unchanged).
- Dynamic exposure: probeSourceLuma measures the frames; exposureNormalizationFilter
  maps the mean toward a target; the grade is now exposure-preserving (no crushed
  subjects: bowling final went ~63 -> ~100 mean luma).
- Motion-adaptive in-shot push-in (zoompan), amount from per-shot YDIF.
- Audio mix ducks source audio under the generated score so it leads.
- Highlight duration is no longer capped (validator + config).

Automatic director (plans were hand-authored before):
- Tier 1 HighlightMontageDirector: composes the montage from measured motion (YDIF)
  and audio-energy (RMS) curves -- setup, continuous action/tension, slow-mo payoff
  on the audio climax, resolution button, camera-whip tail trimmed.
- Tier 2 HighlightVisionDirector + tools/vision_caption.py: a local, offline
  vision-language model (moondream2) captions the payoff frame and augments the
  montage with a semantic overlay ("STRIKE") and scene-informed music; fails soft.
- Wired into the scheduler behind auto-director-enabled / vision-director-enabled
  (on in the localpoc profile).

Docs: cinematic-quality-rules.md (R1-R5, R9 both tiers), poc-plan milestones.
Tests: mvn -o verify -> 262 passing, 0 failures.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MPuJXQyAeWpFcTtcnxo1UN
2026-07-23 22:49:05 +02:00
JSLMPR b3718dd0b8 Add cinematic montage mode (break free of the 8-35s highlight windows)
A montage edits many short shots pulled from ANYWHERE in the source (not a few
fixed contiguous highlight windows), sequenced establishing -> quick detail cuts ->
slow-motion hero, over one continuous music bed -- much closer to how a car film is
actually cut.

- MontagePlan model + director/montage.json shot list (per-shot source time,
  duration, punch-in zoom, speed).
- HighlightDirectorFlowService.processMontage: builds one EditPlan from the shot
  list (bypassing the highlight-window validator), one continuous music cue,
  distributed voiceover, and titles; reuses asset prep + worker + renderer.
- Renderer: explicit per-shot framing via a "zoom=" token (falls back to the
  progressive punch-in); pin each segment to its exact target duration with -t so
  frame-quantization drift cannot accumulate across many short shots.

Verified on the DJI source: 18 shots, 16.7 s, -16.5 LUFS, TP -2.8 dBTP, QA green.
The edit now reads as a real montage (varied framing + detail cuts + hero) rather
than slow pans. mvn -o verify green (248). Remaining ceiling is the source footage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bg76sLc43Wc3j5ZcLkboYR
2026-07-22 22:35:08 +02:00
JSLMPR daa58a8c8d Dynamic multi-cut edit: tighter framing + progressive punch-in per beat
Turn each beat from one long pan into an edit:
- Flow splits every beat into contiguous cuts (opening 2, rising 3, hero 2) with
  hard cuts between and sequential timeline positions; playback speed is preserved
  so the hero stays slow-motion across its cuts.
- Renderer frames each cut with a tighter center crop that fills the frame and
  hides the mundane location, plus a progressive punch-in (each successive cut of a
  beat steps tighter), so the sequence reads as deliberate.
- Widen the duration QA tolerance to the frozen acceptance value (0.25 s): multi-cut
  and slow-motion accumulate small per-segment frame-quantization drift.

Verified: 7 cuts (2/3/2), final 27.4 s, TP -2.7 dBTP. mvn -o verify green (248).
Known follow-up: integrated loudness runs low (~-18.7 LUFS) on the sparse music-bed
mix; single-pass loudnorm undershoots -- needs two-pass or a louder bed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bg76sLc43Wc3j5ZcLkboYR
2026-07-22 19:05:16 +02:00
JSLMPR d3d2a1b14e Soften voiceover entry/exit with short fades
Add afade in (0.12s) / out (0.25s) to each narration line so it eases in and out
instead of hard-cutting -- the hard cut read as un-cinematic. Voice remains
present and leading (measured onset ramp -18 -> -17 dB).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bg76sLc43Wc3j5ZcLkboYR
2026-07-22 18:19:27 +02:00
JSLMPR aae92ed7a5 Fix: voiceover was silently dropped from every mix; remove SFX gating
Root cause of "no voiceover": in audioMixCommand the [voice] label was used both
as the sidechaincompress key AND as an amix input. FFmpeg does NOT auto-split a
reused label, so the ducking sidechain consumed the voice entirely and the amix
reference got no audio -- the narration never made it into any final mix (every
render played ducked music with a silent hole where the voice should be).

Fix: explicitly `asplit=2[voice_key][voice_mix]` so one copy keys the duck and one
copy stays in the mix. Measured: voice window went from ~-30..-53 dB (silent) to
~-16 dB (present, leading the bed). Revert the compensating +8 dB over-boost back
to unity; music bed lowered to -14 dB so narration leads cleanly.

Also make SFX direction OPTIONAL in the validator (matching the earlier
voiceover-optional change) so a clean music+narration edit with no sound effects
validates. Regression test added for the asplit. mvn -o verify green (248 tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bg76sLc43Wc3j5ZcLkboYR
2026-07-22 18:03:38 +02:00
JSLMPR 842f2a7404 Cinematic pass: 2.39 letterbox, film grain, optional voiceover
Push the highlight output toward a genuinely cinematic look after a human review
found it functional-but-not-cinematic:

- HighlightFfmpegRenderer: add a 2.39:1 letterbox and subtle film grain to each
  graded segment; raise overlay placement above the letterbox bar. (A time-based
  crop-zoom push-in was prototyped and removed: FFmpeg crop cannot use the `t`
  variable for width/height; a zoompan push-in is a possible follow-up.)
- HighlightDirectorPlanValidator: make voiceover OPTIONAL so a music-driven edit
  can carry no narration (lines still validated when present).

Combined with a no-voiceover, driving-orchestral, slow-motion-hero director plan,
this yields a letterboxed, richly graded, music-led cinematic cut. mvn -o verify
green (247 tests, 0 failures).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bg76sLc43Wc3j5ZcLkboYR
2026-07-22 16:13:19 +02:00
JSLMPR 56205d91f2 Fix local CV visual-analysis client (HTTP/1.1) to enable YOLO selection
The local-cv provider was never exercised end to end (its bootstrap was
prohibited), and hid a latent bug: the JDK HttpClient defaulted to HTTP/2 and
negotiated an h2c cleartext upgrade that the HTTP/1.1-only worker (uvicorn/h11)
mishandled by dropping the request body, so every call returned HTTP 422. Pin the
client to HTTP/1.1.

With this fix the resident YOLOv8 worker (run offline against the existing
yolov8n.pt, no bootstrap script) classifies the sample source as CAR_VLOG at 0.95
with measured OpenCV blur/exposure and a real car label, replacing the previous
filename-keyword GENERIC_VLOG fallback. Provider remains opt-in via runtime
override; the committed localpoc profile keeps the heuristic default.

Also ignore yolov*.pt.license.txt (provenance for the git-ignored weights).
mvn -o verify green (247 tests, 0 failures).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bg76sLc43Wc3j5ZcLkboYR
2026-07-22 11:14:48 +02:00
JSLMPR a0b6023b9c Beat-specific cinematic grading for highlights
The highlight renderer now selects a filmic grade per story beat, read from the
EditPlan style key (safeKey: style_<category>_<storyPurpose>), so no change to the
shared EditDecision or its serialization is needed:

- opening_hook: calmer, cooler, softer contrast (linear_contrast, gentle vignette)
- rising_energy / default: balanced base grade (medium_contrast)
- hero_payoff: richest, warmer, stronger S-curve and deeper vignette (strong_contrast)

Threads plan.style() into segmentCommand -> cinematicVisualFilter. Multi-clip
FfmpegEditRenderer untouched. Test added; mvn -o verify green (247 tests, 0 failures).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bg76sLc43Wc3j5ZcLkboYR
2026-07-22 10:19:52 +02:00
JSLMPR 24bd1d78f2 Premium highlight overlay styling (P3.3)
Replace the plain hard-cut white caption with a refined 48px caption, a soft drop
shadow, a thin subtle border, and a smooth alpha fade in and out (0.4s ramps)
within each overlay timeline window. Highlight renderer only; the multi-clip
renderer and overlay placement/safe-area logic are unchanged. Test added;
mvn -o verify green (246 tests, 0 failures).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bg76sLc43Wc3j5ZcLkboYR
2026-07-22 09:52:12 +02:00
JSLMPR 0fcfca9283 Improve highlight render: filmic grade + true-peak limiter
Phase 3 quality fixes for the highlight renderer (multi-clip FfmpegEditRenderer
left untouched):

- cinematicVisualFilter: replace the weak fixed eq with a deliberate filmic grade
  (curves medium_contrast S-curve + teal-orange colorbalance + eq + unsharp +
  vignette). Richer blue, warm highlights, tonal contrast. Still one uniform look;
  beat/category-specific grading is future work (needs a validated grade enum).
- audio mix: add a brickwall limiter (alimiter limit=0.72) after loudnorm. The
  first render clipped at 0.0 dBFS true peak; measured re-render now lands
  -1.7/-2.7/-2.8 dBFS per highlight (all within the -1.5 dBTP gate), integrated
  loudness -16.3 LUFS.

Test updated; mvn -o verify green (245 tests, 0 failures).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bg76sLc43Wc3j5ZcLkboYR
2026-07-22 09:38:47 +02:00
JSLMPR 588c652a2f Add opt-in localpoc profile for the local highlight PoC
Activated with --spring.profiles.active=localpoc. Points only at pre-provisioned
local model paths (Piper voice, MusicGen, AudioLDM2), disables bootstrap
auto-start, uses heuristic visual analysis, isolates PoC input/output dirs, and
keeps render disabled + director approval required. Base/production defaults are
untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bg76sLc43Wc3j5ZcLkboYR
2026-07-22 09:38:47 +02:00
JSLMPR f6dc6b8a83 Harden cinematic highlight planning and rendering
- require explicit approval and skip ineligible highlight projects
  - validate timing and deduplicate candidate ranges
  - enforce licensed local assets and fail-closed generation
  - preserve video duration when mixing generated audio
  - refresh skill runbooks and regression coverage
2026-07-21 18:32:35 +02:00
JSLMPR 97ba827d50 add asset generation 2026-07-21 10:03:27 +02:00
JSLMPR 618ba9af49 - Implement end-to-end cinematic highlight rendering pipeline
- Wire visual effects and local asset generation into highlight flow
  - Add director plan rendering with local asset worker
2026-07-12 01:20:18 +02:00
JSLMPR adc979eea8 Add local CV worker readiness checks 2026-07-11 17:46:40 +02:00
JSLMPR 8195b58552 Add rich video editing diagnostics 2026-07-11 17:11:35 +02:00
JSLMPR e2f49e2e5a Add managed local CV worker startup 2026-07-11 16:50:54 +02:00
JSLMPR 9dc720b0cc Add runnable local CV model worker 2026-07-11 16:40:59 +02:00
JSLMPR 82e557905e Add local CV visual analysis provider 2026-07-11 10:49:11 +02:00
JSLMPR eea619a2d3 Add highlight visual analysis 2026-07-11 10:35:07 +02:00
JSLMPR fc17578549 Add highlight audio analysis 2026-07-11 10:23:07 +02:00
JSLMPR 5d5f8022f2 Add highlight scene segmentation 2026-07-11 10:16:07 +02:00
JSLMPR ed337c1268 Add highlight source analysis 2026-07-11 09:59:55 +02:00
JSLMPR 0b6e5afddf Add highlight source scheduler 2026-07-11 09:50:11 +02:00
JSLMPR 5ba108f740 Add highlight project folder contract 2026-07-11 09:42:55 +02:00
JSLMPR 9536928054 Add cinematic edit approval gate 2026-07-11 09:36:56 +02:00
JSLMPR 2dc3ec97f4 Add cinematic benchmark metrics 2026-07-11 09:28:13 +02:00
JSLMPR 72a0626ab7 Add cinematic category fixture integration tests 2026-07-11 01:29:23 +02:00
JSLMPR 9b56e89b4c Add cinematic render QA report 2026-07-11 01:25:38 +02:00
JSLMPR 2d0c331710 Add cinematic dynamic crop rendering 2026-07-11 01:20:39 +02:00
JSLMPR bb23ac80e1 Add cinematic audio mastering filters 2026-07-11 01:16:14 +02:00
JSLMPR 43fccb7dc6 Render cinematic text overlays 2026-07-11 01:06:38 +02:00
JSLMPR 376bc41685 Add local cinematic asset library 2026-07-11 01:02:38 +02:00
JSLMPR e3d69ad209 Add cinematic edit asset provider interfaces 2026-07-11 00:59:04 +02:00
JSLMPR 3348ae8e5d Validate cinematic edit plans 2026-07-11 00:54:52 +02:00
JSLMPR 5006dfd50b Add category-aware cinematic highlight planning 2026-07-11 00:50:12 +02:00
JSLMPR 5d889b00dc • working version but not cinematic 2026-07-11 00:32:46 +02:00
JSLMPR 13b7dc4cdf Complete cinematic editing implementation plan 2026-07-10 19:10:34 +02:00
JSLMPR e5a86257d1 Document local AI director workflow 2026-07-10 19:05:19 +02:00
JSLMPR 051f4e56d0 Add cinematic editing integration test 2026-07-10 19:00:40 +02:00
JSLMPR 8fc85320e9 Add cinematic edit observability 2026-07-10 18:58:57 +02:00
JSLMPR c3904b75c2 Add voiceover generation hook 2026-07-10 18:53:34 +02:00
JSLMPR 1c3db181a3 Add edit sound effect cues 2026-07-10 18:47:18 +02:00
JSLMPR e2037a7629 Add basic edit transitions 2026-07-10 16:19:05 +02:00
JSLMPR c3c6c7a790 Add edit render manifest 2026-07-10 16:16:13 +02:00
JSLMPR a3ca4826f5 Add edit audio mixing 2026-07-10 16:15:09 +02:00
JSLMPR 46a4982ef9 Add concat edit timeline rendering 2026-07-10 16:13:59 +02:00
JSLMPR 21e5cef45d Add normalized edit segment rendering 2026-07-10 16:08:08 +02:00
JSLMPR 2b4c5992a6 Add edit plan API 2026-07-10 16:00:49 +02:00