音视频八股文(11)-- ffmpeg 音频重采样

news2025/1/9 12:33:07

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

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/515277.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从头开始学习Python接口自动化测试:编写测试用例,执行测试以及生成测试报告

Python接口自动化测试详解 随着Web服务和移动应用不断增多&#xff0c;以及对API和微服务的需求不断增加&#xff0c;API已成为现代应用程序中必不可少的组件。自动化测试框架可以大大简化API测试的过程&#xff0c;并确保其正确性和稳定性。Python是一种非常流行的编程语言&a…

洛谷B2100 同行列对角线的格

同行列对角线的格 题目描述 输入三个自然数 N N N&#xff0c; i i i&#xff0c; j j j&#xff08; 1 ≤ i ≤ n 1 \le i \le n 1≤i≤n&#xff0c; 1 ≤ j ≤ n 1 \le j \le n 1≤j≤n&#xff09;&#xff0c;输出在一个 N N N \times N NN 格的棋盘中&#xff08;行…

西门子1200PLC如何在威纶通HMI上进行时间显示

先生成定时器DB&#xff0c;然后在引脚绑定变量&#xff0c;在西门子PLC中&#xff0c;DINT和TIME之间可以隐含转化。 第一种方法&#xff1a;触摸屏元件设置成DINT类型 数值元件资料格式为32-bit Signed&#xff0c;对应PLC中即为DINT类型。小数点以下没有位数。这是我们测试…

Android RecyclerView实现侧滑删除,附 Demo

距上次写博客有半年多了&#xff0c;回忆起来都觉得不可思议&#xff0c;中间也想憋俩大招&#xff0c;总是被耽误&#xff0c;这俩月忙完之后&#xff0c;终于空下来了&#xff0c;恰好新项目我和UI俩人商量一下&#xff0c;用MD来实现app。中间有个需求是RecyclerView中侧滑显…

ch06-Pytorch的正则化与归一化

ch06-Pytorch的正则化与归一化 0.引言1.weight decay 和 dropout1.1.Regularization1.2.Dropout 2.Normalization2.1.Batch Normalization2.2.Batch Normalization in PyTorch2.2.1.nn.BatchNorm1d()2.2.2.nn.BatchNorm2d()2.2.3.nn.BatchNorm3d() 2.3.其他常见的Normalization…

java servlet jsp 农产品价格信息搜集系统 python开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 jsp 农产品价格信息搜集系统 python是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助 系统采用 serlvetdaobean 模式开发 利用python 进行网站爬取 &#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开…

Redis常见命令有哪些?怎么使用?

一、概述&#xff1a; 在了解Redis命令之前&#xff0c;我们要先了解Redis的数据结构&#xff0c;Redis是NoSQL数据库&#xff0c;采用了json存储模式&#xff0c;比MySQL等关系数据库更易于扩展&#xff0c;拥有丰富的数据类型&#xff0c;分基本类型与特殊类型。基本类型包括…

【Linux】网络---->套接字编程(TCP)

套接字编程TCP TCP的编程流程TCP的接口TCP的代码&#xff08;单线程、多进程、多线程代码&#xff09;单线程多进程多线程 TCP的编程流程 TCP的编程流程&#xff1a;大致可以分为五个过程&#xff0c;分别是准备过程、连接建立过程、获取新连接过程、消息收发过程和断开过程。 …

【youcans的深度学习 07】PyTorch入门教程:张量的基本操作 2

欢迎关注『youcans的深度学习』系列&#xff0c;持续更新中… 【youcans的深度学习 01】安装环境之 miniconda 【youcans的深度学习 02】PyTorch CPU版本安装与环境配置 【youcans的深度学习 03】PyTorch CPU版本安装与环境配置 【youcans的深度学习 04】PyTorch入门教程&#…

面向对象程序设计概述

&#x1f9d1;‍&#x1f4bb;CSDN主页&#xff1a;夏志121的主页 &#x1f4cb;专栏地址&#xff1a;Java核心技术专栏 目录 一、类 二、对象 三、识别类 四、类之间的关系 面向对象程序设计&#xff08;Object-Oriented Programming,OOP)是当今的主流程序设计范型&#x…

线段树详解

目录 线段树的概念 线段树的实现 线段树的存储 需要4n大小的数组 线段树的区间是确定的 线段树的难点在于lazy操作 代码样例 线段树的概念 线段树&#xff08;Segment Tree&#xff09;是一种平衡二叉树&#xff0c;用于解决区间查询问题。它将一个区间划分成若干个子区…

Android 车载值不值得入手学?

前言 随着智能车的不断普及和智能化程度的提高&#xff0c;车载系统也在逐步升级和演进&#xff0c;越来越多的汽车厂商开始推出采用Android系统的车载设备&#xff0c;这为Android车载开发提供了广泛的市场需求。 其次&#xff0c;随着人工智能技术的发展和应用&#xff0c;…

Linux : 安装源码包

安装源码包之前我们要准备好yum环境&#xff0c;或者使用默认上网下载的yum仓库或者查看&#xff1a;Linux&#xff1a;rpm查询安装 && yum安装_鲍海超的博客-CSDN博客 准备离线yum仓库 &#xff0c;默认的需要在有网环境下才能去网上下载 其次就是安装 gcc make 准…

UDP协议 sendto 和 recvfrom 浅析与示例

UDP&#xff08;user datagram protocol&#xff09;用户数据报协议&#xff0c;属于传输层。 UDP是面向非连接的协议&#xff0c;它不与对方建立连接&#xff0c;而是直接把数据报发给对方。UDP无需建立类如三次握手的连接&#xff0c;使得通信效率很高。因此UDP适用于一次传…

Kyligence Zen 一站式指标平台体验——“绝对实力”的指标分析和管理工具——入门体验评测

&#x1f996;欢迎观阅本本篇文章&#xff0c;我是Sam9029 文章目录 前言Kyligence Zen 是什么Kyligence Zen 能做什么Kyligence Zen 优势在何处 正文注册账号平台功能模块介绍指标图表新建指标指标模板 目标仪表盘数据设置 实际业务体验---使用官网数据范例使用流程归因分析指…

MySQL --- 多表设计

关于单表的操作(包括单表的设计、单表的增删改查操作)我们就已经学习完了。接下来我们就要来学习多表的操作&#xff0c;首先来学习多表的设计。 项目开发中&#xff0c;在进行数据库表结构设计时&#xff0c;会根据业务需求及业务模块之间的关系&#xff0c;分析并设计表结构…

ChatGPT-4怎么对接-ChatGPT-4强化升级了哪些功能

ChatGPT-4怎么使用 使用ChatGPT-4&#xff0c;需要通过OpenAI的API接口来对接ChatGPT-4。OpenAI是一个人工智能公司&#xff0c;为开发者提供多个API接口&#xff0c;包括自然语言处理&#xff0c;图像处理等。ChatGPT-4是OpenAI开发的最新版本的聊天式对话模型&#xff0c;可…

React antd Form item「受控组件与非受控组件」子组件 defaultValue 不生效等问题总结

一、为什么 Form.Item 下的子组件 defaultValue 不生效&#xff1f; 当你为 Form.Item 设置 name 属性后&#xff0c;子组件会转为受控模式。因而 defaultValue 不会生效。你需要在 Form 上通过 initialValues 设置默认值。name 字段名&#xff0c;支持数组 类型&#xff1a;N…

2.存储器层次系统

存储器 随机访问存储器 RAM&#xff08;随机存储器&#xff09; SRAM 双稳态触发器&#xff0c;有电就保持不变&#xff0c;干扰消除后时会恢复到稳定值&#xff0c;晶体管多因此密集度低 DRAM 每个位存储为对一个电容的充电&#xff0c;对干扰敏感&#xff0c;漏电所以需要刷…

静态数码管

静态数码管 1、简介工作方式数码管静态显示原理 2、硬件设计3、软件设计4、 1、简介 一般共阳极数码管更为常用 好处&#xff1a;将驱动数码管的工作交到公共端&#xff08;一般接驱动电源&#xff09;&#xff0c;加大驱动电源的功率自然要比加大IC芯片I/O口的驱动电流简单许…