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

无需FFmpeg,Node.js下将OGG转为WebM适配Whisper的方案

给OGG音频添加WebM容器的字节方案

要直接给Telegram获取的OGG二进制数据添加WebM容器首尾,你需要构造符合Matroska(WebM基于此规范)结构的头部和尾部字节,以下是具体实现细节:

1. 头部字节构造

WebM的头部需要包含EBML魔数、EBML头部元数据、轨道定义这几个核心部分,对应的Uint8Array序列如下:

const webmHeader = new Uint8Array([
  // EBML魔数(WebM文件标识)
  0x1A, 0x45, 0xDF, 0xA3,
  // EBML头部总长度(可变编码,此处表示42字节)
  0x80, 0x80, 0x80, 0x80, 0x2A,
  // EBML版本
  0x42, 0x86, 0x81, 0x01,
  // EBML读取版本
  0x42, 0xF7, 0x81, 0x01,
  // EBML最大ID长度
  0x42, 0xF2, 0x81, 0x04,
  // EBML最大尺寸长度
  0x42, 0xF3, 0x81, 0x08,
  // 文档类型(WebM)
  0x42, 0x82, 0x87, 0x57, 0x65, 0x62, 0x4D,
  // 文档类型版本
  0x42, 0x87, 0x81, 0x01,
  // 文档类型读取版本
  0x42, 0x85, 0x81, 0x01,
  // Tracks元素起始(长度占位,需后续调整)
  0x16, 0x54, 0xAE, 0x6B, 0x80, 0x80, 0x80, 0x80, 0x38,
  // TrackEntry起始
  0xAE, 0x80, 0x80, 0x80, 0x80, 0x30,
  // Track编号
  0xD7, 0x81, 0x01,
  // Track类型(音频)
  0x83, 0x81, 0x02,
  // Track名称
  0x85, 0x85, 0x56, 0x6F, 0x72, 0x62, 0x69, 0x73,
  // CodecID(指定为Vorbis编码)
  0x86, 0x88, 0x76, 0x6F, 0x72, 0x62, 0x69, 0x73, 0x30, 0x30,
  // Audio元素起始
  0xE1, 0x80, 0x80, 0x80, 0x80, 0x14,
  // 采样率(默认44100Hz,可变编码)
  0xB5, 0x84, 0x40, 0x00, 0x00, 0x00,
  // 声道数(单声道)
  0x9F, 0x81, 0x01,
  // 位深度(16位)
  0x62, 0x64, 0x81, 0x10,
  // 关闭Audio、TrackEntry、Tracks元素
  0x00, 0x00, 0x00, 0x00,
  // Cluster元素起始(长度占位,需后续调整)
  0x1F, 0x43, 0xB6, 0x75, 0x80, 0x80, 0x80, 0x80
]);

2. 处理OGG原始数据

Telegram返回的OGG包含页面头部,需要跳过这部分提取纯Vorbis音频流:

// 假设audioData是从Telegram获取的OGG ArrayBuffer
const oggUint8 = new Uint8Array(audioData);
// 跳过OGG初始页面头部(通常前27字节,部分文件可能有差异)
const vorbisData = oggUint8.slice(27);

3. 尾部字节构造

WebM尾部需要关闭Cluster和整个EBML文档:

const webmFooter = new Uint8Array([
  // 关闭Cluster元素
  0x00, 0x00, 0x00, 0x00,
  // 关闭EBML文档
  0x00, 0x00, 0x00, 0x00
]);

4. 合并生成WebM数据

将头部、处理后的Vorbis流、尾部合并为完整的WebM ArrayBuffer:

// 计算总长度
const totalLength = webmHeader.length + vorbisData.length + webmFooter.length;
// 合并所有数据段
const webmData = new Uint8Array(totalLength);
webmData.set(webmHeader, 0);
webmData.set(vorbisData, webmHeader.length);
webmData.set(webmFooter, webmHeader.length + vorbisData.length);
// 转换为ArrayBuffer用于传给Whisper
const webmArrayBuffer = webmData.buffer;

注意事项

  • 头部中的长度字段采用Matroska可变长度编码,若要严格符合规范,需根据实际数据长度重新计算并替换占位值
  • 部分OGG文件的页面头部长度可能不同,需根据实际OGG结构调整slice(27)的起始位置
  • 不可直接将完整OGG数据放入WebM容器,必须提取纯Vorbis流才能被Whisper识别

内容的提问来源于stack exchange,提问作者Evert

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 23:40:38