使用 JavaScript 和 ffmpeg.wasm 将录音 Blob 流切分并转换为多个 5 秒的 WAV 文件
引言
在现代Web应用中,音频处理变得越来越常见。本文将介绍如何使用JavaScript和ffmpeg.wasm库来处理录音数据,将其切分为多个5秒的WAV文件。
准备工作
首先,我们需要在项目中引入ffmpeg.wasm。可以通过CDN方式引入:
<script src="https://unpkg.com/@ffmpeg/ffmpeg@latest/dist/ffmpeg.min.js"></script>
实现步骤
1. 初始化FFmpeg
首先需要加载FFmpeg核心:
const { createFFmpeg, fetchFile } = FFmpeg;
const ffmpeg = createFFmpeg({ log: true });
// 加载FFmpeg核心
await ffmpeg.load();2. 录音功能实现
使用MediaRecorder API进行录音:
let mediaRecorder;
let audioChunks = [];
// 开始录音
async function startRecording() {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = (event) => {
if (event.data.size > 0) {
audioChunks.push(event.data);
}
};
mediaRecorder.start(5000); // 每5秒触发一次dataavailable事件
}
// 停止录音
function stopRecording() {
return new Promise((resolve) => {
mediaRecorder.onstop = () => {
const audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
resolve(audioBlob);
};
mediaRecorder.stop();
});
}3. 音频处理和切分
使用ffmpeg.wasm处理音频并切分为5秒片段:
async function splitAudioIntoChunks(audioBlob) {
// 将Blob写入FFmpeg文件系统
ffmpeg.FS('writeFile', 'input.webm', await fetchFile(audioBlob));
// 使用FFmpeg命令切分音频
// -i input.webm: 输入文件
// -f segment: 使用分段器
// -segment_time 5: 每段5秒
// -c copy: 直接复制编码,不重新编码
// output_%03d.wav: 输出文件名模式
await ffmpeg.run(
'-i', 'input.webm',
'-f', 'segment',
'-segment_time', '5',
'-c', 'copy',
'output_%03d.wav'
);
// 读取所有生成的文件
const chunks = [];
let i = 0;
while (true) {
try {
const data = ffmpeg.FS('readFile', `output_${String(i).padStart(3, '0')}.wav`);
chunks.push(new Blob([data.buffer], { type: 'audio/wav' }));
i++;
} catch (error) {
break;
}
}
return chunks;
}4. 完整的使用示例
整合上述功能的完整示例:
class AudioSplitter {
constructor() {
this.ffmpeg = createFFmpeg({ log: true });
this.audioChunks = [];
}
async initialize() {
await this.ffmpeg.load();
}
async startRecording() {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
this.mediaRecorder = new MediaRecorder(stream);
this.mediaRecorder.ondataavailable = (event) => {
if (event.data.size > 0) {
this.audioChunks.push(event.data);
}
};
this.mediaRecorder.start(5000);
}
async stopAndSplitRecording() {
return new Promise((resolve) => {
this.mediaRecorder.onstop = async () => {
const audioBlob = new Blob(this.audioChunks, { type: 'audio/webm' });
const chunks = await this.splitAudioIntoChunks(audioBlob);
this.audioChunks = []; // 清空数组
resolve(chunks);
};
this.mediaRecorder.stop();
});
}
async splitAudioIntoChunks(audioBlob) {
this.ffmpeg.FS('writeFile', 'input.webm', await fetchFile(audioBlob));
await this.ffmpeg.run(
'-i', 'input.webm',
'-f', 'segment',
'-segment_time', '5',
'-c', 'copy',
'output_%03d.wav'
);
const chunks = [];
let i = 0;
while (true) {
try {
const data = this.ffmpeg.FS('readFile', `output_${String(i).padStart(3, '0')}.wav`);
chunks.push(new Blob([data.buffer], { type: 'audio/wav' }));
i++;
} catch (error) {
break;
}
}
return chunks;
}
}
// 使用示例
const splitter = new AudioSplitter();
await splitter.initialize();
// 开始录音
await splitter.startRecording();
// 10秒后停止并获取切分的音频块
setTimeout(async () => {
const chunks = await splitter.stopAndSplitRecording();
console.log(`生成了 ${chunks.length} 个音频片段`);
// 可以在这里处理每个音频片段,比如下载或上传
chunks.forEach((chunk, index) => {
const url = URL.createObjectURL(chunk);
const a = document.createElement('a');
a.href = url;
a.download = `audio_chunk_${index + 1}.wav`;
a.click();
URL.revokeObjectURL(url);
});
}, 10000);注意事项
- ffmpeg.wasm文件较大,首次加载可能需要较长时间
- 浏览器兼容性需要考虑,特别是MediaRecorder API的支持情况
- 录音权限需要用户授权
- 可以根据需要调整切分的时间间隔
- 在生产环境中,建议添加适当的错误处理和用户反馈
总结
通过结合JavaScript的MediaRecorder API和ffmpeg.wasm,我们可以轻松地在浏览器中实现音频录制和切分功能。这种方法无需服务器端处理,完全在客户端完成,保护了用户隐私并减少了服务器负载。