Make layout blur, opacity, and watermark position apply in rendered videos.
Still-image encodes ignored boxblur and 1s black fills; switch to gblur plus full-length black frames, and honor brand watermark position.
This commit is contained in:
+19
-10
@@ -64,7 +64,7 @@ export type LayoutSettings = {
|
||||
* Ignored when `template` is set (art-track always uses a blur fill).
|
||||
*/
|
||||
blurFill: boolean;
|
||||
/** 0–100 → FFmpeg boxblur intensity. */
|
||||
/** 0-100 - FFmpeg gblur intensity. */
|
||||
blurAmount: number;
|
||||
/** 0–100 → how visible the blurred fill is (vs black). */
|
||||
blurOpacity: number;
|
||||
@@ -134,12 +134,21 @@ export function blurToBoxblur(blurAmount: number): { radius: number; power: numb
|
||||
return { radius, power };
|
||||
}
|
||||
|
||||
/**
|
||||
* Still-image cover inputs (-loop 1 -r 1) respond poorly to boxblur; gblur is
|
||||
* reliable and maps 0-100 to a visible sigma range.
|
||||
*/
|
||||
export function boxblurFilterSegment(blurAmount: number): string {
|
||||
const bb = blurToBoxblur(blurAmount);
|
||||
if (!bb) return "";
|
||||
return `boxblur=luma_radius=${bb.radius}:luma_power=${bb.power}:chroma_radius=${bb.radius}:chroma_power=${bb.power}`;
|
||||
const amount = clampBlurAmount(blurAmount, 0);
|
||||
if (amount <= 0) return "";
|
||||
const sigma = Math.max(0.8, (amount / 100) * 24);
|
||||
return `gblur=sigma=${sigma.toFixed(2)}`;
|
||||
}
|
||||
|
||||
/** Solid black used when fading blur opacity; must outlast any track length. */
|
||||
const BLACK_FRAME = (width: number, height: number, label: string) =>
|
||||
`color=c=black:s=${width}x${height}:d=86400[${label}]`;
|
||||
|
||||
type RawLayoutInput = {
|
||||
template?: unknown;
|
||||
layoutTemplate?: unknown;
|
||||
@@ -516,14 +525,14 @@ export function buildArtTrackFilterComplex(opts: {
|
||||
if (opacity >= 0.999) {
|
||||
parts.push(`${bgSrc}${bgChain}[blurred]`);
|
||||
} else if (opacity <= 0.001) {
|
||||
parts.push(`color=c=black:s=${W}x${H}:d=1[blurred]`);
|
||||
parts.push(BLACK_FRAME(W, H, "blurred"));
|
||||
} else {
|
||||
const a = opacity.toFixed(3);
|
||||
const b = (1 - opacity).toFixed(3);
|
||||
parts.push(
|
||||
`${bgSrc}${bgChain}[blur_raw]`,
|
||||
`color=c=black:s=${W}x${H}:d=1[blk]`,
|
||||
`[blur_raw][blk]blend=all_expr='A*${a}+B*${b}':shortest=1[blurred]`,
|
||||
BLACK_FRAME(W, H, "blk"),
|
||||
`[blur_raw][blk]blend=all_expr='A*${a}+B*${b}'[blurred]`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -560,14 +569,14 @@ export function buildClassicBlurFillFilterComplex(opts: {
|
||||
if (opacity >= 0.999) {
|
||||
parts.push(`[bg]${bgChain}[blurred]`);
|
||||
} else if (opacity <= 0.001) {
|
||||
parts.push(`color=c=black:s=${W}x${H}:d=1[blurred]`);
|
||||
parts.push(BLACK_FRAME(W, H, "blurred"));
|
||||
} else {
|
||||
const a = opacity.toFixed(3);
|
||||
const b = (1 - opacity).toFixed(3);
|
||||
parts.push(
|
||||
`[bg]${bgChain}[blur_raw]`,
|
||||
`color=c=black:s=${W}x${H}:d=1[blk]`,
|
||||
`[blur_raw][blk]blend=all_expr='A*${a}+B*${b}':shortest=1[blurred]`,
|
||||
BLACK_FRAME(W, H, "blk"),
|
||||
`[blur_raw][blk]blend=all_expr='A*${a}+B*${b}'[blurred]`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user