FFmpeg音频解码-音频可视化

article/2025/10/23 2:18:44

        最近在做一个音频可视化的业务,网上有Java层的实现方法,但是业务需要用C实现,从原理出发其实很简单,先对音频进行解码,再计算分贝。这比把大象放进冰箱还简单。本文从音频可视化的业务为依托,以FFmpeg为基础实现解码,计算,绘制。

一、解码流程

        解码流程大致分为以下三个部分,以FFmpge源码下的ffmpeg\doc\examples\decode_audio.c为参考。

1.1、解析音频信息

        avformat_open_input负责打开需要解码的音频文件,如果文件打开成功的话会初始化AVFormatContext,avformat_find_stream_info开启音频流遍历,av_find_best_stream找到最合适解析数据的帧,解析完后我们可以通过返回的AVStream获取到我们需要用的解码器id、通道数、采样率、位深、音频时长、数据排列结构。拿到解码器id我们通过解码器id获取解码器avcodec_find_decoder,有些解码器并不是FFmpeg内置的,所以有些需要在编译时就加进去,我之前的文章也有讲过AAC和MP3编解码第三方库。如果找到了解码器,下一步就是avcodec_alloc_context3对解码器上下文AVCodecContext进行初始化,初始化完成后avcodec_parameters_to_context将解码器参数设置给解码器上下文,例如通道数,采样率,采样位深等等信息。如果未设置可能会出现invalid argument的错误,导致后续无法继续。最后通过avcodec_open2打开解码器,如果打开成功我们就可以开始对音频数据进行读取。

1.2、从原始数据packet到frame

        我们解码的目的就是为了拿到底层播放器能播的PCM数据。既然我们已经获取到了解码器,那么下面就是一帧一帧的读取解码器解析出来的数据。首先我们需要av_packet_alloc初始化包对象AVPacket,包对象是未解码的数据,原始的音频数据被打包成一个一个的包,然后送给解码器去把包打开,变成帧对象,所以我们又需要通过av_frame_alloc初始化帧对象AVFrame,把它送给解码器,解码器用数据把它装满后返回回来。av_read_frame就是从打开的文件读取一个数据包,对于AAC/MP3来说他们是未解码的压缩数据。然后通过avcodec_send_packet把数据包送给解码器,返回0表示解码器解包成功,接下来就可以从解码器读数据,这时的数据就是以帧的形式存在,avcodec_receive_frame读取帧,因为一个包可能有几个帧,所以需要循环读取,当avcodec_receive_frame返回0时表示读取成功,可以进行下一步操作,当返回值是AVERROR_EOF表示读取完毕可以跳出循环了,返回AVERROR(EAGAIN)表示解码器输出已经是不可用的状态,必须向解码器送新包来激活输出,同样也可以跳出读取和解析帧的循环。

1.3、从frame到PCM byte

        我们的PCM数据就在frame的data里,但是我们并不能直接拿,首先我们得知道拿多少,怎么拿。拿多少取决于采样位数,通道数和帧里面的样本数。例如44100HZ的话一秒就有44100*通道数个样本。那一个帧里面就一共有 采样位数/8*通道数*样本数个字节数据。怎么拿取决于音频数据的存储方式,音频存储方式有两种:

  • planar:音频左右声道数据分开放置,数据存储格式为

        data[0]:LLLLLLLLLLLLLLLL

        data[1]:RRRRRRRRRRRRR

  • packet:音频左右声道数据交替放置,数据存储格式为

        data[0]:LRLRLRLRLRLRLRLR

        最终拿到的数据都是以LRLRLRLRLR的方式排列,到这里我们可以把它送给播放器或者在送给播放器前加一些我们自己的音频算法,全部解码完成后,最后记得释放掉相关资源。在这里我们简单点,计算它的分贝,实现音频可视化的功能。

二、分贝计算

        我们音频的分贝往往不需要计算每一个样本的分贝数,第一计算密度太大超出人眼感知对显示没有益处,二是计算量太大会导致我们的计算时间大大延长。因为声音具有一定的延续性,所以我们可以计算一个时间段内的平均值来获得一段音频范围的分布值,这样既减小了工作量又达到了合理可视化的效果。首先是获取平均值,假设我们每秒想获取10个分贝值,那么我们需要计算采样率*通道数*采样位数/8/10个字节数据的平均值,我们不妨自己把它叫dB采样区间样本数,一个16bit位深的音频每两个字节组成一个样本,将区间内样本相加再除以样本数取平均值即可。接下来就是dB的计算,dB其实并不特指分贝,它只是在音频描述领域。它描述的是音频的增益关系,如果想详细了解db是什么可以看看《什么是dB》。分贝的计算公式是

        20*log10(value)

        所以声音的分贝描述的并不是线性关系而是指数关系,例如70db比50db的声音大了20倍,例如16bit可以描述的音频范围为0-65535那么它的最大dB值在96.3左右,32bit可以描述音频范围在0-4294967296,那么它的最大dB值在192.6。把我们刚才计算的平均值带入value就能获得我们的区间的分贝,把它存起来解析完一起返回或者逐个回调都可以,看你的业务需求。下面是计算16bit采样位数的分贝的方法,32bit的处理方法类似,主要注意值的大小,和每次位移的byte步长。拿到了了分贝我们就可以将它们变成条变成块的绘制到屏幕了。

void getPcmDB16(const unsigned char *pcmdata, size_t size) {int db = 0;short int value = 0;double sum = 0;for(int i = 0; i < size; i += bit_format/8){memcpy(&value, pcmdata+i, bit_format/8); //获取2个字节的大小(值)sum += abs(value); //绝对值求和}sum = sum / (size / (bit_format/8)); //求平均值(2个字节表示一个振幅,所以振幅个数为:size/2个)if(sum > 0){db = (int)(20.0*log10(sum));}memcpy(wave_buffer+wave_index,(char*)&db,1);wave_index++;
}

        需要注意的是我们在解码时ffmpeg的音频格式类型除了packet和planar两个大类外,对于32位的音频又区分了32位整形和32位浮点型。

enum AVSampleFormat {AV_SAMPLE_FMT_NONE = -1,AV_SAMPLE_FMT_U8,          ///< unsigned 8 bitsAV_SAMPLE_FMT_S16,         ///< signed 16 bitsAV_SAMPLE_FMT_S32,         ///< signed 32 bitsAV_SAMPLE_FMT_FLT,         ///< floatAV_SAMPLE_FMT_DBL,         ///< doubleAV_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planarAV_SAMPLE_FMT_S16P,        ///< signed 16 bits, planarAV_SAMPLE_FMT_S32P,        ///< signed 32 bits, planarAV_SAMPLE_FMT_FLTP,        ///< float, planarAV_SAMPLE_FMT_DBLP,        ///< double, planarAV_SAMPLE_FMT_S64,         ///< signed 64 bitsAV_SAMPLE_FMT_S64P,        ///< signed 64 bits, planarAV_SAMPLE_FMT_NB           ///< Number of sample formats. DO NOT USE if linking dynamically
};

        浮点型的取值范围在-1到1的区间,所以我们在计算时需要乘以0x7fff来获得和16位同比例的数据,达到同样的显示效果。 

void getPcmDBFloat(const unsigned char *pcmdata, size_t size) {int db = 0;float value = 0;double sum = 0;for(int i = 0; i < size; i += bit_format/8){memcpy(&value, pcmdata+i, bit_format/8); //获取4个字节的大小(值)sum += abs(value*0x7fff); //绝对值求和}sum = sum / (size / (bit_format/8)); if(sum > 0){db = (int)(20.0*log10(sum));}memcpy(wave_buffer+wave_index,(char*)&db,1);wave_index++;
}

三、实现效果

       

         欢迎大家交流讨论,批评指正。完整代码我会阶段性的推到我的GitHub上Audio项目上,如果需要解析音频的单个C文件可以私聊我发送给大家。

        更新:资源已经上传到CSDN,0积分下载,有兴趣的可以下载下来看一看。解码只针对ffmpeg,计算db的方法可通用。音频解码,分贝计算 资源下载icon-default.png?t=M3K6https://download.csdn.net/download/qq_37841321/85203912?spm=1001.2014.3001.5503

        


http://chatgpt.dhexx.cn/article/h7AqqYbj.shtml

相关文章

基于FFmpeg的视频播放器之七:音频解码

一.流程 音频解码的流程和视频解码几乎一样,最大的区别是解码后需要进行重采样。因为解码出的AVSampleFormat格式是AV_SAMPLE_FMT_FLTP(float, planar),该格式无法直接使用SDL进行播放,需要转换成SDL支持的AV_SAMPLE_FMT_S16(signed 16 bits)格式。关于重采样,详见下篇…

2020手机音频解码芯片_2020杰理音频芯片全解析,14款音频产品代表作拆解汇总...

珠海市杰理科技股份有限公司,成立于2010年。杰理科技主要从事射频智能终端、多媒体智能终端等系统级芯片(SoC)的研究、开发和销售。 杰理科技的芯片产品主要应用于AI智能音箱、蓝牙音箱、蓝牙耳机、智能语音玩具等物联网智能终端产品,下游应用产品市场十分广泛和巨大。 杰理科…

音频编解码原理

实例说明 音频编解码常用的实现方案有三 种。 第一种就是采用专用的音频芯片对 语音信号进行采集和处理&#xff0c;音频编解码算法集成在硬件内部&#xff0c;如 MP3 编解码芯片、语音合成 分析芯片等。使用这种方案的优点就是处理速度块&#xff0c;设计周期短&#xff1b;缺…

基于STM32音频解码MP3——vs1053

基于正点原子教程 VS1053简介&#xff1a; 1.该模块采用VS1053B 作为主芯片 2.支持&#xff1a;MP3/WMA/OGG/WAV/FLAC/MIDI/AAC 等音频格式的解码 3.支持&#xff1a;OGG/WAV 音频格式的录音&#xff0c;支持高低音调节以及 EarSpeaker 空间效果设置 模块如图所示正点原子 AL…

ijkplayer音频解码播放架构分析

ijkplayer是一款跨平台播放器&#xff0c;支持Android与iOS播放&#xff0c;音频解码默认使用FFmpeg的avcodec软解。Android端播放音频可以用OpenSL ES和AudioTrack&#xff0c;而iOS端播放音频默认使用AudioQueue。 一、iOS音频解码播放 采用pipeline形式创建音频播放组件&a…

HIFI音频解码芯片ES9023

现在的HiFi播放器、解码耳放设备越来越多&#xff0c;推陈出新的速度也越来越快。各家厂商也都对产品进行了卖点细分&#xff0c;把新款旗舰级解码芯片拎出来宣传。美国ESS公司推出的ES9038Pro芯片大家都早已耳熟能详。 美国ESS系列芯片拥有行业高标准的信噪比 DNR&#xff08;…

DP7398:国产兼容替代CS4398立体声24位/192kHz音频解码芯片

目录 DP7398简介结构框图芯片特性 应用领域 DP7398简介 DP7398是立体声 24 位/192kHz 数模转换芯片。该D/A系统包括数字去加重、半分贝步长音量控制、ATAPI 通道混频、可选择的快速和慢速数字插补滤波器和过采样多位增量 Sigma-Delta 调制器&#xff1b;该调制器采用失调整形技…

ijkplayer 音频解码线程

在ijkplayer 读线程中提到&#xff0c;函数stream_component_open()中的decoder_start()会创建音频解码线程&#xff0c;来看解码线程audio_thread()的主要代码 static int audio_thread(void *arg) {...do {...if ((got_frame decoder_decode_frame(ffp, &is->auddec…

ES9023音频解码芯片原理及应用简介

一般来说&#xff0c;音频解码器分为两类&#xff0c;一类是用于Hi&#xff0d;Fi听音的纯音频解码器&#xff0c;即指把CD机等数字音源器材一分为二后&#xff0c;去掉转盘&#xff08;驱动光碟旋转读盘&#xff09;的部分。 纯音频解码器的主要作用是把读取的数字音频信息转…

iOS的音频解码详解

在iOS平台上,所有的音频框架底层都是基于AudioUnit实现的,较高层次的音频框架包括: Media Player、 AV Foundation、OpenAL和Audio Toolbox,这些框架都封装了AudioUnit,然后提供了更高层次的API(功能更少,职责更单一的接口)。 当开发者在开发音视频相关产品的时候,如果…

FFmpeg音频解码流程详解及简单demo参考

本文主要讲解FFmpeg的音频解码具体流程&#xff0c;API使用。最后再以一个非常简单的demo演示将一个mp3格式的音频文件解码为原始数据pcm文件。 本文主要基于FFmpeg音频解码新接口。 一、FFmpeg音频解码API调用流程图 API接口简单大体讲解如下&#xff1a; av_register…

ffmpeg 音频解码一

1. ffmpeg 视频解码一 2. ffmpeg 视频解码二 3. ffmpeg 音频解码一 4. ffmpeg 音频解码二 5. ffmpeg 音视频解码 6. ffmpeg 视频编码一 7. ffmpeg 视频编码一&#xff08;精简版&#xff09; 8. ffmpeg 视频编码二&#xff08;基于 libswscale 转换视频&#xff09; 9. ffmpeg …

MP3音频解码详细过程(二)

最近做了无人机的音频解码&#xff0c;二周内从无任何音频基础到输出PCM数据码流到无人机上可以实现播报功能&#xff0c;其中遇到了许多莫名的坑&#xff0c;谨以此篇记录心得。也算交个作业。 架构设计思路&#xff1a;由usart 实时传输mp3音频码流&#xff0c;STM32F446 将…

低延迟音频中的音频解码优化策略

文章目录 前言音频播放举个例子&#xff1a;PortAudio回调函数解码与播放 优化策略1. 一次性读取音频到内存中2. MMAP3. 音频转码&#xff0c;再接 MMAP4. 解码缓冲 总结参考资料 前言 延迟是指信号在系统中传输所需的时间。下面是常见类型的音频应用相关延迟时间&#xff1a;…

音频编解码基础

1. PCM PCM 脉冲编码调制是Pulse Code Modulation的缩写。脉冲编码调制是数字通信的编码方式之一。主要过程是将话音、图像等模拟信号每隔一定时间进行取样&#xff0c;使其离散化&#xff0c;同时将抽样值按分层单位四舍五入取整量化&#xff0c;同时将抽样值按一组二进制码来…

音视频解码流程详解

1、解码整体流程 &#xff08;1&#xff09; 音频解码整体流程 &#xff08;2&#xff09;视频解码整体流程 2、FFmpeg音视频解码详细流程 3、关键数据结构 AVCodecParser&#xff1a;⽤于解析输⼊的数据流并把它分成⼀帧⼀帧的压缩编码数据。⽐较形象 的说法就是把⻓⻓的⼀…

FFmpeg 音频解码(秒懂)

1.简介 解码音频数据&#xff0c;如下图所示&#xff0c;把MP3或者AAC数据解码成原始的数据pcm。 2.流程 2.1在使用FFmpeg API之前&#xff0c;需要先注册API&#xff0c;然后才能使用API。当然&#xff0c;新版本的库不需要再调用下面的方法。 av_register_all() 2.2 构建输…

语音编解码技术演进和应用选型

本文来自现网易云音乐音视频实验室负责人刘华平在LiveVideoStackCon 2017大会上的分享&#xff0c;并由LiveVideoStack整理而成。分享中刘华平以时间为主线&#xff0c;讲述了语音编解码技术的演进路线及实际应用中的技术选型。 文 / 刘华平 整理 / LiveVideoStack 大家好&…

回访。

wyx 过来&#xff0c;还 sxt &#xff0c;拿走了几张碟。为此&#xff0c;特意收拾了房间。还是被说没地方坐。 由于事先约了 zhmm 吃饭&#xff0c;没调开时间&#xff0c;所以&#xff0c;五点多&#xff0c;大家就一起吃了。大青花&#xff0c;东北风味儿。餐厅在二楼&…

客户信息管理软件系统

拟实现一个基于文本界面的《客户信息管理软件》 进一步掌握编程技巧和调试技巧&#xff0c;熟悉面向对象编程 主要涉及以下知识点&#xff1a; ▶类结构的使用&#xff1a; ▶对象的创建与使用 ▶类的封装性 ▶声明和使用数组 ▶数组的插入、删除和替换 ▶关键字的使用&#xf…