feat(audio): add ffmpeg-backed audio converter for mp3/wav/ogg/flac/aac/m4a
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
import { execFile } from 'node:child_process';
|
||||
import { promisify } from 'node:util';
|
||||
import { register } from './registry.js';
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
export const AUDIO_FORMATS = ['mp3', 'wav', 'ogg', 'flac', 'aac', 'm4a'];
|
||||
|
||||
const CODEC_ARGS = {
|
||||
mp3: ['-c:a', 'libmp3lame'],
|
||||
ogg: ['-c:a', 'libvorbis'],
|
||||
aac: ['-c:a', 'aac'],
|
||||
m4a: ['-c:a', 'aac'],
|
||||
wav: ['-c:a', 'pcm_s16le'],
|
||||
flac: ['-c:a', 'flac'],
|
||||
};
|
||||
|
||||
const BITRATE_CAPABLE_FORMATS = ['mp3', 'ogg', 'aac', 'm4a'];
|
||||
|
||||
export function registerAudioConverters() {
|
||||
for (const sourceFormat of AUDIO_FORMATS) {
|
||||
for (const targetFormat of AUDIO_FORMATS) {
|
||||
if (sourceFormat === targetFormat) continue;
|
||||
register({
|
||||
family: 'audio',
|
||||
sourceFormat,
|
||||
targetFormat,
|
||||
convert: async (inputPath, outputPath, { quality, timeoutMs } = {}) => {
|
||||
const ffmpegPath = process.env.FFMPEG_PATH || 'ffmpeg';
|
||||
const args = ['-y', '-i', inputPath, ...CODEC_ARGS[targetFormat]];
|
||||
if (quality != null && BITRATE_CAPABLE_FORMATS.includes(targetFormat)) {
|
||||
args.push('-b:a', `${quality}k`);
|
||||
}
|
||||
args.push(outputPath);
|
||||
await execFileAsync(ffmpegPath, args, { timeout: timeoutMs });
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user