音频的各项指标

news2024/11/25 0:49:22

对于下面data和linesize的解释(参考下面3.4中的av_samples_alloc_array_and_samples函数说明):

1)data是通道的意思,例如双通道,data[0]代表左声道,data[1]代表右声道。

2)linesize为采样个数的最大大小字节空间

例如aac,64位,双通道,则对于交错模式最大为:linesize = 2 x 1024 x 8 = 16384。此时也是一个音频帧的大小。

对于平面模式最大为:linesize = 1024 x 8 = 8192,平面模式时会有多个平面通道,例data[0],data[1],注意,断点看时参不一定是最大大小字节空间数,此时linesize不代表什么,他只是代表单个通道的所有样本数所占的字节数。

3)额外注意,已经写入的音频文件是交错模式,而FFmpeg库默认是平面模式处理的,所以将音频文件读到内存使用FFmpeg处理时需要转成平面模式;同理FFmpeg写入文件需要转成交错模式再写入。

一 音频通道数、采样率、采样个数(样本数)、采样位数的概念

1 通道数: 个人理解,就是同时有个几个设备在进行音频的采样,这样对上面的公式更好理解,最少为1,一般通道数越多,音质越好。

2 采样频率: 也称为采样速度,定义了每秒从连续信号中提取并组成离散信号的采样个数,它用赫兹(Hz)来表示。

3 采样位数(采样格式): 既然采样频率表示每秒采样的个数,那么如何描述每个采样点呢?用什么方法独立每个采样点值的区别呢?也就是如何度量每个采样点,而这正是采样格式出现的意义。通常使用16bit(2字节),也就是2的16次方,共有65536个不同的度量值,这样采样位数越高,音频度量化的就越精细,音质同样也就越高。

简括采样位数就是,例如我1s采样了10个采样点,那么我需要区分这10个采样点,就需要给它一个范围值区分,一般以2字节16位的来保存这个值,所以既然每个采样点占2字节,那么
所有采样点的总字节=采样个数 x 其所占字节数。即10 x 2 = 20。若为双通道采样,那么就是2 x 10 x 2 = 40。

4 采样个数(样本数)(nb_samples):
采样个数就是采样的个数
对于采样频率,采样频率是一秒采样的个数,例如48000HZ,每秒采样个数为48000,44100HZ,每秒采样个数为44100。

而对于一帧音频的采样个数,AAC固定一帧采样1024个,MP3格式则为1152。
至于为何固定,下面会进行解释。

二 计算一帧音频的大小、每秒播放的音频字节大小、一帧音频的播放时长

1 一帧音频的大小(字节) = 通道数 x 采样个数 x 采样位数。例如该音频帧是FLTP格式的PCM数据,那么就是aac,所以一帧中包含1024个采样个数,并且是双声道的话,那么该音频帧包含的数据量是 2 x 1024 x 4 = 8192字节。
若格式改成AV_SAMPLE_FMT,那那么采样位数是64位8字节,数据量为 2 x 1024 x 8 = 16384字节。

2 每秒播放的音频字节大小(字节) = 通道数 x 采样个数 x 采样位数。公式是一样的,但是由于求的是每秒的数据量而不是一帧的数据量,所以我们需要知道它的采样频率。 例如当采样频率为48kHZ时,一秒包含48k个采样个数而不是1024个,同样是双声道,FLTP格式,那么每秒的数据量是 2 x 48000 x 4 = 384000字节。

3 一帧音频的播放时长
以采样率44100HZ来计算,每秒44100个sample,而正常一帧为1024个sample,由于比是相等的,可知每帧播放时间/1024 = 1000ms/44100,得到每帧播放时间=1024*1000/44100 = 23.2ms(更精确的是23.21995464852608)。

或者用另一种方式去理解公式,1s显示的帧数 = 44100 / 1024 = 43.06640625帧。所以每一帧的播放时长 = 1s / 43.06640625 = 1000ms / 43.06640625 = 23.21995464852607ms。和上面的公式一样(浮点数尾部运算存在极小误差是正常)。所以转换一下公式:
一帧播放时间(毫秒) = 1000ms / (44100 / 1024) = 1000ms * 1024 / 44100 = 23.2ms(更精确的是23.21995464852607)。

所以最终都是转化成下面的公式:
一帧播放时间(毫秒) = nb_sample样本数 * 1000 / 采样率 。

播放时长的精度是否可以舍弃呢?
答:不能。

例如当采样频率为44.1kHZ:

1)一帧播放时间(毫秒) = nb_sample样本数 * 1000 / 采样率 = 1024 * 1000 / 44100 = 23.21995464852608ms -> 约等于23.2ms,精确损失了0.011995464852608ms,如果累计10万帧,误差 > 1199毫秒,如果有视频一起的就会出现音视频同步的问题,如果按着23.2msm去计算pts(0 23.2 46.4 …)就会有累积误差
这里播放10万个音频帧大概需要的时长:((23.21995464852608ms x 100000) / 1000)s / 60 = 38.699924min。乘以10万得到ms,除以1000单位变成秒,除以60单位变成分钟。

采样频率为48kHZ时的一帧播放时长:

2)1024 * 1000 / 48000 = 21.33333333333ms。同理,精度不能舍弃。

以上是AAC格式的播放时长。

下面是MP3的一音频帧的播放时长:

  • 1)44.1kHZ,一帧播放时间(毫秒) = nb_sample样本数 * 1000 / 采样率 = 1152 * 1000 / 44100 = 26.1224489795918367ms -> 约等于26.2ms。
  • 2)48kHZ,一帧播放时间(毫秒) = nb_sample样本数 * 1000 / 采样率 = 1152 * 1000 / 48000 = 24ms,刚好能整除。

解释为何AAC和MP3为何一帧固定采样个数。
从我自己的理解来看,固定AAC为1024,MP3为1152肯定是有道理的,从一帧音频帧的播放时长中就可以看出,范围在21ms,24ms,26ms范围左右,而视频一帧的时长一般是40ms,人体对图片变化的感知也在20-60ms内感知良好,所以个人认为采样数固定,是在考虑人眼,与音视频同步的方便程度,音频压缩的质量等方面因素后,最终确定下来的采样数。

三 音频重采样

3.1 什么是重采样
将音频三元组(采样率,采样大小和通道数)其中任意一个值发生改变就称为重采样, 例如48000/32/2 转成 44100/16/2。

3.2 为什么要重采样

  • 1)从设备采集的音频数据与编码器要求的数据不一致。
  • 2)扬声器要求的音频数据与要播放的音频数据不一致。
  • 3)更方便运算(回音消除须使用单声道,需要先转换)。

3.3 重采样的步骤

  • 1)创建重采样上下文。
  • 2)设置参数。
  • 3)初始化重采样。
  • 4)进行重采样。

3.4 几个重要的API

  • swr_alloc_set_opts(创建上下文,设置参数)。
  • swr_init(初始化)。
  • av_samples_alloc_array_and_samples(给输入源分配内存空间,其中参1为输入源,参2为采样个数的最大大小字节空间(src_linesize),例如aac,64位,双通道,则对于交错模式最大为:src_linesize = 2x1024x8 = 16384,对于平面模式最大为:src_linesize = 1024x8 = 8192,平面模式时会有多个平面通道,例data[0],data[1],注意,断点看时参不一定是最大大小字节空间数,这就是对于参2行大小的解释。参345就是参2对应的变量,参6是内存对齐,赋0即可)。
  • swr_convert(具体音频帧转换)。
  • swr_free(释放上下文占用资源)。

在这里插入图片描述

3.5 重采样时,输出的样本数怎么求
进行重采样时,输入和输出时间是需要相等的。所以我们可以根据上面的公式去求出输出的样本数即采样点。
在这里插入图片描述

根据上面一帧音频的播放时长公式有,输入输出都去掉1000,有下面的公式:
在这里插入图片描述

可以看到,上面公式的规律:

  • 1)当高采样频率转低采样频率,在输入的参数一定即输入的样本数和输入采样频率一定时,输出的样本数随着低采样率而变低。
  • 2)当低采样频率转高采样频率,在输入的参数一定即输入的样本数和输入采样频率一定时,输出的样本数随着高采样频率而变高。
  • 3)并且注意,计算输出的样本数后,如果是一个浮点数,将对其采用向上取整。
    即若计算出来的out_count=940.8,那么向上取整后为941。
    代码的实现常常利用av_rescale_rnd:
    它的作用是计算 “a * b / c” 的值并分五种方式来取整。a,b,c分别代表参数123,参4是取整的方式,例如这里的AV_ROUND_UP。
 
  1. //AV_ROUND_UP代表向上取整

  2. dst_nb_samples = av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);

在这里插入图片描述

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

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

相关文章

ChatGPT全栈开发实战:从需求分析到数据可视化,一站式指南助你快速构建全面应用

文章目录 序章:PDF版下载第一章:Java后端开发1.需求分析1.1 项目分析1.2 开发计划1.3 风险评估1.4 需求增强1.5 需求转情景 2.生成代码2.1 解析文件2.2 数据结构2.3 算法策略2.4 异步处理 3.Bug修改3.1 逻辑错误3.2 性能问题3.3 资源泄露3.4 死锁问题3.5…

MySQL之存储过程和存储函数

1. 存储过程概念 能够将完成特定功能的SQL指令进行封装(SQL指令集),编译之后存储在数据库服务器上,并且为之取一个名字,客户端可以通过名字直接调用这个SQL指令集,获取执行结果。 2. 存储过程优缺点 2.1 优点 (1&am…

【SpringCloud】二、服务注册发现Eureka与负载均衡Ribbon

文章目录 一、Eureka1、服务提供者与消费者2、Eureka原理分析3、搭建Eureka4、服务注册5、模拟多服务实例启动6、服务的发现 二、Ribbon1、负载均衡的原理2、源码分析3、负载均衡策略4、饥饿加载 一、Eureka 1、服务提供者与消费者 服务提供者:一次业务中&#xf…

Elastic-Job原理

Elastic-Job作业类型创建任务并执行 :启动流程弹性分布式实现 Elastic-Job elastic-job(quartz的扩展)使用了quartz的调度机制,内部原理一致,使用注册中心(zookeeper)替换了quartz的jdbc数据存储方式,支持…

ubuntu22.04切换回Xorg使用flameshot截图的问题

在ubuntu20.04时使用flameshot一切正常. 升级到ubuntu22.04之后,发现flameshot不能使用快捷键区域截图了,这个就很不方便. 在网上找了一圈后先是修改文件 /etc/gdm3/custom.conf将里面的 #WaylandEnableflase改成 WaylandEnablefalse即配置为不使用Wayland.然后重启系统,后…

动态通讯录实现(C语言)

目录 前言: 一:单个节点的设计和主逻辑 结点设计 主逻辑 二:接口实现 (1)生成一个新的结点 (2)增加信息 (3)打印信息 (4)查找 (5)删除信息 (6)修改信息 (7)排序 插入排序 快速排序 (8)已有数据读取 (9)更新数据录入 三&…

C语言复习笔记3

1.标识符常量和宏函数&#xff08;宏函数是简单替换所以需要把括号加到位&#xff09; #include<stdio.h>#define MAX 1000//标识符常量 #define num 10 //#define SUM(X,Y) XY //不对 #define SUM(X,Y) ((X)(Y))int max(int a, int b) {return a>b?a:b; }int main(…

系列八、vue配置请求

一、vue2配置请求转发 config/index.js proxyTable配置后端的请求地址 proxyTable: {/: {target: "http://localhost:9000", // 后端服务器地址changeOrigin: true,pathRewrite: {^/: }} }, 注意事项&#xff1a;vue2中不像大多数教程里边讲的那样&#xff0c;直接…

Apache NiFi:实时数据流处理的可视化利器【上进小菜猪大数据系列】

上进小菜猪&#xff0c;沈工大软件工程专业&#xff0c;爱好敲代码&#xff0c;持续输出干货。欢迎订阅本专栏&#xff01; Apache NiFi是一个强大的、可扩展的开源数据流处理工具&#xff0c;广泛应用于大数据领域。本文将介绍Apache NiFi的核心概念和架构&#xff0c;并提供…

路由守卫的几种方式-M

vue的路由 Vue-router是Vue.js官方的路由插件。vue的单页面应用是基于路由和组件的&#xff0c;路由用于设定访问路径&#xff0c;并将路径和组件映射起来。传统的页面应用&#xff0c;是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中&#xff0c;则是路径之…

C# | KMeans聚类算法的实现,轻松将数据点分组成具有相似特征的簇

C# KMeans聚类算法的实现 文章目录 C# KMeans聚类算法的实现前言示例代码实现思路测试结果结束语 前言 本章分享一下如何使用C#实现KMeans算法。在讲解代码前先清晰两个小问题&#xff1a; 什么是聚类? 聚类是将数据点根据其相似性分组的过程&#xff0c;它有很多的应用场景&…

章节1:信息收集

章节1:信息收集 1 信息收集概览 01 为什么要做信息收集&#xff1f; 渗透测试的流程 确定目标 信息收集 漏洞扫描 漏洞利用 形成报告 信息收集包括的内容 域名信息、IP段、开放的端口、网站架构、文件目录结构、软件版本、WAF、旁站、C段… 分类 域名相关信息IP相关…

Redis缓存数据库(四)

目录 一、概述 1、Redis Sentinel 1.1、docker配置Redis Sentinel环境 2、Redis存储方案 2.1、哈希链 2.2、哈希环 3、Redis分区(Partitioning) 4、Redis面试题 一、概述 1、Redis Sentinel Redis Sentinel为Redis提供了高可用解决方案。实际上这意味着使用Sentinel…

Java 与排序算法(1):冒泡排序

一、冒泡排序 冒泡排序&#xff08;Bubble Sort&#xff09;是一种简单的排序算法&#xff0c;它的基本思想是通过不断交换相邻两个元素的位置&#xff0c;使得较大的元素逐渐往后移动&#xff0c;直到最后一个元素为止。冒泡排序的时间复杂度为 O ( n 2 ) O(n^2) O(n2)&…

《Kali渗透基础》02. 基本工具

kali渗透 1&#xff1a;基本工具1.1&#xff1a;NetCat1.1.1&#xff1a;命令参数1.1.2&#xff1a;示例 1.2&#xff1a;NCat1.2.1&#xff1a;命令参数1.2.2&#xff1a;示例 1.3&#xff1a;WireShark1.4&#xff1a;TCPdump1.4.1&#xff1a;命令参数1.4.2&#xff1a;示例…

C语言——函数

目录 1. 函数基本用法1.1 定义和三要素1.2 函数的声明和定义1.2.1 函数声明1.2.2 函数定义格式 1.3 函数调用1.4 函数传参1.4.1 值传递1.4.2 地址传递1.4.3 数组传递 1.5 函数和栈区 2. 开辟堆空间2.1 堆的概念2.2.malloc函数2.2.1 定义2.2.2 用法 2.3 free()函数定义注意&…

随机数发生器设计(一)

1 随机数发生器设计概述 密码行业的随机数发生器总体框架标准为GM/T 0103。随机数发生器可以分为硬件随机数发生器和软件随机数发生器。 硬件随机数发生器一般以组成部件的形式集成在安全芯片的内部&#xff0c;或者随机数发生器本身就是安全芯片。考虑到随机数发生器是密码产…

ChatGPT 能自己跑代码了!

公众号关注 “GitHubDaily” 设为 “星标”&#xff0c;每天带你逛 GitHub&#xff01; time leap, sci-fi, photorealistic, --niji 5 --ar 3:2 --s 1000 自 ChatGPT 发布以来&#xff0c;各行各业对其能力探索的举措一直没有停止。 很多大厂纷纷跟进&#xff0c;竞相推出自研…

Springboot +spring security,登录用户数据获取

一.简介 前面章节学习了登录表单的配置并且对源码进行了简单的分析&#xff0c;现在有个问题了&#xff0c;既然用户登录了&#xff0c;那么如何在接口中获取用户信息呢。这篇文章就来看下这个问题&#xff0c;代码中获取登录用户信息。 二.创建项目 如何创建一个SpringSecu…

笔记:BLIP源码之(1)数据集预处理【仅考虑Image-Text Retrieval on COCO】

BLIP&#xff1a;Bootstrapping Language-Image Pre-training for Unified Vision-Language Understanding and Generat 论文的两个贡献如下&#xff1a; 从模型的角度&#xff1a;提出了 Encoder-Decoder (MED) 的多模态混合 An MED can operate either as a unimodal encode…