☰
Mediabunny μ-law(G.711)PCM 音频编解码器注册规范:codec 字符串、EncodedPacket 数据格式与实现原理
2026/9/29 6:35:10 网站建设 项目流程
  • 音视频
  • 视频处理
  • 音频处理

【免费下载链接】mediabunny

Pure TypeScript media toolkit for reading, writing, and converting video and audio files, directly in the browser.

项目地址:https://gitcode.com/gh_mirrors/me/mediabunny
点击查看免费下载

本篇文章基于 Mediabunny Codec Registry 中 μ-law PCM 编解码器注册条目 展开,完整定义 μ-law(μ 律,即 G.711 压缩 PCM)在 Mediabunny 中的合法 codec 字符串、EncodedPacket数据格式、AudioDecoderConfig配置约定,并结合 src/codec.ts、src/pcm.ts 等源码与 test/node/pcm.test.ts 测试用例,讲解其底层压缩原理、WAVE/MP4 容器映射及实用编解码示例。读完本文,你将掌握如何在浏览器环境中用 Mediabunny 正确声明、编解码与封装 μ-law 音频流。

背景:Mediabunny Codec Registry 与 μ-law

Mediabunny 是一个纯 TypeScript 实现的媒体工具库,可直接在浏览器中完成视频/音频文件的读取、写入与格式转换。为了保证所有出入库的媒体数据行为一致,docs/codec-registry/overview.md 建立了一套 Codec Registry(编解码器注册表):对每个受支持的编解码器,它精确规定EncodedPacket、VideoDecoderConfig、AudioDecoderConfig必须遵循的数据格式,且作为 WebCodecs Codec Registry 的扩展,凡双方共同支持的编解码器,其注册定义保持一致。

μ-law(μ 律)与 A-law(A 律)同属 ITU-T G.711 标准定义的压扩(companding)PCM 音频编解码器:以 8 bit 码字表示原本需要更高位深表达的线性采样值,在语音通信、电话网络与 VoIP 场景中应用极为广泛。在 Mediabunny 的 Codec Registry 中,μ-law 与线性 PCM、A-law 一起被归入"未压缩 PCM 编解码器"家族(见 docs/codec-registry/overview.md 的音频编解码器列表),注册条目为 μ-law PCM。

Codec ID:唯一的合法 codec 字符串

μ-law 在 Mediabunny 中的 Codec ID 只有一个合法取值:

'ulaw'

该字符串即 WebCodecs 体系中 μ-law 的标准 codec 字符串。在 src/codec.ts 的PCM_AUDIO_CODECS常量数组中,'ulaw'与'alaw'、'pcm-s16'、'pcm-u8'等线性 PCM codec 并列,被整体归类为"已知的未压缩音频编解码器"(注释明确说明:不添加le前缀是为了兼容 WebCodecs 注册的 PCM codec 字符串)。AUDIO_CODECS则由NON_PCM_AUDIO_CODECS(AAC、Opus、MP3 等压缩 codec)与PCM_AUDIO_CODECS共同拼接而成,μ-law 因此同时出现在"支持写入的 codec 白名单"中。

与之配套的字符串解析函数inferCodecFromCodecString(见 src/codec.ts)中,codecString === 'ulaw'被显式映射回'ulaw';而在校验音频 chunk 元数据时,VALID_AUDIO_CODEC_STRING_PREFIXES(见 src/codec.ts)将'ulaw'、'alaw'与'pcm'、'mp4a'等前缀并列,说明"以 ulaw 开头"是 Mediabunny 认可的合法音频 codec 字符串前缀之一。后续针对 PCM 家族的专项校验(见 src/codec.ts)则要求 codec 字符串必须精确命中PCM_AUDIO_CODECS中的某一项,否则抛出TypeError。

EncodedPacket数据格式:逐字节的 μ-law 采样流

数据组织规则

EncodedPacket的 data 必须是一串任意长度的字节序列,并满足两个硬性约束:

  1. 总字节数必须能被声道数整除(divisible by the channel count)——即每个声道在每个采样时刻都贡献恰好一个字节;
  2. 每个字节就是一个 μ-law 编码的 PCM 采样值(8 bit 码字);
  3. 多声道时,不同声道的采样按帧交错排列(interleaved)——与线性 PCM 的交错布局一致。

以双声道为例,data 的字节序列应为L0 R0 L1 R1 L2 R2 ...,其中L、R分别代表左右声道在同一采样时刻的 μ-law 码字。由于单个码字只有 8 bit、正好一个字节,因此任意合法的音频帧在字节长度上天然满足"可被声道数整除"的要求;这也是 μ-law 与 A-law 编解码器在本仓库中sampleSize恒为 1 的原因(详见后文)。

与采样转换管道的衔接

Mediabunny 的音频处理核心位于 src/media-sink.ts 与 src/media-source.ts 两处:

  • 解码方向(sink):在 src/media-sink.ts 中,当dataType === 'ulaw' || dataType === 'alaw'时,输入的 8 bit μ-law 码字会被fromUlaw解码为16 bit 有符号整数(s16)输出,outputSampleSize由 1 提升为 2。其读取逻辑(src/media-sink.ts)正是fromUlaw(view.getUint8(byteOffset))——即"每个字节 = 一个 μ-law 采样"的直接体现。
  • 编码方向(source):在 src/media-source.ts 中,浮点采样先被钳位放大为 16 bit 整数(clamp(Math.round(value * 32768), -32768, 32767)),再经toUlaw(int16)压缩为单字节码字写入目标缓冲区。

可见注册表所定义的"1 字节 = 1 采样"格式,在编解码两端都由parsePcmCodec的返回结构(src/codec.ts)显式保障:{ dataType: 'ulaw', sampleSize: 1, littleEndian: true, silentValue: 255 }。其中silentValue: 255值得注意——G.711 μ-law 中码字0xFF(即线性值 0 的编码结果,见测试断言)被用作静音填充值,这与线性 PCM 以 0 为静音的约定不同。

EncodedPacket类型:恒为关键帧

μ-law 是无帧内预测、无跨包依赖的逐采样压缩格式,因此每个EncodedPacket的 type恒为'key'(关键帧)。这意味着:

  • 任何单个包都可以独立解码,无需参照前后包;
  • 媒体管道的丢包容错、随机访问(seek)逻辑可以简化——解码器可以从任意包位置直接切入。

这一特性与 Mediabunny 中其他逐采样格式(如 A-law、线性 PCM)保持一致,也是 WebCodecs 体系对这类 codec 的通行约定。

AudioDecoderConfig:codec 字符串与 description 约定

codec 字符串

AudioDecoderConfig中的 codec 字段合法取值同样是:

'ulaw'

配置时需同时提供有效的sampleRate(正整数)与numberOfChannels(正整数);validateAudioChunkMetadata(见 src/codec.ts)会强制校验这两个字段,任一缺失或非正整数都会抛出TypeError。

description:不使用

μ-law 的全部解码参数(压扩曲线、位深、字节布局)都由 G.711 标准与 codec 字符串本身确定,description字段不被使用。这与需要携带description(如内含编码器配置的 AAC、FLAC 等)的 codec 形成鲜明对比:

  • 对'ulaw'前缀的 codec,校验逻辑不要求description;
  • 从 src/codec.ts 的分支结构看,description仅对需要额外配置的 codec(如 FLAC 等)生成引用描述,其他 codec 一律允许undefined。

因此,创建 μ-law 解码器配置时只需三要素:codec: 'ulaw'、sampleRate、numberOfChannels。

源码级原理:G.711 μ-law 压扩算法实现

编解码核心 src/pcm.ts

src/pcm.ts 提供了 μ-law 的完整编码/解码实现(注明原始来源为 pcm-g711 项目):

编码toUlaw(s16)的要点:

  • 采用 μ-law 编码偏置MULAW_BIAS = 33(G.711 标准规定,偏置用于消除编码误差下限);
  • 输入 16 bit 有符号值右移 2 位(相当于预先除以 4),加上偏置后以MULAW_MAX = 0x1FFF钳位;
  • 通过位扫描确定量化段(position 从 12 递减),拼装符号位、段位与 4 bit 尾数(lsb),最终按 μ-law 规则取反(~(…) & 0xFF)得到 8 bit 码字。

解码fromUlaw(u8)的要点:

  • 对码字取反后分离符号位,从"段位 + 尾数"中还原 13 bit 幅值,减去偏置后左移 2 位回到 16 bit 有符号范围。

整个曲线是近对数的:小信号量化步长小(保真度高)、大信号量化步长大,从而在 8 bit 码字下获得约 12~13 bit 的动态范围,这也是电话语音场景选用 G.711 的根本原因。

测试用例的权威验证 test/node/pcm.test.ts

测试文件明确注明"期望值来自 ITU-T G.711 解码表,以 s16 PCM 表示":

  • 解码锚点(L127-L135):fromUlaw(0x00) === -32124、fromUlaw(0x80) === 32124、fromUlaw(0xFF) === 0、fromUlaw(0xFE) === 8、fromUlaw(0x55) === -716——这些值直接对应 G.711 标准查表结果;
  • 编码锚点(L146-L154):toUlaw(0) === 0xFF、toUlaw(32124) === 0x80、toUlaw(-32768) === 0x00,验证了全幅值与静音值的编码映射;
  • 往返误差(L166-L179):对 12 组正负采样值做fromUlaw(toUlaw(v))往返,断言解码误差|decoded - v| <= max(16, |v| >> 3),定量刻画了 μ-law 压扩的量化误差特征(相对误差约 1/8,绝对误差下限 16);
  • 文件级往返(L181-L236):构造包含全部 256 个可用码字的Int16Array,经WavOutputFormat写出、再经Input读回,断言 codec 为'ulaw'且解码后数据逐字节一致(无损往返),完整验证了"编码 → WAVE 容器 → 解码"整条链路。

容器映射:WAVE 与 ISO-BMFF(MP4)中的 μ-law

WAVE(.wav):format tag 0x0007

WAVE 通过fmtchunk 的 format tag 标识编码。在 src/wave/wave-demuxer.ts 中,WaveFormat.MULAW = 0x0007。关键行为:

  • 解析fmt时若 format tag 为 μ-law/A-law(src/wave/wave-demuxer.ts),bitsPerSample 被强制置为 8,以规范 WAVE 头(即使文件中写的是 0 或其他值);
  • 支持WAVEFORMATEXTENSIBLE(format tag 0xFFFE),会从 subFormat GUID 前 2 字节还原真实 format tag(src/wave/wave-demuxer.ts),兼容现代编码器产出的 WAVE 文件;
  • 识别后getCodec()返回'ulaw'(src/wave/wave-demuxer.ts),MIME 类型为audio/wav。

写入侧在 src/wave/wave-muxer.ts 中,通过parsePcmCodec(codec)判断dataType === 'ulaw'时写WaveFormat.MULAW;由于 μ-law 的sampleSize为 1,blockSize = sampleSize * channels恰好等于声道数。WAVE 输出格式WavOutputFormat的支持 codec 列表明确包含'ulaw'、'alaw'(见 src/output-format.ts),而 Matroska(MKV)输出格式则将 μ-law/A-law 排除在支持列表之外(见 src/output-format.ts)——这是容器能力差异的如实体现,选型时应以目标容器的getSupportedCodecs()为准。

ISO-BMFF(MP4 / MOV):ulawsample entry

在 src/isobmff/isobmff-boxes.ts 的audioCodecToBoxName映射中,'ulaw'对应名为ulaw的 sample entry box(QuickTime 风格,大小写形式即ulaw)。解封装侧在解析stsd内的声音 sample description 时(src/isobmff/isobmff-demuxer.ts),识别到codecName === 'ulaw'后直接将轨道 codec 置为'ulaw'——因此带 μ-law 音轨的 MP4/MOV 文件可被 Mediabunny 正常读取。

实用示例:在浏览器中编码与解码 μ-law 音频

基于上文规范,给出可直接运行的 Mediabunny 用法示例。

编码(s16 → ulaw)并写入 WAVE 文件(参考 test/node/pcm.test.ts 的往返流程):

import { Output, WavOutputFormat, BufferTarget, AudioSampleSource, AudioSample } from 'mediabunny'; const data = new Int16Array(8000); // 1 秒、8 kHz 的单声道 s16 PCM for (let i = 0; i < data.length; i++) data[i] = ...; // 填充采样 const output = new Output({ format: new WavOutputFormat(), target: new BufferTarget(), }); // codec 字符串必须严格使用 'ulaw' const audioSource = new AudioSampleSource({ codec: 'ulaw' }); output.addAudioTrack(audioSource); await output.start(); const sample = new AudioSample({ data, format: 's16', numberOfChannels: 1, sampleRate: 8000, timestamp: 0, }); await audioSource.add(sample); sample.close(); audioSource.close(); await output.finalize(); // output.target.buffer 即为携带 μ-law 音轨(format tag 0x0007)的 WAVE 文件

解码(ulaw → s16 PCM)并读取采样:

import { Input, BufferSource, AudioSampleSink } from 'mediabunny'; using input = new Input({ source: new BufferSource(wavBuffer), formats: ['wav'], }); const track = (await input.getPrimaryAudioTrack())!; console.log(await track.getCodec()); // 'ulaw' const sink = new AudioSampleSink(track); for await (using sample of sink.samples()) { const decoded = new Int16Array(sample.numberOfFrames * sample.numberOfChannels); sample.copyTo(decoded, { format: 's16', planeIndex: 0 }); // decoded 即解码后的 16 bit 线性 PCM 采样 }

要点回顾:

  • codec 字符串一律写作'ulaw',同时必须提供sampleRate与numberOfChannels;
  • 输入AudioSampleSource的 codec 决定写出格式,输出WavOutputFormat会据此写出0x0007format tag;
  • 解码侧AudioSampleSink自动执行fromUlaw,产出 s16 格式的AudioSample;
  • 底层AudioDecoderConfig不需要description,EncodedPacket的 type 恒为'key',data 中每个字节为一个 μ-law 码字、多声道按帧交错。

与 A-law 的对照及选型建议

μ-law 与 A-law(docs/codec-registry/alaw.md)在 Mediabunny 中的注册结构几乎完全对称:同样为单字节采样、type 恒为'key'、AudioDecoderConfig不使用description;差异主要体现在两处:

维度μ-lawA-law
Codec ID / codec 字符串'ulaw''alaw'
标准依据ITU-T G.711 Tables 2a/2bITU-T G.711 Tables 1a/1b
WAVE format tag0x0007(WaveFormat.MULAW)0x0006(WaveFormat.ALAW)
编码偏置/取反规则偏置 33、码字取反码字异或0x55
静音码字(silentValue)255(0xFF)213(0xD5)

silentValue的差异来自 src/codec.ts:μ-law 静音码字为255,A-law 为213。选择建议:遵循 G.711 的通行地域惯例——北美/日本为主的系统使用 μ-law,欧洲与我国电话网络使用 A-law;若面对未知来源的语音文件,可依据容器内的 format tag 或 codec 字符串自动识别(Mediabunny 的解封装器已具备此能力)。

总结

μ-law 是 Mediabunny Codec Registry 中结构最简洁的编解码器之一:Codec ID 与AudioDecoderConfigcodec 字符串均为'ulaw',description不使用,EncodedPackettype 恒为'key',data 为"每声道每帧 1 字节、多声道交错"的 μ-law 码字序列。理解这些约定,即可通过AudioSampleSource/AudioSampleSink与WavOutputFormat/ISO-BMFF 容器完成 μ-law 音频的编解码与封装,其 G.711 压扩曲线、静音码字与 16 bit 解码输出的每个细节,均有 src/pcm.ts 与 test/node/pcm.test.ts 中的锚点值可查可验。

  • 音视频
  • 视频处理
  • 音频处理

【免费下载链接】mediabunny

Pure TypeScript media toolkit for reading, writing, and converting video and audio files, directly in the browser.

项目地址:https://gitcode.com/gh_mirrors/me/mediabunny
点击查看免费下载

相关推荐

上一篇:Pie语言入门指南:从安装到编写第一个依赖类型程序的完整教程
下一篇:知识图谱嵌入从未如此简单:PromptKG助力研究者快速实现SOTA模型

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询