fix(render): dim and cheaply blur the vertical backdrop

The blurred backdrop behind fitted landscape footage enlarged burned captions
into a readable ghost line. Blur at 1/8 size (harder blur, far less CPU than a
full-resolution gblur) and dim it to about 35% so source text no longer reads
in the backdrop. Shared by legacy export and speaker framing.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
周小舟
2026-09-30 21:03:30 +08:00
co-authored by Claude Opus 5.5
parent fda1a5751c
commit 5737a6db02
2 changed files with 15 additions and 3 deletions
+12 -1
View File
@@ -138,13 +138,24 @@ def _load_srt_entries(project_id: str) -> List[Dict[str, Any]]:
# ---------------------------------------------------------------- ffmpeg ---
def blurred_backdrop(w: int, h: int) -> str:
"""Filter chain (no labels) turning the source into a dim, heavily blurred full-canvas backdrop.
Blurring at 1/8 size is far cheaper than a full-resolution gblur and blurs harder; dimming to
~35% keeps text in the source (burned captions, lower thirds) from reading as a ghost copy.
"""
sw, sh = max(2, w // 8 // 2 * 2), max(2, h // 8 // 2 * 2)
return (f"scale={sw}:{sh}:force_original_aspect_ratio=increase,crop={sw}:{sh},gblur=sigma=6,"
f"colorlevels=romax=0.35:gomax=0.35:bomax=0.35,scale={w}:{h}")
def _layout_filters(layout: str, w: Optional[int], h: Optional[int]) -> List[str]:
if layout == "none" or not w or not h:
return []
if layout == "blur":
return [
f"[0:v]split=2[bg][fg]",
f"[bg]scale={w}:{h}:force_original_aspect_ratio=increase,crop={w}:{h},gblur=sigma=24[bg2]",
f"[bg]{blurred_backdrop(w, h)}[bg2]",
f"[fg]scale={w}:-2[fg2]",
f"[bg2][fg2]overlay=(W-w)/2:(H-h)/2[base]",
]
+3 -2
View File
@@ -185,8 +185,9 @@ def fit_spans(scene: Scene) -> list[tuple[float, float]]:
return spans
def layout_filter(scene: Scene, fallback: float, w: int, h: int, blur: int = 24) -> str:
def layout_filter(scene: Scene, fallback: float, w: int, h: int) -> str:
"""The `[0:v]…[base]` chain for a cropped scene, switching to a blurred fit on `fit` shots."""
from backend.services.publish_export import blurred_backdrop
cropped = (f"scale={w}:{h}:force_original_aspect_ratio=increase,"
f"crop={w}:{h}:x='(iw-ow)*{crop_expression(scene, fallback)}':y=(ih-oh)/2,setsar=1")
spans = fit_spans(scene)
@@ -194,7 +195,7 @@ def layout_filter(scene: Scene, fallback: float, w: int, h: int, blur: int = 24)
return f"[0:v]{cropped}[base]"
enable = "+".join(f"between(t,{start},{end})" for start, end in spans)
return (f"[0:v]split=3[c][bg][fg];[c]{cropped}[cropped];"
f"[bg]scale={w}:{h}:force_original_aspect_ratio=increase,crop={w}:{h},gblur=sigma={blur}[bg2];"
f"[bg]{blurred_backdrop(w, h)}[bg2];"
f"[fg]scale={w}:{h}:force_original_aspect_ratio=decrease[fg2];"
f"[bg2][fg2]overlay=(W-w)/2:(H-h)/2[fitted];"
f"[cropped][fitted]overlay=0:0:enable='{enable}'[base]")