1重采样

1.1 什么是重采样

所谓的重采样,就是改变⾳频的采样率、sample format、声道数等参数,使之按照我们期望的参数输出。

1.2 为什么要重采样

为什么要重采样?当然是原有的⾳频参数不满⾜我们的需求,⽐如在FFmpeg解码⾳频的时候,不同的⾳源有不同的格式,采样率等,在解码后的数据中的这些参数也会不⼀致(最新FFmpeg 解码⾳频后,⾳频格

式为AV_SAMPLE_FMT_FLTP,这个参数应该是⼀致的),如果我们接下来需要使⽤解码后的⾳频数据做其他操作,⽽这些参数的不⼀致导致会有很多额外⼯作,此时直接对其进⾏重采样,获取我们制定的⾳频参数,这样就会⽅便很多。

再⽐如在将⾳频进⾏SDL播放时候,因为当前的SDL2.0不⽀持planar格式,也不⽀持浮点型的,⽽最新的FFMPEG 16年会将⾳频解码为AV_SAMPLE_FMT_FLTP格式,因此此时就需要我们对其重采样,使之可以在SDL2.0上进⾏播放。

2 对应参数解析

2.1 采样率

采样设备每秒抽取样本的次数

2.2采样格式及量化精度(位宽)

每种⾳频格式有不同的量化精度(位宽),位数越多,表示值就越精确,声⾳表现⾃然就越精准。FFMpeg中⾳频格式有以下⼏种,每种格式有其占⽤的字节数信息(libavutil/samplefmt.h):

enum AVSampleFormat {
AV_SAMPLE_FMT_NONE = -1,
AV_SAMPLE_FMT_U8, ///< unsigned 8 bits
AV_SAMPLE_FMT_S16, ///< signed 16 bits
AV_SAMPLE_FMT_S32, ///< signed 32 bits
AV_SAMPLE_FMT_FLT, ///< float
AV_SAMPLE_FMT_DBL, ///< double
AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar
AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar
AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar
AV_SAMPLE_FMT_FLTP, ///< float, planar
AV_SAMPLE_FMT_DBLP, ///< double, planar
AV_SAMPLE_FMT_S64, ///< signed 64 bits
AV_SAMPLE_FMT_S64P, ///< signed 64 bits, planar
AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically
};

2.3 分⽚(plane)和打包(packed)

以双声道为例,带P(plane)的数据格式在存储时,其左声道和右声道的数据是分开存储的,左声道的数据存储在data[0],右声道的数据存储在data[1],每个声道的所占⽤的字节数为linesize[0]和linesize[1];

不带P(packed)的⾳频数据在存储时,是按照LRLRLR...的格式交替存储在data[0]中,linesize[0]表示总的数据量。

2.4 声道分布(channel_layout)

声道分布在FFmpeg\libavutil\channel_layout.h中有定义,⼀般来说⽤的⽐较多的是AV_CH_LAYOUT_STEREO(双声道)和AV_CH_LAYOUT_SURROUND(三声道),这两者的定义如下:

#define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT)
#define AV_CH_LAYOUT_SURROUND (AV_CH_LAYOUT_STEREO | AV_CH_FRONT_CENTER)

2.5 ⾳频帧的数据量计算

⼀帧⾳频的数据量(字节)=channel数 * nb_samples样本数 * 每个样本占⽤的字节数

如果该⾳频帧是FLTP格式的PCM数据,包含1024个样本,双声道,那么该⾳频帧包含的⾳频数据量是210244=8192字节。

AV_SAMPLE_FMT_DBL : 210248 = 16384

2.6 ⾳频播放时间计算

以采样率44100Hz来计算,每秒44100个sample,⽽正常⼀帧为1024个sample,可知每帧播放时间/1024=1000ms/44100,得到每帧播放时间=1024*1000/44100=23.2ms (更精确的是23.21995464852608)。

⼀帧播放时间(毫秒) = nb_samples样本数 *1000/采样率 =

(1)1024*1000/44100=23.21995464852608ms ->约等于 23.2ms,精度损失了0.011995464852608ms,如果累计10万帧,误差>1199毫秒,如果有视频⼀起的就会有⾳视频同步的问题。 如果按着23.2去计算pts(0 23.2 46.4 )就会有累积误差。

(2)1024*1000/48000=21.33333333333333ms

3 FFmpeg重采样API

分配⾳频重采样的上下⽂

struct SwrContext *swr_alloc(void);

当设置好相关的参数后,使⽤此函数来初始化SwrContext结构体

int swr_init(struct SwrContext *s);

分配SwrContext并设置/重置常⽤的参数。

struct SwrContext* swr_alloc_set_opts(struct SwrContext* s, // ⾳频重采样上下⽂
int64_t out_ch_layout, // 输出的layout, 如:5.1声道
enum AVSampleFormat out_sample_fmt, // 输出的采样格式。Float, S16,⼀般选⽤是s16 绝⼤部分声卡⽀持
int out_sample_rate, //输出采样率
int64_t in_ch_layout, // 输⼊的layout
enum AVSampleFormat in_sample_fmt, // 输⼊的采样格式
int in_sample_rate, // 输⼊的采样率
int log_offset, // ⽇志相关,不⽤管先,直接为0
void* log_ctx // ⽇志相关,不⽤管先,直接为NULL
);

将输⼊的⾳频按照定义的参数进⾏转换并输出

int swr_convert(struct SwrContext* s, // ⾳频重采样的上下⽂
uint8_t** out, // 输出的指针。传递的输出的数组
int out_count, //输出的样本数量,不是字节数。单通道的样本数量。
const uint8_t** in, //输⼊的数组,AVFrame解码出来的DATA
int in_count // 输⼊的单通道的样本数量。
);

in和in_count可以设置为0,以最后刷新最后⼏个样本。

释放掉SwrContext结构体并将此结构体置为NULL;

void swr_free(struct SwrContext **s);

⾳频重采样,采样格式转换和混合库。与lswr的交互是通过SwrContext完成的,SwrContext被分配给swr_alloc()或

swr_alloc_set_opts()。 它是不透明的,所以所有参数必须使⽤AVOptions API设置。为了使⽤lswr,你需要做的第⼀件事就是分配SwrContext。 这可以使⽤swr_alloc()或 swr_alloc_set_opts()来完成。 如果您使⽤前者,则必须通过AVOptions API设置选项。 后⼀个函数提供了相同的功能,但它允许您在同⼀语句中设置⼀些常⽤选项。

例如,以下代码将设置从平⾯浮动样本格式到交织的带符号16位整数的转换,从48kHz到44.1kHz的下采

样,以及从5.1声道到⽴体声的下混合(使⽤默认混合矩阵)。 这是使⽤swr_alloc()函数。

SwrContext * swr = swr_alloc();
av_opt_set_channel_layout(swr, "in_channel_layout", AV_CH_LAYOUT_5POINT1, 0);
av_opt_set_channel_layout(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(swr, "in_sample_rate", 48000, 0);
av_opt_set_int(swr, "out_sample_rate", 44100, 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);

同样的⼯作也可以使⽤swr_alloc_set_opts():

SwrContext * swr = swr_alloc_set_opts(NULL, // we're allocating a new context
AV_CH_LAYOUT_STEREO, // out_ch_layout
AV_SAMPLE_FMT_S16, // out_sample_fmt
44100, // out_sample_rate
AV_CH_LAYOUT_5POINT1, // in_ch_layout
AV_SAMPLE_FMT_FLTP, // in_sample_fmt
48000, // in_sample_rate
0, // log_offset
NULL); // log_ctx

⼀旦设置了所有值,它必须⽤swr_init()初始化。 如果需要更改转换参数,可以使⽤AVOptions来更改参数,如上⾯第⼀个例⼦所述; 或者使⽤swr_alloc_set_opts(),但是第⼀个参数是分配的上下⽂。 您必须再次调⽤swr_init()。⼀旦设置了所有值,它必须⽤swr_init()初始化。 如果需要更改转换参数,可以使⽤AVOptions来更改参数,如上⾯第⼀个例⼦所述; 或者使⽤swr_alloc_set_opts(),但是第⼀个参数是分配的上下⽂。 您必须再次调⽤swr_init()。

转换本身通过重复调⽤swr_convert()来完成。 请注意,如果提供的输出空间不⾜或采样率转换完成后,样本可能会在swr中缓冲,这需要“未来”样本。 可以随时通过使⽤swr_convert()(in_count可以设置为0)来检索不需要将来输⼊的样本。 在转换结束时,可以通过调⽤具有NULL in和in incount的swr_convert()来刷新重采样缓冲区。

4 go代码

moonfdd/ffmpeg-go

音视频八股文(11)-- ffmpeg 音频重采样的更多相关文章

  1. FFMpeg音频重采样和视频格式转

    一.视频像素和尺寸转换函数 1.sws_getContext : 像素格式上下文  --------------->多副图像(多路视频)进行转换同时显示 2.struct SwsContext  ...

  2. Android 音视频深入 十一 FFmpeg和AudioTrack播放声音(附源码下载)

    项目地址,求starhttps://github.com/979451341/AudioVideoStudyCodeTwo/tree/master/FFmpeg%E6%92%AD%E6%94%BE%E ...

  3. 音视频】5.ffmpeg命令分类与使用

    GT其实平时也有一些处理音视频的个人或者亲人需求,熟练使用ffmpeg之后也不要借助图示化软件,一个命令基本可以搞定 G: 熟练使用ffmpeg命令!T :不要死记硬背,看一遍,自己找下规律,敲一遍, ...

  4. 音视频处理之FFmpeg封装格式20180510

    一.FFMPEG的封装格式转换器(无编解码) 1.封装格式转换 所谓的封装格式转换,就是在AVI,FLV,MKV,MP4这些格式之间转换(对应.avi,.flv,.mkv,.mp4文件). 需要注意的 ...

  5. 音视频处理之FFmpeg+SDL视频播放器20180409

    一.FFmpeg视频解码器 1.视频解码知识 1).纯净的视频解码流程 压缩编码数据->像素数据. 例如解码H.264,就是“H.264码流->YUV”. 2).一般的视频解码流程 视频码 ...

  6. Android 音视频深入 九 FFmpeg解码视频生成yuv文件(附源码下载)

    项目地址,求star https://github.com/979451341/Audio-and-video-learning-materials/tree/master/FFmpeg(MP4%E8 ...

  7. 音视频处理之FFmpeg+SDL+MFC视频播放器20180411

    一.FFmpeg+SDL+MFC视频播放器 1.MFC知识 1).创建MFC工程的方法 打开VC++ 文件->新建->项目->MFC应用程序 应用程序类型->基于对话框 取消勾 ...

  8. 音视频处理之FFmpeg程序的介绍与使用20180302

    一.FFMPEG程序介绍与使用 主要介绍一下ffmpeg工程包含的三个exe的使用方法. 1. FFMPEG程序介绍 1.1.下载 ffmpeg的官方网站是:http://ffmpeg.org/ 下载 ...

  9. Android 音视频深入 十 FFmpeg给视频加特效(附源码下载)

    项目地址,求starhttps://github.com/979451341/Audio-and-video-learning-materials/tree/master/FFmpeg(AVfilte ...

  10. Android音视频之AudioTrack播放音频(二)

    前一篇讲了如何录制wav音频文件,本篇就来讲讲如何播放wav文件,这里就是使用AudioTrack来播放音频,确切的说是播放pcm格式数据,使用AudioTrack播放也没什么难度,主要就是将数据写入 ...

随机推荐

  1. spring事件发布与监听

    一.组成部分 spring的事件监听有三个部分组成,事件(ApplicationEvent).监听器(ApplicationListener)和事件发布操作. 二.具体实现 事件 事件对象就是一个简单 ...

  2. win10安装node-red遇到的问题及解决方法

    1.安装失败 原因:没有管理员权限,需要用powershell(管理员)来安装 2.安装完成后运行失败 出现下面的情况 PS C:\WINDOWS\system32> node-rednode- ...

  3. .net 学习必须学的书籍,新手必备,老手升级必须品!!!

    最近看到一篇文章 是关于学习.net的数据 给大家看看. <<第一篇:>> 人身为一个典型的技术宅,平时看了一些技术书籍.算不上是"博览群书",但也涉猎不少 ...

  4. vue 作者在2022-2-7起宣布 vue3 正式作为默认版本

    vue 作者在2022-2-7起宣布 vue3 正式作为默认版本 vue 作者尤雨溪在知乎上发布一篇文章,宣布 Vue3 将在 2022 年 2 月 7 日 成为新的默认版本! 并且还在文章中做出了一 ...

  5. 《MySQL是怎样运行的》第二章小结

  6. Android笔记--添加联系人

    添加联系人(将联系人信息添加到手机的通讯录里面) 方式一:使用ContentResolver方法写入对象,每次一个字段 新创建一个需要加入通讯录的对象(我这里写的比较简单,并不是通讯录的标准格式,就是 ...

  7. Python学习笔记--第二阶段啦

    初识对象 示例: 类的成员方法 上图中的self必须填写!!! 示例: 类和对象 有c和c++语言基础的话,就会发现其实是一样的道理,只是实现代码有差异 构造方法(init) 示例: 注意: 其他内置 ...

  8. Android 音视频采集那些事

    音视频采集 在整个音视频处理的过程中,位于发送端的音视频采集工作无疑是整个音视频链路的开始.在 Android 或者 IOS 上都有相关的硬件设备--Camera 和麦克风作为输入源.本章我们来分析如 ...

  9. DevOps|研发效能不是老板工程,是开发者服务

    有人说研发效能是老板工程.不是的,研发效能不是老板工程,它不直接服务于老板(虽然老板可能看一些报表),反而是服务于广大产研运(产品+研发+质量+运维)的同学,所以有的公司也把研发效能叫做基础中台,平台 ...

  10. Linux环境下使用jsoncpp

    目录 1. 下载jsoncpp 2. 生成静态库libjsoncpp.a 3. 复制相关文件至/usr/local下(方便编程) 4. CMakeList.txt编写(需要新增的) 1. 下载json ...