feat: add media converter app and fix compilation errors
This commit is contained in:
157
lib/media/wasm/wasmLoader.ts
Normal file
157
lib/media/wasm/wasmLoader.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import type { FFmpeg } from '@ffmpeg/ffmpeg';
|
||||
import type { ConverterEngine, WASMModuleState } from '@/types/media';
|
||||
|
||||
/**
|
||||
* WASM module loading state
|
||||
*/
|
||||
const moduleState: WASMModuleState = {
|
||||
ffmpeg: false,
|
||||
imagemagick: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* Cached WASM instances
|
||||
*/
|
||||
let ffmpegInstance: FFmpeg | null = null;
|
||||
let imagemagickInstance: any = null;
|
||||
|
||||
/**
|
||||
* Load FFmpeg WASM module
|
||||
*/
|
||||
export async function loadFFmpeg(): Promise<FFmpeg> {
|
||||
if (ffmpegInstance && moduleState.ffmpeg) {
|
||||
return ffmpegInstance;
|
||||
}
|
||||
|
||||
try {
|
||||
const { FFmpeg } = await import('@ffmpeg/ffmpeg');
|
||||
const { toBlobURL } = await import('@ffmpeg/util');
|
||||
|
||||
ffmpegInstance = new FFmpeg();
|
||||
|
||||
// Load core and dependencies
|
||||
const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/umd';
|
||||
|
||||
ffmpegInstance.on('log', ({ message }) => {
|
||||
console.log('[FFmpeg]', message);
|
||||
});
|
||||
|
||||
await ffmpegInstance.load({
|
||||
coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),
|
||||
wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),
|
||||
});
|
||||
|
||||
moduleState.ffmpeg = true;
|
||||
console.log('FFmpeg loaded successfully');
|
||||
|
||||
return ffmpegInstance;
|
||||
} catch (error) {
|
||||
console.error('Failed to load FFmpeg:', error);
|
||||
throw new Error('Failed to load FFmpeg WASM module');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load ImageMagick WASM module
|
||||
*/
|
||||
export async function loadImageMagick(): Promise<any> {
|
||||
if (imagemagickInstance && moduleState.imagemagick) {
|
||||
return imagemagickInstance;
|
||||
}
|
||||
|
||||
try {
|
||||
const { initializeImageMagick } = await import('@imagemagick/magick-wasm');
|
||||
|
||||
// Initialize ImageMagick with WASM file from public directory
|
||||
// In production (static export), this will be served from /wasm/magick.wasm
|
||||
const wasmUrl = '/wasm/magick.wasm';
|
||||
|
||||
console.log('[ImageMagick] Attempting to load WASM from:', wasmUrl);
|
||||
|
||||
// Test fetch the WASM file first to debug
|
||||
try {
|
||||
const response = await fetch(wasmUrl);
|
||||
console.log('[ImageMagick] WASM fetch response:', {
|
||||
ok: response.ok,
|
||||
status: response.status,
|
||||
contentType: response.headers.get('content-type'),
|
||||
contentLength: response.headers.get('content-length'),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch WASM file: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const arrayBuffer = await response.arrayBuffer();
|
||||
console.log('[ImageMagick] WASM file size:', arrayBuffer.byteLength, 'bytes');
|
||||
|
||||
if (arrayBuffer.byteLength === 0) {
|
||||
throw new Error('WASM file is empty');
|
||||
}
|
||||
|
||||
// Now initialize with the buffer directly
|
||||
await initializeImageMagick(arrayBuffer);
|
||||
} catch (fetchError) {
|
||||
console.error('[ImageMagick] Failed to fetch WASM:', fetchError);
|
||||
throw fetchError;
|
||||
}
|
||||
|
||||
const ImageMagick = await import('@imagemagick/magick-wasm');
|
||||
|
||||
imagemagickInstance = ImageMagick;
|
||||
moduleState.imagemagick = true;
|
||||
console.log('[ImageMagick] Loaded and initialized successfully');
|
||||
|
||||
return imagemagickInstance;
|
||||
} catch (error) {
|
||||
console.error('[ImageMagick] Failed to load:', error);
|
||||
throw new Error(`Failed to load ImageMagick WASM module: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get loaded module state
|
||||
*/
|
||||
export function getModuleState(): WASMModuleState {
|
||||
return { ...moduleState };
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a specific module is loaded
|
||||
*/
|
||||
export function isModuleLoaded(engine: ConverterEngine): boolean {
|
||||
return moduleState[engine];
|
||||
}
|
||||
|
||||
/**
|
||||
* Load appropriate WASM module for converter engine
|
||||
*/
|
||||
export async function loadModule(engine: ConverterEngine): Promise<any> {
|
||||
switch (engine) {
|
||||
case 'ffmpeg':
|
||||
return loadFFmpeg();
|
||||
case 'imagemagick':
|
||||
return loadImageMagick();
|
||||
default:
|
||||
throw new Error(`Unknown converter engine: ${engine}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unload all WASM modules and free memory
|
||||
*/
|
||||
export function unloadAll(): void {
|
||||
if (ffmpegInstance) {
|
||||
// FFmpeg doesn't have an explicit unload method
|
||||
// Just null the instance
|
||||
ffmpegInstance = null;
|
||||
moduleState.ffmpeg = false;
|
||||
}
|
||||
|
||||
if (imagemagickInstance) {
|
||||
imagemagickInstance = null;
|
||||
moduleState.imagemagick = false;
|
||||
}
|
||||
|
||||
console.log('All WASM modules unloaded');
|
||||
}
|
||||
Reference in New Issue
Block a user