当前位置: 首页 > news >正文

音视频入门基础:AAC专题(13)——FFmpeg源码中,获取ADTS格式的AAC裸流音频信息的实现

=================================================================

音视频入门基础:AAC专题系列文章:

音视频入门基础:AAC专题(1)——AAC官方文档下载

音视频入门基础:AAC专题(2)——使用FFmpeg命令生成AAC裸流文件

音视频入门基础:AAC专题(3)——AAC的ADTS格式简介

音视频入门基础:AAC专题(4)——ADTS格式的AAC裸流实例分析

音视频入门基础:AAC专题(5)——FFmpeg源码中,判断某文件是否为AAC裸流文件的实现

音视频入门基础:AAC专题(6)——FFmpeg源码中解码ADTS格式的AAC的Header的实现

音视频入门基础:AAC专题(7)——FFmpeg源码中计算AAC裸流每个packet的size值的实现

音视频入门基础:AAC专题(8)——FFmpeg源码中计算AAC裸流AVStream的time_base的实现

音视频入门基础:AAC专题(9)——FFmpeg源码中计算AAC裸流每个packet的duration和duration_time的实现

音视频入门基础:AAC专题(10)——FFmpeg源码中计算AAC裸流每个packet的pts、dts、pts_time、dts_time的实现

音视频入门基础:AAC专题(11)——AudioSpecificConfig简介

音视频入门基础:AAC专题(12)——FFmpeg源码中,解码AudioSpecificConfig的实现

音视频入门基础:AAC专题(13)——FFmpeg源码中,获取ADTS格式的AAC裸流音频信息的实现

=================================================================

一、引言

对于携带Audio Specific Config的媒体文件,比如音频压缩编码格式为AAC的FLV文件,FFmpeg一般通过解码其Audio Tag中Audio Specific Config获取其音频信息。而通过《音视频入门基础:AAC专题(2)——使用FFmpeg命令生成AAC裸流文件》生成的AAC裸流文件和TS流中的AAC是没有Audio Specific Config的,只有ADTS Header,这时就得通过解码ADTS Header获取其音频信息(音频压缩编码格式的profile、音频采样率、音频声道数、码率等):

 本文讲述FFmpeg源码中,获取ADTS格式的AAC裸流音频信息的实现。

二、音频压缩编码格式

具体获取方法可以参考:《音视频入门基础:AAC专题(5)——FFmpeg源码中,判断某文件是否为AAC裸流文件的实现》

三、音频压缩编码格式的profile

音频压缩编码格式还有附带的profile(规格)。比如,如果音频压缩编码格式为AAC,根据《ISO14496-3-2009.pdf》第124页,还有AAC Main、AAC LC、AAC SSR、AAC LTP这几种规格:

FFmpeg获取AAC裸流的音频压缩编码格式的profile,是根据ADTS Header中的profile_ObjectType属性获取的。由《音视频入门基础:AAC专题(3)——AAC的ADTS格式简介》可以知道,ADTS Header中存在一个占2位的profile_ObjectType属性,表示AAC的规格。

由《音视频入门基础:AAC专题(6)——FFmpeg源码中解码ADTS格式的AAC的Header的实现》可以知道,FFmpeg源码中通过ff_adts_header_parse函数解码ADTS格式的AAC的Header。而ff_adts_header_parse函数中,通过下面语句,将profile_ObjectType属性的值加1赋值给hdr->object_type:

hdr->object_type    = aot + 1;

然后在parse_adts_frame_header函数中,将hdr->object_type赋值给ac->oc[1].m4ac.object_type:

static int parse_adts_frame_header(AACDecContext *ac, GetBitContext *gb)
{
//...size = ff_adts_header_parse(gb, &hdr_info);if (size > 0) {//...ac->oc[1].m4ac.object_type     = hdr_info.object_type;//...}
//...
}

之后,通过aac_decode_frame_int函数将ac->oc[1].m4ac.object_type的值减1赋值给AVCodecContext的profile,这样AVCodecContext的profile就会得到原本的profile_ObjectType属性:

static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame,int *got_frame_ptr, GetBitContext *gb,const AVPacket *avpkt)
{
//...// The AV_PROFILE_AAC_* defines are all object_type - 1// This may lead to an undefined profile being signaledac->avctx->profile = ac->oc[1].m4ac.object_type - 1;
//...
}

然后在dump_stream_format函数中,通过avcodec_string函数中的语句:profile = avcodec_profile_name(enc->codec_id, enc->profile)拿到上一步中得到的AVCodecContext的profile。最后再在dump_stream_format函数中将profile打印出来:

void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
{
//...profile = avcodec_profile_name(enc->codec_id, enc->profile);
//...
}

所以FFmpeg获取AAC裸流文件的音频压缩编码格式的profile,获取的是ADTS Header中的profile_ObjectType属性:

四、音频采样率

FFmpeg获取AAC裸流的音频采样频率,是根据ADTS Header中的samplingFrequencyIndex属性获取的。 由《音视频入门基础:AAC专题(3)——AAC的ADTS格式简介》可以知道,ADTS Header中存在一个占4位的samplingFrequencyIndex属性,表示音频采样频率:

ff_adts_header_parse函数中,通过下面语句,将samplingFrequencyIndex属性的值赋值给hdr->sampling_index。将音频采样频率(单位为Hz)赋值给hdr->sample_rate:

    hdr->sampling_index = sr;hdr->sample_rate    = ff_mpeg4audio_sample_rates[sr];

然后在parse_adts_frame_header函数中,将hdr->sample_rate赋值给ac->oc[1].m4ac.sample_rate:

​
static int parse_adts_frame_header(AACDecContext *ac, GetBitContext *gb)
{
//...size = ff_adts_header_parse(gb, &hdr_info);if (size > 0) {//...ac->oc[1].m4ac.sample_rate     = hdr_info.sample_rate;//...}
//...
}​

之后,通过aac_decode_frame_int函数将ac->oc[1].m4ac.sample_rate赋值给AVCodecContext的sample_rate:

static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame,int *got_frame_ptr, GetBitContext *gb,const AVPacket *avpkt)
{
//...if (ac->oc[1].status && audio_found) {avctx->sample_rate = ac->oc[1].m4ac.sample_rate << multiplier;avctx->frame_size = samples;ac->oc[1].status = OC_LOCKED;}
//...
}

然后在dump_stream_format函数中,通过avcodec_string函数中的语句:av_bprintf(&bprint, "%d Hz, ", enc->sample_rate)拿到上一步中得到的AVCodecContext的sample_rate。最后再在dump_stream_format函数中将其打印出来:

void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
{
//...switch (enc->codec_type) {case AVMEDIA_TYPE_AUDIO:av_bprintf(&bprint, "%s", separator);if (enc->sample_rate) {av_bprintf(&bprint, "%d Hz, ", enc->sample_rate);}
//...}
//...
}

所以FFmpeg获取AAC裸流文件的音频采样率,获取的是ADTS Header中的samplingFrequencyIndex属性:

五、音频声道数

FFmpeg获取AAC裸流的音频声道数,是根据ADTS Header中的channel_configuration属性获取的。 由《音视频入门基础:AAC专题(3)——AAC的ADTS格式简介》可以知道,ADTS Header中存在一个占3位的channel_configuration属性,表示音频声道数:

ff_adts_header_parse函数中,通过下面语句,将音频声道数赋值给hdr->chan_config:

hdr->chan_config    = ch;

然后在parse_adts_frame_header函数中,将hdr->chan_config赋值给AVCodecContext的ch_layout:

​
​
static int parse_adts_frame_header(AACDecContext *ac, GetBitContext *gb)
{
//...size = ff_adts_header_parse(gb, &hdr_info);if (size > 0) {//...if (hdr_info.chan_config) {ac->oc[1].m4ac.chan_config = hdr_info.chan_config;if ((ret = set_default_channel_config(ac, ac->avctx,layout_map,&layout_map_tags,hdr_info.chan_config)) < 0)return ret;if ((ret = output_configure(ac, layout_map, layout_map_tags,FFMAX(ac->oc[1].status,OC_TRIAL_FRAME), 0)) < 0)return ret;}//...}
//...
}

然后在dump_stream_format函数中,通过avcodec_string函数中的语句:av_channel_layout_describe_bprint(&enc->ch_layout, &bprint)拿到AVCodecContext的ch_layout对应的音频声道数目。最后再在dump_stream_format函数中将音频声道数目打印出来:

void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
{
//...switch (enc->codec_type) {case AVMEDIA_TYPE_AUDIO:av_channel_layout_describe_bprint(&enc->ch_layout, &bprint);//...break;}
//...
}

所以FFmpeg获取AAC裸流文件的音频声道数,获取的是ADTS Header中的channel_configuration属性:

六、Bit depth

FFmpeg获取AAC裸流的Bit depth(又叫位深度、位元深度、采样深度、采样位数、采样格式),获取到的值是没有意义的。当音频压缩编码格式为AAC时,FFmpeg会强制把Bit depth设置为fltp。这是因为对于有损压缩编解码器(如MP3和AAC),Bit depth是在编码期间计算的,并且可以因采样而异,Bit depth只对PCM数字信号有意义。具体可以参考:《音视频入门基础:AAC专题(3)——AAC的ADTS格式简介》。

可以看到在aac_decode_init函数中(该函数定义在libavcodec/aacdec_template.c),强制把音频采样格式设置成了AV_SAMPLE_FMT_FLTP:

static av_cold int aac_decode_init(AVCodecContext *avctx)
{
//...avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
//...
}

所以如果音频压缩编码格式为AAC,通过FFmpeg获取到的音频采样格式固定为fltp,该值没有意义:

七、音频码率

通过解码ADTS Header无法直接获得音频码率,但是可以通过里面的属性间接计算出音频码率。

ff_adts_header_parse函数中,将该ADTS音频帧中原始数据块的个数乘以1024,得到的结果赋值给hdr->samples。FFmpeg源码内部强制默认AAC(AAC Main、AAC LC、AAC SSR、AAC LTP)的samples是1024。hdr->samples为该ADTS音频帧中采样的次数:

hdr->samples        = (rdb + 1) * 1024;

通过公式得到该ADTS音频帧的码率,单位为bits/s,赋值给hdr->bit_rate:

hdr->bit_rate       = size * 8 * hdr->sample_rate / hdr->samples;

然后ff_aac_ac3_parse函数中,通过下面代码得到实际的以bps为单位的音频码率,赋值给AVCodecContext的bit_rate:

int ff_aac_ac3_parse(AVCodecParserContext *s1,AVCodecContext *avctx,const uint8_t **poutbuf, int *poutbuf_size,const uint8_t *buf, int buf_size)
{
//...if (got_frame) {//...int bit_rate;if (avctx->codec_id != AV_CODEC_ID_AAC) {//...}else{AACADTSHeaderInfo hdr, *phrd = &hdr;int ret = avpriv_adts_header_parse(&phrd, buf, buf_size);if (ret < 0)return i;bit_rate = hdr.bit_rate;}/* Calculate the average bit rate */s->frame_number++;if (!CONFIG_EAC3_DECODER || avctx->codec_id != AV_CODEC_ID_EAC3) {avctx->bit_rate +=(bit_rate - avctx->bit_rate) / s->frame_number;}}
//...
}

然后在dump_stream_format函数中,通过avcodec_string函数中的语句:bitrate = get_bit_rate(enc)拿到AVCodecContext的bit_rate。最后再把它除以1000,得到以kb/s为单位的音频码率,打印出来:

void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
{
//...bitrate = get_bit_rate(enc);if (bitrate != 0) {av_bprintf(&bprint, ", %"PRId64" kb/s", bitrate / 1000);
//...
}

所以FFmpeg获取AAC裸流文件的音频码率,是根据ADTS Header中的属性计算出来的:

相关文章:

音视频入门基础:AAC专题(13)——FFmpeg源码中,获取ADTS格式的AAC裸流音频信息的实现

音视频入门基础&#xff1a;AAC专题系列文章&#xff1a; 音视频入门基础&#xff1a;AAC专题&#xff08;1&#xff09;——AAC官方文档下载 音视频入门基础&#xff1a;AAC专题&#xff08;2&#xff09;——使用FFmpeg命令生成AAC裸流文件 音视频入门基础&#xff1a;AAC…...

【C++】B2069 求分数序列和题目解析与优化详解

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目描述输入格式输出格式输入输出样例输入&#xff1a;输出&#xff1a; &#x1f4af;解题思路分析题目解题步骤 &#x1f4af;代码实现我的代码实现实现特点 老师的代码…...

4.FPGA如何实现设计

在前面分别引入了&#xff0c;LUT的知识&#xff0c;全局时钟网络&#xff0c;以及FPGA内部的资源。 LUT的知识&#xff1a; 在FPGA设计中实现的逻辑运算在不借用其他的硬核的基础上都是在LUT中通过查表的方式进行完成的&#xff0c;比如实现的c a & b;就是将a&b的所…...

SO-CNN-LSTM-MATT蛇群算法优化注意力机制深度学习多特征分类预测

SO-CNN-LSTM-MATT蛇群算法优化注意力机制深度学习多特征分类预测&#xff08;多输入单输出&#xff09; 目录 SO-CNN-LSTM-MATT蛇群算法优化注意力机制深度学习多特征分类预测&#xff08;多输入单输出&#xff09;分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matl…...

大模型-Ollama使用相关的笔记

大模型-Ollama使用相关的笔记 解决Ollama外网访问问题&#xff08;配置ollama跨域访问&#xff09;Postman请求样例 解决Ollama外网访问问题&#xff08;配置ollama跨域访问&#xff09; 安装Ollama完毕后&#xff0c; /etc/systemd/system/ollama.service进行如下修改&#…...

OpenCV计算机视觉 02 图片修改 图像运算 边缘填充 阈值处理

目录 图片修改&#xff08;打码、组合、缩放&#xff09; 图像运算 边缘填充 ​阈值处理 上一篇文章&#xff1a; OpenCV计算机视觉 01 图像与视频的读取操作&颜色通道 图片修改&#xff08;打码、组合、缩放&#xff09; # 图片打码 import numpy as np a cv2.imre…...

langchain使用FewShotPromptTemplate出现KeyError的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...

tryhackme-Cyber Security 101-Linux Shells(linux命令框)

目的&#xff1a;了解脚本和不同类型的 Linux shell。 任务1&#xff1a;Introduction to Linux Shells&#xff08;Linux Shell 简介&#xff09; 作为操作系统的常规用户&#xff0c;我们都广泛使用图形用户界面 &#xff08;GUI&#xff09; 来执行大多数操作。只需点击几…...

亚远景-ISO 21434标准涵盖了哪些方面?

ISO 21434标准《道路车辆—网络安全工程》全面涵盖了汽车网络安全领域&#xff0c;其目的是确保汽车电子系统在整个产品生命周期中的网络安全性能。具体来说&#xff0c;该标准包括以下几个方面&#xff1a; 1. 术语和定义 &#xff1a;提供汽车网络安全相关的术语、概念和定义…...

第3章 集合与关系

2024年12月24日一稿 2024年12月26日二稿 &#x1f430;3.1 集合的概念和表示法 &#x1f998;3.1.1 集合的表示 &#x1f998;3.1.2 基本概念 &#x1f430;3.2 集合的运算 &#x1f998;3.2.1 集合的基本运算 &#x1f998;3.2.2 有穷计数集 &#x1f998;3.2.3 广义交和广义…...

【vmware】|设置共享文件夹

目的: 虚拟机中设置共享文件夹&#xff0c;本地物理机中可以搜到该共享文件夹 1、虚拟机&#xff1a; 设置共享文件夹 右键属性-共享页码进行下列设置 点击网络和共享中心&#xff0c;检查下列选项 二、在本地物理机中启用网络发现&#xff1a; 此时&#xff0c;刷新网络…...

Log4j1.27配置日志输出级别不起效

起因&#xff1a;构建独立版本debezuim使用时&#xff0c;日志一直打印debug信息。 原因&#xff1a;包冲突问题&#xff0c;进行排包操作。 参考log4j日志级别配置完成后不生效 系统一直打印debug日志_log4j不起作用-CSDN博客 1、application.properties logging.configc…...

计算机图形学知识点汇总

一、计算机图形学定义与内容 1.图形 图形分为“图”和“形”两部分。 其中&#xff0c;“形”指形体或形状&#xff0c;存在于客观世界和虚拟世界&#xff0c;它的本质是“表示”&#xff1b;而图则是包含几何信息与属性信息的点、线等基本图元构成的画面&#xff0c;用于表达…...

详解下c语言中struct和union的对齐规则

接触过c语言的同学应该都知道字节对齐。有些时候我们很容易弄错字节对齐的方式&#xff0c;特别是涉及到struct&#xff08;结构体&#xff09;和union&#xff08;联合体&#xff09;时。今天我们通过详细例子来说明下struct和union的对齐规则&#xff0c;以便了解各种struct和…...

ubuntu安装sublime安装与免费使用

1. ubuntu安装sublime 参考官网: Linux Package Manager Repositories 2. 破解过程 打开如下网址,打开/opt/sublime_text/sublime_text https://hexed.it/ 3. 替换在hexed打开的文件中查找并替换: 4180激活方法 使用二进制编辑器 8079 0500 0f94 c2替换为 c641 05…...

攻防世界 cookie

开启场景 Cookie&#xff08;HTTP cookie&#xff09;是一种存储在用户计算机上的小型文本文件。它由网站通过用户的浏览器在用户访问网站时创建&#xff0c;并存储一些用于跟踪和识别用户的信息。Cookie 主要用于在网站和浏览器之间传递数据&#xff0c;以便网站可以根据用户的…...

深度学习笔记1:神经网络与模型训练过程

参考博客&#xff1a;PyTorch深度学习实战&#xff08;1&#xff09;——神经网络与模型训练过程详解_pytorch 实战-CSDN博客 人工神经网络 ANN&#xff1a;张量及数学运算的集合&#xff0c;排列方式近似于松散的人脑神经元排列 组成 1&#xff09;输入层 2&#xff09;隐…...

什么是 DevOps 自动化?

DevOps 自动化是一种现代软件开发方法&#xff0c;它使用工具和流程来自动化任务并简化工作流程。它将开发人员、IT 运营和安全团队聚集在一起&#xff0c;帮助他们有效协作并交付可靠的软件。借助 DevOps 自动化&#xff0c;组织能够处理重复性任务、优化流程并更快地将应用程…...

使用 Python 操作 MySQL 数据库的实用工具类:MySQLHandler

操作数据库是非常常见的需求&#xff0c;使用 Python 和 pymysql 库封装一个通用的 MySQL 数据库操作工具类&#xff0c;并通过示例演示如何使用这个工具类高效地管理数据库。 工具类的核心代码解析 MySQLHandler 类简介 MySQLHandler 是一个 Python 类&#xff0c;用于简化…...

DB-GPT V0.6.3 版本更新:支持 SiliconCloud 模型、新增知识处理工作流等

DB-GPT V0.6.3版本现已上线&#xff0c;快速预览新特性: 新特性 1. 支持 SiliconCloud 模型&#xff0c;让用户体验多模型的管理能力 如何使用&#xff1a; 修改环境变量文件.env&#xff0c;配置SiliconCloud模型 # 使用 SiliconCloud 的代理模型 LLM_MODELsiliconflow_p…...

告别性能焦虑:5个被忽略的华硕设备优化神器隐藏功能

告别性能焦虑&#xff1a;5个被忽略的华硕设备优化神器隐藏功能 【免费下载链接】g-helper Lightweight, open-source control tool for ASUS laptops and ROG Ally. Manage performance modes, fans, GPU, battery, and RGB lighting across Zephyrus, Flow, TUF, Strix, Scar…...

用快马ai快速构建你的第一个endnote式文献管理原型

最近在写论文时&#xff0c;突然意识到需要个简单的文献管理工具。虽然EndNote这类专业软件功能强大&#xff0c;但对于快速记录和引用参考文献来说&#xff0c;有时候只需要一个轻量级的解决方案。于是我在InsCode(快马)平台上尝试用HTML、CSS和JavaScript快速搭建了一个原型&…...

告别黑苹果配置难题:零基础也能轻松上手的智能工具详解

告别黑苹果配置难题&#xff1a;零基础也能轻松上手的智能工具详解 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 你是否曾因黑苹果EFI配置的复杂流程…...

Cursor AI破解免费VIP 2025终极完整教程:轻松解除试用限制,畅享专业功能

Cursor AI破解免费VIP 2025终极完整教程&#xff1a;轻松解除试用限制&#xff0c;畅享专业功能 【免费下载链接】cursor-free-vip [Support 0.45]&#xff08;Multi Language 多语言&#xff09;自动注册 Cursor Ai &#xff0c;自动重置机器ID &#xff0c; 免费升级使用Pro …...

开源工具 企业级应用激活:Atlassian Agent全流程实践指南

开源工具 企业级应用激活&#xff1a;Atlassian Agent全流程实践指南 【免费下载链接】atlassian-agent Atlassians productions crack. 项目地址: https://gitcode.com/gh_mirrors/at/atlassian-agent 企业在部署JIRA、Confluence等Atlassian产品时&#xff0c;常面临许…...

OpenClaw语音控制:Qwen3-4B-Thinking-2507-GPT-5-Codex-Distill-GGUF实现声控自动化

OpenClaw语音控制&#xff1a;Qwen3-4B-Thinking-2507-GPT-5-Codex-Distill-GGUF实现声控自动化 1. 为什么需要语音控制自动化 去年冬天的一个深夜&#xff0c;我在赶项目文档时突然冒出一个想法&#xff1a;如果能像科幻电影里那样&#xff0c;用语音指挥电脑完成重复性工作…...

终极指南:如何使用MTEX工具箱进行材料微观结构分析

终极指南&#xff1a;如何使用MTEX工具箱进行材料微观结构分析 【免费下载链接】mtex MTEX is a free Matlab toolbox for quantitative texture analysis. Homepage: 项目地址: https://gitcode.com/gh_mirrors/mt/mtex MTEX是一款强大的开源MATLAB工具箱&#xff0c;专…...

深度解析:如何高效使用开源虚拟机检测工具VMDE实现系统环境识别

深度解析&#xff1a;如何高效使用开源虚拟机检测工具VMDE实现系统环境识别 【免费下载链接】VMDE Source from VMDE paper, adapted to 2015 项目地址: https://gitcode.com/gh_mirrors/vm/VMDE 虚拟机检测工具VMDE是一款专业的开源工具&#xff0c;专门用于精确识别系…...

VSCode开发Mirage Flow应用的环境配置指南

VSCode开发Mirage Flow应用的环境配置指南 1. 环境准备与插件安装 在开始开发Mirage Flow应用之前&#xff0c;我们需要先配置好VSCode开发环境。VSCode作为一款轻量级但功能强大的代码编辑器&#xff0c;通过合适的插件配置可以大幅提升开发效率。 首先确保你已经安装了最新…...

开箱即用!Retinaface+CurricularFace人脸识别镜像一键部署与测试

开箱即用&#xff01;RetinafaceCurricularFace人脸识别镜像一键部署与测试 你是否曾对复杂的人脸识别项目望而却步&#xff1f;面对PyTorch、CUDA版本冲突、模型下载和环境配置的层层阻碍&#xff0c;是不是感觉还没开始写代码&#xff0c;精力就已经耗尽了&#xff1f;今天&…...