Files
convert-ui/lib/utils/formatMappings.ts
Sebastian Krüger 1d9f10fd32 fix: optimize FFmpeg encoding to reduce memory usage
- Switch from VP9 to VP8 codec for WebM (less memory-intensive)
- Add realtime encoding deadline and fast CPU preset
- Add ultrafast preset for x264 encoding
- Set explicit bitrates to control memory usage
- Use libvorbis instead of libopus for better compatibility

This fixes "memory access out of bounds" errors during video conversion
in browser environments with limited WASM memory.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 10:54:03 +01:00

320 lines
6.9 KiB
TypeScript

import type { ConversionFormat, FormatPreset } from '@/types/conversion';
/**
* All supported conversion formats
*/
export const SUPPORTED_FORMATS: ConversionFormat[] = [
// Video formats (FFmpeg)
{
id: 'mp4',
name: 'MP4',
extension: 'mp4',
mimeType: 'video/mp4',
category: 'video',
converter: 'ffmpeg',
description: 'MPEG-4 video format',
},
{
id: 'webm',
name: 'WebM',
extension: 'webm',
mimeType: 'video/webm',
category: 'video',
converter: 'ffmpeg',
description: 'WebM video format',
},
{
id: 'avi',
name: 'AVI',
extension: 'avi',
mimeType: 'video/x-msvideo',
category: 'video',
converter: 'ffmpeg',
description: 'Audio Video Interleave',
},
{
id: 'mov',
name: 'MOV',
extension: 'mov',
mimeType: 'video/quicktime',
category: 'video',
converter: 'ffmpeg',
description: 'QuickTime movie',
},
{
id: 'mkv',
name: 'MKV',
extension: 'mkv',
mimeType: 'video/x-matroska',
category: 'video',
converter: 'ffmpeg',
description: 'Matroska video',
},
// Audio formats (FFmpeg)
{
id: 'mp3',
name: 'MP3',
extension: 'mp3',
mimeType: 'audio/mpeg',
category: 'audio',
converter: 'ffmpeg',
description: 'MPEG audio layer 3',
},
{
id: 'wav',
name: 'WAV',
extension: 'wav',
mimeType: 'audio/wav',
category: 'audio',
converter: 'ffmpeg',
description: 'Waveform audio',
},
{
id: 'ogg',
name: 'OGG',
extension: 'ogg',
mimeType: 'audio/ogg',
category: 'audio',
converter: 'ffmpeg',
description: 'Ogg Vorbis audio',
},
{
id: 'aac',
name: 'AAC',
extension: 'aac',
mimeType: 'audio/aac',
category: 'audio',
converter: 'ffmpeg',
description: 'Advanced Audio Coding',
},
{
id: 'flac',
name: 'FLAC',
extension: 'flac',
mimeType: 'audio/flac',
category: 'audio',
converter: 'ffmpeg',
description: 'Free Lossless Audio Codec',
},
// Image formats (ImageMagick)
{
id: 'png',
name: 'PNG',
extension: 'png',
mimeType: 'image/png',
category: 'image',
converter: 'imagemagick',
description: 'Portable Network Graphics',
},
{
id: 'jpg',
name: 'JPG',
extension: 'jpg',
mimeType: 'image/jpeg',
category: 'image',
converter: 'imagemagick',
description: 'JPEG image',
},
{
id: 'webp',
name: 'WebP',
extension: 'webp',
mimeType: 'image/webp',
category: 'image',
converter: 'imagemagick',
description: 'WebP image format',
},
{
id: 'gif',
name: 'GIF',
extension: 'gif',
mimeType: 'image/gif',
category: 'image',
converter: 'imagemagick',
description: 'Graphics Interchange Format',
},
{
id: 'bmp',
name: 'BMP',
extension: 'bmp',
mimeType: 'image/bmp',
category: 'image',
converter: 'imagemagick',
description: 'Bitmap image',
},
{
id: 'tiff',
name: 'TIFF',
extension: 'tiff',
mimeType: 'image/tiff',
category: 'image',
converter: 'imagemagick',
description: 'Tagged Image File Format',
},
{
id: 'svg',
name: 'SVG',
extension: 'svg',
mimeType: 'image/svg+xml',
category: 'image',
converter: 'imagemagick',
description: 'Scalable Vector Graphics',
},
// Document formats (Pandoc - future implementation)
{
id: 'pdf',
name: 'PDF',
extension: 'pdf',
mimeType: 'application/pdf',
category: 'document',
converter: 'pandoc',
description: 'Portable Document Format',
},
{
id: 'docx',
name: 'DOCX',
extension: 'docx',
mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
category: 'document',
converter: 'pandoc',
description: 'Microsoft Word document',
},
{
id: 'markdown',
name: 'Markdown',
extension: 'md',
mimeType: 'text/markdown',
category: 'document',
converter: 'pandoc',
description: 'Markdown text',
},
{
id: 'html',
name: 'HTML',
extension: 'html',
mimeType: 'text/html',
category: 'document',
converter: 'pandoc',
description: 'HyperText Markup Language',
},
{
id: 'txt',
name: 'Plain Text',
extension: 'txt',
mimeType: 'text/plain',
category: 'document',
converter: 'pandoc',
description: 'Plain text file',
},
];
/**
* Format presets for common conversions
*/
export const FORMAT_PRESETS: FormatPreset[] = [
{
id: 'web-video',
name: 'Web Video',
description: 'Optimize video for web playback (VP8 for better compatibility)',
category: 'video',
sourceFormats: ['mp4', 'avi', 'mov', 'mkv'],
targetFormat: 'webm',
options: {
videoCodec: 'libvpx',
videoBitrate: '1M',
audioCodec: 'libvorbis',
audioBitrate: '128k',
},
},
{
id: 'web-image',
name: 'Web Image',
description: 'Optimize image for web',
category: 'image',
sourceFormats: ['png', 'jpg', 'bmp', 'tiff'],
targetFormat: 'webp',
options: {
imageQuality: 85,
},
},
{
id: 'audio-compress',
name: 'Compress Audio',
description: 'Reduce audio file size',
category: 'audio',
sourceFormats: ['wav', 'flac'],
targetFormat: 'mp3',
options: {
audioBitrate: '192k',
audioCodec: 'libmp3lame',
},
},
{
id: 'video-gif',
name: 'Video to GIF',
description: 'Convert video to animated GIF',
category: 'video',
sourceFormats: ['mp4', 'webm', 'avi', 'mov'],
targetFormat: 'gif',
options: {
videoFps: 15,
videoResolution: '480x-1',
},
},
];
/**
* Get format by ID
*/
export function getFormatById(id: string): ConversionFormat | undefined {
return SUPPORTED_FORMATS.find((f) => f.id === id);
}
/**
* Get format by extension
*/
export function getFormatByExtension(extension: string): ConversionFormat | undefined {
return SUPPORTED_FORMATS.find((f) => f.extension === extension.toLowerCase());
}
/**
* Get format by MIME type
*/
export function getFormatByMimeType(mimeType: string): ConversionFormat | undefined {
return SUPPORTED_FORMATS.find((f) => f.mimeType === mimeType);
}
/**
* Get all formats by category
*/
export function getFormatsByCategory(category: string): ConversionFormat[] {
return SUPPORTED_FORMATS.filter((f) => f.category === category);
}
/**
* Get compatible output formats for input format
*/
export function getCompatibleFormats(inputFormat: ConversionFormat): ConversionFormat[] {
// Same category and same converter
return SUPPORTED_FORMATS.filter(
(f) => f.category === inputFormat.category && f.converter === inputFormat.converter && f.id !== inputFormat.id
);
}
/**
* Check if conversion is supported
*/
export function isConversionSupported(
inputFormat: ConversionFormat,
outputFormat: ConversionFormat
): boolean {
return (
inputFormat.category === outputFormat.category &&
inputFormat.converter === outputFormat.converter &&
inputFormat.id !== outputFormat.id
);
}