You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用原生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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 03:09:20