202 lines
5.8 KiB
TypeScript
202 lines
5.8 KiB
TypeScript
import type { BuiltInExportPreset } from './preset.types';
|
|
|
|
function immutable<T extends BuiltInExportPreset>(preset: T): Readonly<T> {
|
|
return Object.freeze({
|
|
...preset,
|
|
requirements: Object.freeze({
|
|
...preset.requirements,
|
|
...(preset.requirements.muxers
|
|
? { muxers: Object.freeze([...preset.requirements.muxers]) }
|
|
: {}),
|
|
...(preset.requirements.encoders
|
|
? { encoders: Object.freeze([...preset.requirements.encoders]) }
|
|
: {}),
|
|
...(preset.requirements.filters
|
|
? { filters: Object.freeze([...preset.requirements.filters]) }
|
|
: {}),
|
|
}),
|
|
...(preset.video ? { video: Object.freeze({ ...preset.video }) } : {}),
|
|
...(preset.audio ? { audio: Object.freeze({ ...preset.audio }) } : {}),
|
|
settingsSummary: Object.freeze([...preset.settingsSummary]),
|
|
});
|
|
}
|
|
|
|
export const VIDEO_PRESETS: readonly BuiltInExportPreset[] = Object.freeze([
|
|
immutable({
|
|
id: 'mp4-h264-balanced',
|
|
name: 'MP4 · H.264 + AAC',
|
|
description: 'Balanced browser-friendly video.',
|
|
kind: 'video',
|
|
container: 'mp4',
|
|
fileExtension: 'mp4',
|
|
video: {
|
|
codec: 'libx264',
|
|
qualityMode: 'balanced',
|
|
crf: 23,
|
|
pixelFormat: 'yuv420p',
|
|
encoderPreset: 'medium',
|
|
},
|
|
audio: { codec: 'aac', bitrateKbps: 160, sampleRate: 48_000, channels: 2 },
|
|
fastStart: true,
|
|
metadataPolicy: 'copy',
|
|
chapterPolicy: 'keep',
|
|
subtitlePolicy: 'convert',
|
|
requirements: {
|
|
muxers: ['mp4'],
|
|
encoders: ['libx264', 'aac'],
|
|
},
|
|
settingsSummary: [
|
|
'libx264 CRF 23, medium preset',
|
|
'yuv420p pixel format',
|
|
'AAC 160 kbit/s stereo at 48 kHz',
|
|
'fast-start metadata',
|
|
],
|
|
builtIn: true,
|
|
}),
|
|
immutable({
|
|
id: 'mp4-h264-compatibility',
|
|
name: 'MP4 · H.264 compatibility',
|
|
description: 'Conservative settings for broad playback support.',
|
|
kind: 'video',
|
|
container: 'mp4',
|
|
fileExtension: 'mp4',
|
|
video: {
|
|
codec: 'libx264',
|
|
qualityMode: 'compatibility',
|
|
crf: 24,
|
|
pixelFormat: 'yuv420p',
|
|
encoderPreset: 'fast',
|
|
},
|
|
audio: { codec: 'aac', bitrateKbps: 128, sampleRate: 44_100, channels: 2 },
|
|
fastStart: true,
|
|
metadataPolicy: 'copy',
|
|
chapterPolicy: 'keep',
|
|
subtitlePolicy: 'convert',
|
|
requirements: { muxers: ['mp4'], encoders: ['libx264', 'aac'] },
|
|
settingsSummary: [
|
|
'libx264 CRF 24, fast preset',
|
|
'yuv420p pixel format',
|
|
'AAC 128 kbit/s stereo at 44.1 kHz',
|
|
],
|
|
builtIn: true,
|
|
}),
|
|
immutable({
|
|
id: 'webm-vp9-opus',
|
|
name: 'WebM · VP9 + Opus',
|
|
description: 'Efficient open web video when both encoders are available.',
|
|
kind: 'video',
|
|
container: 'webm',
|
|
fileExtension: 'webm',
|
|
video: {
|
|
codec: 'libvpx-vp9',
|
|
qualityMode: 'smaller-file',
|
|
crf: 32,
|
|
bitrateKbps: 0,
|
|
pixelFormat: 'yuv420p',
|
|
},
|
|
audio: {
|
|
codec: 'libopus',
|
|
bitrateKbps: 128,
|
|
sampleRate: 48_000,
|
|
channels: 2,
|
|
},
|
|
metadataPolicy: 'copy',
|
|
chapterPolicy: 'keep',
|
|
subtitlePolicy: 'convert',
|
|
requirements: {
|
|
muxers: ['webm'],
|
|
encoders: ['libvpx-vp9', 'libopus'],
|
|
},
|
|
settingsSummary: ['libvpx-vp9 CRF 32', 'Opus 128 kbit/s stereo at 48 kHz'],
|
|
builtIn: true,
|
|
}),
|
|
immutable({
|
|
id: 'webm-vp8-vorbis',
|
|
name: 'WebM · VP8 + Vorbis',
|
|
description: 'Compatibility-oriented open web video.',
|
|
kind: 'video',
|
|
container: 'webm',
|
|
fileExtension: 'webm',
|
|
video: {
|
|
codec: 'libvpx',
|
|
qualityMode: 'compatibility',
|
|
crf: 18,
|
|
bitrateKbps: 1_500,
|
|
pixelFormat: 'yuv420p',
|
|
},
|
|
audio: {
|
|
codec: 'libvorbis',
|
|
bitrateKbps: 128,
|
|
sampleRate: 48_000,
|
|
channels: 2,
|
|
},
|
|
metadataPolicy: 'copy',
|
|
chapterPolicy: 'keep',
|
|
subtitlePolicy: 'convert',
|
|
requirements: { muxers: ['webm'], encoders: ['libvpx', 'libvorbis'] },
|
|
settingsSummary: ['libvpx CRF 18, 1.5 Mbit/s target', 'Vorbis 128 kbit/s'],
|
|
builtIn: true,
|
|
}),
|
|
immutable({
|
|
id: 'animated-webp',
|
|
name: 'Animated WebP',
|
|
description: 'Animated image derivative without audio.',
|
|
kind: 'derivative',
|
|
container: 'webp',
|
|
fileExtension: 'webp',
|
|
video: {
|
|
codec: 'libwebp_anim',
|
|
qualityMode: 'balanced',
|
|
crf: 60,
|
|
pixelFormat: 'rgba',
|
|
},
|
|
metadataPolicy: 'remove',
|
|
chapterPolicy: 'remove',
|
|
subtitlePolicy: 'none',
|
|
requirements: { muxers: ['webp'], encoders: ['libwebp_anim'] },
|
|
settingsSummary: ['libwebp_anim quality 60', 'audio omitted'],
|
|
builtIn: true,
|
|
}),
|
|
immutable({
|
|
id: 'animated-gif',
|
|
name: 'Animated GIF',
|
|
description: 'Advanced compatibility derivative with limited colours.',
|
|
kind: 'derivative',
|
|
container: 'gif',
|
|
fileExtension: 'gif',
|
|
video: { codec: 'gif', qualityMode: 'compatibility' },
|
|
metadataPolicy: 'remove',
|
|
chapterPolicy: 'remove',
|
|
subtitlePolicy: 'none',
|
|
requirements: {
|
|
muxers: ['gif'],
|
|
encoders: ['gif'],
|
|
filters: ['palettegen', 'paletteuse'],
|
|
},
|
|
settingsSummary: ['palettegen/paletteuse filter workflow', 'audio omitted'],
|
|
builtIn: true,
|
|
}),
|
|
immutable({
|
|
id: 'matroska-h264-aac',
|
|
name: 'Matroska · H.264 + AAC',
|
|
description: 'Flexible Matroska output with selected compatible streams.',
|
|
kind: 'video',
|
|
container: 'matroska',
|
|
fileExtension: 'mkv',
|
|
video: {
|
|
codec: 'libx264',
|
|
qualityMode: 'higher-quality',
|
|
crf: 20,
|
|
pixelFormat: 'yuv420p',
|
|
encoderPreset: 'medium',
|
|
},
|
|
audio: { codec: 'aac', bitrateKbps: 192, sampleRate: 48_000, channels: 2 },
|
|
metadataPolicy: 'copy',
|
|
chapterPolicy: 'keep',
|
|
subtitlePolicy: 'copy-compatible',
|
|
requirements: { muxers: ['matroska'], encoders: ['libx264', 'aac'] },
|
|
settingsSummary: ['libx264 CRF 20', 'AAC 192 kbit/s', 'Matroska container'],
|
|
builtIn: true,
|
|
}),
|
|
]);
|