无需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
相关产品推荐
相关产品推荐

