使用原生JavaScript从视频Blob中提取音频的实现方法
原生JS客户端提取视频Blob音频实现
全程使用浏览器内置API,无需引入任何第三方依赖,核心通过Web Audio API完成音频解码,默认输出兼容性最好的无损WAV格式音频。
核心提取函数
async function extractAudio(videoBlob) { // 兼容webkit前缀的旧版浏览器 const AudioContext = window.AudioContext || window.webkitAudioContext; const audioCtx = new AudioContext(); // 将视频Blob转为解码所需的ArrayBuffer格式 const videoBuffer = await videoBlob.arrayBuffer(); // 解码提取视频中的原始PCM音频数据 const audioBuffer = await audioCtx.decodeAudioData(videoBuffer); // 编码为WAV格式 const channelCount = audioBuffer.numberOfChannels; const sampleRate = audioBuffer.sampleRate; const sampleLength = audioBuffer.length * channelCount * 2; const wavBuffer = new ArrayBuffer(44 + sampleLength); // WAV标准头部占44字节 const view = new DataView(wavBuffer); // 工具方法:写入字符串到DataView const writeStr = (offset, str) => { for (let i = 0; i < str.length; i++) { view.setUint8(offset + i, str.charCodeAt(i)); } }; // 按WAV规范写入文件头 let offset = 0; writeStr(offset, 'RIFF'); offset += 4; view.setUint32(offset, 36 + sampleLength, true); offset += 4; writeStr(offset, 'WAVE'); offset += 4; writeStr(offset, 'fmt '); offset += 4; view.setUint32(offset, 16, true); offset += 4; view.setUint16(offset, 1, true); offset += 2; // 标记为PCM编码 view.setUint16(offset, channelCount, true); offset += 2; view.setUint32(offset, sampleRate, true); offset += 4; view.setUint32(offset, sampleRate * channelCount * 2, true); offset += 4; view.setUint16(offset, channelCount * 2, true); offset += 2; view.setUint16(offset, 16, true); offset += 2; // 16位采样位深 writeStr(offset, 'data'); offset += 4; view.setUint32(offset, sampleLength, true); offset += 4; // 写入PCM音频采样数据 const channels = []; for (let i = 0; i < channelCount; i++) { channels.push(audioBuffer.getChannelData(i)); } for (let i = 0; i < audioBuffer.length; i++) { for (let ch = 0; ch < channelCount; ch++) { let sample = Math.max(-1, Math.min(1, channels[ch][i])); sample = sample < 0 ? sample * 0x8000 : sample * 0x7FFF; view.setInt16(offset, sample, true); offset += 2; } } // 关闭音频上下文释放占用资源 await audioCtx.close(); return new Blob([wavBuffer], { type: 'audio/wav' }); }
音频下载实现
拿到提取后的音频Blob后,通过临时URL触发浏览器原生下载即可:
async function downloadExtractedAudio(videoBlob, saveName = '录制音频.wav') { const audioBlob = await extractAudio(videoBlob); const tempUrl = URL.createObjectURL(audioBlob); const linkEl = document.createElement('a'); linkEl.href = tempUrl; linkEl.download = saveName; document.body.append(linkEl); linkEl.click(); // 清理临时资源避免内存泄漏 linkEl.remove(); URL.revokeObjectURL(tempUrl); }
注意事项
- 所有相关函数必须绑定在用户主动触发的事件(比如点击按钮)回调中调用,否则浏览器会因安全策略拦截音频上下文初始化,导致解码失败
- 上述实现默认输出无损WAV格式,不需要额外编码库,全平台浏览器兼容;如果需要输出MP3、AAC等体积更小的压缩格式,需要额外引入对应的前端音频编码库
- 处理时长较长的视频时会占用一定内存,处理完成后代码会自动释放音频上下文,临时URL也会主动回收,不会造成内存泄漏
内容的提问来源于stack exchange,提问作者Oskar Zanota
相关产品推荐
相关产品推荐

