🎬 第二章 把控FFmpeg骨架:【八大金刚】核心开发库
📄 一句话概括

它管三件事:采样率、采样格式(planar/packed)、声道布局。 重采样改的是「每秒多少个点」,不是时长——时长 = 样本数 ÷ 采样率。

📝 本节和前面几节的关系

2.7 讲画面,这一篇讲声音那一侧的对应物。 它跟 2.9 的 libswscale 是同一层的两个库,一个管音一个管画。

一、三件事,第二件最容易忽略

事 为什么需要


采样率转换 麦克风 44100、声卡 48000,对不上 采样格式转换 planar 与 packed 两种排法 声道布局转换 立体声转单声道、5.1 转立体声

planar 与 packed 的区别就一句话:planar 把左右声道分开存两段, packed 把左右交错成一个序列(LRLRLR)。 FFmpeg 内部多数解码器给 planar,不少设备要 packed。 不转直接喂过去, 听到的是噪声或者一半声道没了。 这个错很隐蔽:不报错、不崩,就是声音不对。所以「声音怪」时第一个要查的就是采样格式。

二、数量的算术:48000/44100 约 1.0884

重采样不改变时长,只改变样本数。 项 值


源采样率 44100 Hz 目标采样率 48000 Hz 1024 个样本 约 23.2 毫秒 转完应该 约 1115 个样本

换算只有一条公式:时长 = 样本数 ÷ 采样率。 转换前后这个商必须相等,不等就是有一步搞错了。 「声音变快」几乎都是「改了标签没改数据」:把 44100 的数据硬当成 48000 播, 时长缩到 0.919 倍,听感就是又快又尖。

三、SwrContext:三步配好

步 函数 干什么


1 swr_alloc_set_opts2 给源与目标的参数 2 swr_init 校验并准备 3 swr_convert 真转换

第 2 步会失败:参数不匹配(比如声道布局对不上)在这一步报,不会等到转换时才崩。 第 3 步的输出长度要自己算。 给的目标缓冲区小了,库会截断——不报错,就是后半段没了。

四、一个例子:把一段音频改成推流要的格式

直播推流常见要求:AAC、48000 Hz、立体声、fltp。 而麦克风给你的是 44100 Hz、单声道、s16。 项 麦克风给的 推流要的


采样率 44100 48000 声道 单声道 立体声 格式 s16 fltp

三样全不一样,一次 swr_convert 全改完。 不用分三步做——它本来就是为「一次改完」设计的。 顺序无所谓,但参数必须给全。 少给一项,它按默认值补,补出来的可能不是你想要的。

五、动手 Demo:44100 变 48000,样本数怎么变

这一段做算术:1024 个样本在两种采样率下的时长与目标样本数。 比例 48000/44100 约 1.0884。

src, dst, n = 44100, 48000, 1024
print(n * 1000.0 / src, "毫秒")
print(round(n * dst / float(src)), "个样本")

实跑输出:

--------------------------------------------------------------------
libswresample——44100 变 48000,样本数怎么变
--------------------------------------------------------------------

**① 真跑一次重采样**

取 1024 个样本(44100 Hz 下约 23.2 毫秒),转成 48000 Hz。

  项             值
  ---------------------------
  源采样率       44100 Hz
  目标采样率     48000 Hz
  送入样本       1024
  应得样本       1115

**比例是 48000/44100,约 1.0884。** 一千多个样本进来,
出去就多几十个——**重采样改的是「每秒多少个点」,不是「时长」。**

**② 它管的三件事**

  事               为什么需要
  -----------------------------------------------------
  采样率转换       麦克风 44100、声卡 48000,对不上
  采样格式转换     planar 与 packed 两种排法
  声道布局转换     立体声转单声道、5.1 转立体声

**第二件最容易被忽略。** FFmpeg 内部多数解码器给的是 planar(左右声道分开存),
而不少设备要的是 packed(左右交错)。**不转就喂过去,听到的是噪声。**

**③ 「声音变快」是怎么来的**

把 44100 的数据直接按 48000 播放,时长会缩到原来的 0.919 倍,听感就是变快变尖。
**这不是重采样,是「改了标签没改数据」。** 正确做法是让 libswresample 真的插值。

**④ 一个能自查的数**

时长 = 样本数 ÷ 采样率。**转换前后这个商必须相等**,不等就是有一步搞错了。

1024 个样本进来,约 1115 个出去。 时长不变(约 23.2 毫秒),变的是每秒的点数。

30 秒实验

  1. 用 av.AudioResampler 把一段 44100 的音频转成 48000,数一下样本数与时长。
  2. 把 planar 的数据当 packed 解读,听一下是什么声音。
  3. 算一遍 48000 转 44100 的目标样本数,跟代码对一下。

常见误区

  1. 以为重采样会改变速度。 它只改每秒点数,时长不变。
  2. 忽略 planar 与 packed 的区别。 不转就喂设备,出来是噪声。
  3. 目标缓冲区给小了。 库会截断,不报错,后半段静默丢失。
自测三问(点开对答案) 1. planar 与 packed 的区别是什么? —— planar 左右声道分开存,packed 交错存(LRLRLR)。解码器多给 planar,设备常要 packed。 2. 为什么重采样不会让声音变快? —— 它按新采样率重新插值出对应数量的点,时长不变。变快是改了标签没改数据。 3. 重采样前后哪条等式必须成立? —— 样本数 ÷ 采样率相等,也就是时长不变。

相关笔记