使用Web Codecs编码AudioBuffer报错:输入缓冲区与编解码器参数不兼容
解决Web Codecs编码时的"Input audio buffer is incompatible with codec parameters"错误
错误原因及修复方案
1. 编码器配置与AudioData参数不匹配
你给AudioEncoder固定配置了采样率44100,但创建AudioData时使用的是原音频的audioBuffer.sampleRate,如果原音频采样率(比如48000)与编码器配置不一致,就会触发参数不兼容错误。
修复:
要么统一使用原音频的参数配置编码器,要么将原音频重采样到编码器指定的采样率:
- 方案一(统一参数):
encoder.configure({ codec: 'opus', sampleRate: audioBuffer.sampleRate, // 对齐原音频采样率 numberOfChannels: audioBuffer.numberOfChannels, // 对齐原音频声道数 bitrate: 128_000, });
- 方案二(强制重采样):
async function resampleAudioBuffer(buffer: AudioBuffer, targetSampleRate: number): Promise<AudioBuffer> { if (buffer.sampleRate === targetSampleRate) return buffer; const offlineContext = new OfflineAudioContext( buffer.numberOfChannels, Math.floor(buffer.length * targetSampleRate / buffer.sampleRate), targetSampleRate ); const source = offlineContext.createBufferSource(); source.buffer = buffer; source.connect(offlineContext.destination); source.start(); return await offlineContext.startRendering(); } // 在encodeAudio中调用 const audioBuffer = await fetchAudioBuffer(url); const resampledBuffer = await resampleAudioBuffer(audioBuffer, 44100);
2. 平面格式转换的偏移量错误
bufferToF32Planar函数中,offset = data.length的写法错误,会导致多声道数据互相覆盖,生成的平面数据格式完全不符合要求,这是触发错误的核心原因之一。
修复:
function bufferToF32Planar(input: AudioBuffer): Float32Array { const result = new Float32Array(input.length * input.numberOfChannels); let offset = 0; for (let i = 0; i < input.numberOfChannels; i++) { const data = input.getChannelData(i); result.set(data, offset); offset += data.length; // 改为累加偏移量 } return result; }
3. 缺少编码器的flush操作
调用encoder.encode(data)后,必须调用encoder.flush()通知编码器处理剩余数据并输出结果,否则编码器可能无法正常完成编码流程,甚至引发状态异常。
修复:
encoder.encode(data); await encoder.flush(); encoder.close(); // 编码完成后关闭编码器
完整修复后的代码示例
/** * Encode an audio file using web codecs */ async function encodeAudio(url: string) { const audioBuffer = await fetchAudioBuffer(url); const signal = bufferToF32Planar(audioBuffer); const encoder = new AudioEncoder({ output: (chunk) => { console.log('编码输出:', chunk); // 可在此处理编码后的Chunk,例如转为Blob保存 }, error: console.error, }); encoder.configure({ codec: 'opus', sampleRate: audioBuffer.sampleRate, numberOfChannels: audioBuffer.numberOfChannels, bitrate: 128_000, }); const data = new AudioData({ format: 'f32-planar', sampleRate: audioBuffer.sampleRate, numberOfChannels: audioBuffer.numberOfChannels, numberOfFrames: audioBuffer.length, timestamp: 0, data: signal, }); encoder.encode(data); await encoder.flush(); encoder.close(); } /** * Convert an audio buffer into a planar float 32 array * @param input processed audio buffer * @returns Typed array */ function bufferToF32Planar(input: AudioBuffer): Float32Array { const result = new Float32Array(input.length * input.numberOfChannels); let offset = 0; for (let i = 0; i < input.numberOfChannels; i++) { const data = input.getChannelData(i); result.set(data, offset); offset += data.length; } return result; } /** * Fetch the audio file and convert it into * an audio buffer using an audio context */ async function fetchAudioBuffer( input: RequestInfo | URL, init?: RequestInit | undefined, ): Promise<AudioBuffer> { const context = new AudioContext(); const res = await fetch(input, init); const buffer = await res.arrayBuffer(); return await context.decodeAudioData(buffer); } await encodeAudio('/audio.mp3');
内容的提问来源于stack exchange,提问作者Konstantin Paulus
相关产品推荐
相关产品推荐

