106 lines
4.0 KiB
TypeScript
106 lines
4.0 KiB
TypeScript
export type VideoHdResolution = "1080P" | "2K" | "4K";
|
|
export type VideoHdInterpolationMode = "none" | "high-quality";
|
|
|
|
export type VideoHdResolutionConfig = {
|
|
width: number;
|
|
height: number;
|
|
baseCost: number;
|
|
interpolationExtraCost: number;
|
|
};
|
|
|
|
export type VideoCanvasVideoHdConfig = {
|
|
enabled: boolean;
|
|
model: string;
|
|
setupCost: number;
|
|
frameRates: number[];
|
|
slowMultipliers: number[];
|
|
resolutions: Record<VideoHdResolution, VideoHdResolutionConfig>;
|
|
};
|
|
|
|
export const defaultVideoCanvasVideoHdConfig: VideoCanvasVideoHdConfig = {
|
|
enabled: true,
|
|
model: "Topazlabs",
|
|
setupCost: 6,
|
|
frameRates: [24, 30, 60, 90, 120],
|
|
slowMultipliers: [1, 2, 3, 5],
|
|
resolutions: {
|
|
"1080P": { width: 1920, height: 1080, baseCost: 24, interpolationExtraCost: 12 },
|
|
"2K": { width: 2560, height: 1440, baseCost: 42, interpolationExtraCost: 24 },
|
|
"4K": { width: 3840, height: 2160, baseCost: 90, interpolationExtraCost: 48 },
|
|
},
|
|
};
|
|
|
|
function positiveInteger(value: unknown, fallback: number) {
|
|
const parsed = Math.round(Number(value));
|
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
}
|
|
|
|
function nonnegativeNumber(value: unknown, fallback: number) {
|
|
const parsed = Number(value);
|
|
return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
|
|
}
|
|
|
|
function numberList(value: unknown, fallback: number[]) {
|
|
if (!Array.isArray(value)) return fallback;
|
|
const normalized = Array.from(
|
|
new Set(value.map((item) => positiveInteger(item, 0)).filter((item) => item > 0)),
|
|
).sort((a, b) => a - b);
|
|
return normalized.length > 0 ? normalized : fallback;
|
|
}
|
|
|
|
export function normalizeVideoCanvasVideoHdConfig(value: unknown): VideoCanvasVideoHdConfig {
|
|
const candidate = value && typeof value === "object" ? value as Partial<VideoCanvasVideoHdConfig> : {};
|
|
const candidateResolutions =
|
|
candidate.resolutions && typeof candidate.resolutions === "object"
|
|
? candidate.resolutions as Partial<Record<VideoHdResolution, Partial<VideoHdResolutionConfig>>>
|
|
: {};
|
|
const resolutions = Object.fromEntries(
|
|
(Object.keys(defaultVideoCanvasVideoHdConfig.resolutions) as VideoHdResolution[]).map((key) => {
|
|
const fallback = defaultVideoCanvasVideoHdConfig.resolutions[key];
|
|
const item = candidateResolutions[key] || {};
|
|
return [key, {
|
|
width: positiveInteger(item.width, fallback.width),
|
|
height: positiveInteger(item.height, fallback.height),
|
|
baseCost: nonnegativeNumber(item.baseCost, fallback.baseCost),
|
|
interpolationExtraCost: nonnegativeNumber(
|
|
item.interpolationExtraCost,
|
|
fallback.interpolationExtraCost,
|
|
),
|
|
}];
|
|
}),
|
|
) as Record<VideoHdResolution, VideoHdResolutionConfig>;
|
|
|
|
return {
|
|
enabled: typeof candidate.enabled === "boolean" ? candidate.enabled : true,
|
|
model: String(candidate.model || defaultVideoCanvasVideoHdConfig.model).trim() || "Topazlabs",
|
|
setupCost: nonnegativeNumber(candidate.setupCost, defaultVideoCanvasVideoHdConfig.setupCost),
|
|
frameRates: numberList(candidate.frameRates, defaultVideoCanvasVideoHdConfig.frameRates),
|
|
slowMultipliers: numberList(
|
|
candidate.slowMultipliers,
|
|
defaultVideoCanvasVideoHdConfig.slowMultipliers,
|
|
),
|
|
resolutions,
|
|
};
|
|
}
|
|
|
|
export function getVideoHdCost(
|
|
config: VideoCanvasVideoHdConfig,
|
|
resolution: VideoHdResolution,
|
|
interpolationMode: VideoHdInterpolationMode,
|
|
slowMultiplier: number,
|
|
) {
|
|
const definition = config.resolutions[resolution];
|
|
const singleDurationCost = definition.baseCost +
|
|
(interpolationMode === "high-quality" ? definition.interpolationExtraCost : 0);
|
|
const multiplier = Math.max(1, positiveInteger(slowMultiplier, 1));
|
|
return Math.round(config.setupCost + (singleDurationCost - config.setupCost) * multiplier);
|
|
}
|
|
|
|
export function formatVideoHdFrameRate(frameRate: number) {
|
|
if (frameRate === 24 || frameRate === 30) return `标准(${frameRate}fps)`;
|
|
if (frameRate === 60) return "流畅(60fps)";
|
|
if (frameRate === 90) return "超流畅(90fps)";
|
|
if (frameRate === 120) return "极致流畅(120fps)";
|
|
return `${frameRate}fps`;
|
|
}
|