使AAC数据包适配createSourceBuffer API以在Safari上兼容HLS
解决Safari中提取HLS音频数据做多通道分析的问题
核心问题
Safari无法直接从媒体元素源提取音频数据,通过hls.js拿到解复用后的裸AAC音频块后,浏览器解码API(包括AudioDecoder和decodeAudioData)无法识别这些裸数据——因为裸AAC缺少ADTS头部,必须先补全头部才能被正确解码。
解决方案步骤
- 生成ADTS头部:根据你的AAC编码参数(采样率48000、双通道、mp4a.40.2编码),生成对应ADTS头字节,添加到每个AAC块前。
- 拼接完整AAC数据流:把带ADTS头的AAC块拼接成连续的二进制数据。
- 解码并接入分析器:用
AudioContext.decodeAudioData解码处理后的数据流,得到AudioBuffer后接入分析器节点。
修正后的代码示例
// 实现ADTS头部生成函数 function generateADTSHeader(frameLength, sampleRate = 48000, channels = 2) { const sampleRateIndex = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350].indexOf(sampleRate); const adtsHeader = new Uint8Array(7); adtsHeader[0] = 0xFF; // 同步字 adtsHeader[1] = 0xF1; // MPEG-4、无CRC校验 adtsHeader[2] = (0x00 << 6) | (sampleRateIndex << 2) | (channels >> 2); adtsHeader[3] = ((channels & 0x3) << 6) | ((frameLength + 7) >> 11); adtsHeader[4] = ((frameLength + 7) & 0x7FF) >> 3; adtsHeader[5] = (((frameLength + 7) & 0x7) << 5) | 0x1F; adtsHeader[6] = 0xFC; return adtsHeader; } hls.on(Hls.Events.BUFFER_APPENDING, function (event, data) { if (data.type === "audio") { const context = new (window.AudioContext || window.webkitAudioContext)(); const analyser = context.createAnalyser(); analyser.connect(context.destination); // 给裸AAC块添加ADTS头部 const aacFrame = data.data; const adtsHeader = generateADTSHeader(aacFrame.length); const fullFrame = new Uint8Array(adtsHeader.length + aacFrame.length); fullFrame.set(adtsHeader, 0); fullFrame.set(new Uint8Array(aacFrame), adtsHeader.length); // 解码处理后的完整AAC数据 context.decodeAudioData(fullFrame.buffer, (audioBuffer) => { const srcNode = context.createBufferSource(); srcNode.buffer = audioBuffer; srcNode.connect(analyser); srcNode.start(); }, (err) => { console.error("解码失败:", err); }); } });
为什么之前的方法无效?
- 直接用
createBuffer把AAC字节当成PCM采样数据:AAC是压缩编码格式,不是原始音频采样值,这样处理会产生噪音或无有效数据。 - 未加头部直接用
AudioDecoder:AudioDecoder需要完整的编码帧结构,裸AAC块缺少ADTS头,解码器无法识别帧边界和编码参数,导致解码失败。
内容的提问来源于stack exchange,提问作者Dan Rossi
相关产品推荐
相关产品推荐

