它管三件事:采样率、采样格式(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 秒实验
- 用
av.AudioResampler把一段 44100 的音频转成 48000,数一下样本数与时长。 - 把 planar 的数据当 packed 解读,听一下是什么声音。
- 算一遍 48000 转 44100 的目标样本数,跟代码对一下。
常见误区
- 以为重采样会改变速度。 它只改每秒点数,时长不变。
- 忽略 planar 与 packed 的区别。 不转就喂设备,出来是噪声。
- 目标缓冲区给小了。 库会截断,不报错,后半段静默丢失。
自测三问(点开对答案)
1. planar 与 packed 的区别是什么? —— planar 左右声道分开存,packed 交错存(LRLRLR)。解码器多给 planar,设备常要 packed。 2. 为什么重采样不会让声音变快? —— 它按新采样率重新插值出对应数量的点,时长不变。变快是改了标签没改数据。 3. 重采样前后哪条等式必须成立? —— 样本数 ÷ 采样率相等,也就是时长不变。- ☐ (本节完,下一节 2.9 libswscale 库简介)