import type { BuiltInExportPreset } from './preset.types'; function immutable(preset: T): Readonly { 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, }), ]);