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

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

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

音视频入门基础: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专题(11)——AudioSpecificConfig简介》中对AudioSpecificConfig进行了简介,本文讲述FFmpeg源码中是怎样解码AudioSpecificConfig,拿到里面的信息。

二、decode_audio_specific_config_gb函数的定义

FFmpeg源码中使用decode_audio_specific_config_gb函数来读取AudioSpecificConfig的信息。该函数定义在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的源文件libavcodec/aacdec_template.c中:

/*** Decode audio specific configuration; reference: table 1.13.** @param   ac          pointer to AACDecContext, may be null* @param   avctx       pointer to AVCCodecContext, used for logging* @param   m4ac        pointer to MPEG4AudioConfig, used for parsing* @param   gb          buffer holding an audio specific config* @param   get_bit_alignment relative alignment for byte align operations* @param   sync_extension look for an appended sync extension** @return  Returns error status or number of consumed bits. <0 - error*/
static int decode_audio_specific_config_gb(AACDecContext *ac,AVCodecContext *avctx,MPEG4AudioConfig *m4ac,GetBitContext *gb,int get_bit_alignment,int sync_extension)
{int i, ret;GetBitContext gbc = *gb;MPEG4AudioConfig m4ac_bak = *m4ac;if ((i = ff_mpeg4audio_get_config_gb(m4ac, &gbc, sync_extension, avctx)) < 0) {*m4ac = m4ac_bak;return AVERROR_INVALIDDATA;}if (m4ac->sampling_index > 12) {av_log(avctx, AV_LOG_ERROR,"invalid sampling rate index %d\n",m4ac->sampling_index);*m4ac = m4ac_bak;return AVERROR_INVALIDDATA;}if (m4ac->object_type == AOT_ER_AAC_LD &&(m4ac->sampling_index < 3 || m4ac->sampling_index > 7)) {av_log(avctx, AV_LOG_ERROR,"invalid low delay sampling rate index %d\n",m4ac->sampling_index);*m4ac = m4ac_bak;return AVERROR_INVALIDDATA;}skip_bits_long(gb, i);switch (m4ac->object_type) {case AOT_AAC_MAIN:case AOT_AAC_LC:case AOT_AAC_SSR:case AOT_AAC_LTP:case AOT_ER_AAC_LC:case AOT_ER_AAC_LD:if ((ret = decode_ga_specific_config(ac, avctx, gb, get_bit_alignment,m4ac, m4ac->chan_config)) < 0)return ret;break;case AOT_ER_AAC_ELD:if ((ret = decode_eld_specific_config(ac, avctx, gb,m4ac, m4ac->chan_config)) < 0)return ret;break;default:avpriv_report_missing_feature(avctx,"Audio object type %s%d",m4ac->sbr == 1 ? "SBR+" : "",m4ac->object_type);return AVERROR(ENOSYS);}ff_dlog(avctx,"AOT %d chan config %d sampling index %d (%d) SBR %d PS %d\n",m4ac->object_type, m4ac->chan_config, m4ac->sampling_index,m4ac->sample_rate, m4ac->sbr,m4ac->ps);return get_bits_count(gb);
}

形参ac:既是输入型参数也是输出型参数。指向一个AACDecContext类型变量。

形参avctx:输入型参数。用来输出日志,可忽略。

形参m4ac:输出型参数,指向一个MPEG4AudioConfig类型变量,执行decode_audio_specific_config_gb函数后,m4ac指向的变量会得到从AudioSpecificConfig中解码出来的属性。MPEG4AudioConfig结构体声明如下:

typedef struct MPEG4AudioConfig {int object_type;int sampling_index;int sample_rate;int chan_config;int sbr; ///< -1 implicit, 1 presenceint ext_object_type;int ext_sampling_index;int ext_sample_rate;int ext_chan_config;int channels;int ps;  ///< -1 implicit, 1 presenceint frame_length_short;
} MPEG4AudioConfig;

形参gb:既是输入型参数也是输出型参数,为GetBitContext类型,用来对“位”进行操作(具体可以参考:《FFmpeg中位操作相关的源码:GetBitContext结构体,init_get_bits函数、get_bits1函数和get_bits函数分析》)。

执行decode_audio_specific_config_gb函数前,gb->buffer为指向某个缓冲区的指针。该缓冲区存放AudioSpecificConfig的二进制数据。

形参get_bit_alignment:输入型参数。字节对齐操作的相对对齐。

形参sync_extension:输入型参数。寻找附加的同步扩展。

三、decode_audio_specific_config_gb函数的内部实现分析

decode_audio_specific_config_gb函数中,首先调用ff_mpeg4audio_get_config_gb函数:

    if ((i = ff_mpeg4audio_get_config_gb(m4ac, &gbc, sync_extension, avctx)) < 0) {*m4ac = m4ac_bak;return AVERROR_INVALIDDATA;}

(一)ff_mpeg4audio_get_config_gb函数

ff_mpeg4audio_get_config_gb函数定义在libavcodec/mpeg4audio.c中:

int ff_mpeg4audio_get_config_gb(MPEG4AudioConfig *c, GetBitContext *gb,int sync_extension, void *logctx)
{int specific_config_bitindex, ret;int start_bit_index = get_bits_count(gb);c->object_type = get_object_type(gb);c->sample_rate = get_sample_rate(gb, &c->sampling_index);c->chan_config = get_bits(gb, 4);if (c->chan_config < FF_ARRAY_ELEMS(ff_mpeg4audio_channels))c->channels = ff_mpeg4audio_channels[c->chan_config];else {av_log(logctx, AV_LOG_ERROR, "Invalid chan_config %d\n", c->chan_config);return AVERROR_INVALIDDATA;}c->sbr = -1;c->ps  = -1;if (c->object_type == AOT_SBR || (c->object_type == AOT_PS &&// check for W6132 Annex YYYY draft MP3onMP4!(show_bits(gb, 3) & 0x03 && !(show_bits(gb, 9) & 0x3F)))) {if (c->object_type == AOT_PS)c->ps = 1;c->ext_object_type = AOT_SBR;c->sbr = 1;c->ext_sample_rate = get_sample_rate(gb, &c->ext_sampling_index);c->object_type = get_object_type(gb);if (c->object_type == AOT_ER_BSAC)c->ext_chan_config = get_bits(gb, 4);} else {c->ext_object_type = AOT_NULL;c->ext_sample_rate = 0;}specific_config_bitindex = get_bits_count(gb);if (c->object_type == AOT_ALS) {skip_bits(gb, 5);if (show_bits(gb, 24) != MKBETAG('\0','A','L','S'))skip_bits(gb, 24);specific_config_bitindex = get_bits_count(gb);ret = parse_config_ALS(gb, c, logctx);if (ret < 0)return ret;}if (c->ext_object_type != AOT_SBR && sync_extension) {while (get_bits_left(gb) > 15) {if (show_bits(gb, 11) == 0x2b7) { // sync extensionget_bits(gb, 11);c->ext_object_type = get_object_type(gb);if (c->ext_object_type == AOT_SBR && (c->sbr = get_bits1(gb)) == 1) {c->ext_sample_rate = get_sample_rate(gb, &c->ext_sampling_index);if (c->ext_sample_rate == c->sample_rate)c->sbr = -1;}if (get_bits_left(gb) > 11 && get_bits(gb, 11) == 0x548)c->ps = get_bits1(gb);break;} elseget_bits1(gb); // skip 1 bit}}//PS requires SBRif (!c->sbr)c->ps = 0;//Limit implicit PS to the HE-AACv2 Profileif ((c->ps == -1 && c->object_type != AOT_AAC_LC) || c->channels & ~0x01)c->ps = 0;return specific_config_bitindex - start_bit_index;
}

1.获取audioObjectType属性

ff_mpeg4audio_get_config_gb函数中,首先通过语句:c->object_type = get_object_type(gb) 获取AudioSpecificConfig的audioObjectType属性。get_object_type函数定义如下。关于get_bits函数的用法可以参考:《FFmpeg中位操作相关的源码:GetBitContext结构体,init_get_bits函数、get_bits1函数和get_bits函数分析》:

static inline int get_object_type(GetBitContext *gb)
{int object_type = get_bits(gb, 5);if (object_type == AOT_ESCAPE)object_type = 32 + get_bits(gb, 6);return object_type;
}

2.获取samplingFrequencyIndex属性

获取完audioObjectType属性后,ff_mpeg4audio_get_config_gb函数中,通过语句:c->sample_rate = get_sample_rate(gb, &c->sampling_index)获取AudioSpecificConfig的samplingFrequencyIndex属性。get_sample_rate定义如下:

static inline int get_sample_rate(GetBitContext *gb, int *index)
{*index = get_bits(gb, 4);return *index == 0x0f ? get_bits(gb, 24) :ff_mpeg4audio_sample_rates[*index];
}

全局数组ff_mpeg4audio_sample_rates定义如下:

const int ff_mpeg4audio_sample_rates[16] = {96000, 88200, 64000, 48000, 44100, 32000,24000, 22050, 16000, 12000, 11025, 8000, 7350
};

3.获取channelConfiguration属性

ff_mpeg4audio_get_config_gb函数中,通过语句:c->chan_config = get_bits(gb, 4)获取AudioSpecificConfig的channelConfiguration属性。

——————————————————分隔符——————————————————

回到decode_audio_specific_config_gb函数,所以执行下面代码块后,m4ac指向的变量会得到从AudioSpecificConfig中解析出来的audioObjectType、samplingFrequencyIndex、channelConfiguration属性:

    if ((i = ff_mpeg4audio_get_config_gb(m4ac, &gbc, sync_extension, avctx)) < 0) {*m4ac = m4ac_bak;return AVERROR_INVALIDDATA;}

然后decode_audio_specific_config_gb函数通过下面代码块解析AudioSpecificConfig中的GASpecificConfig:

    switch (m4ac->object_type) {case AOT_AAC_MAIN:case AOT_AAC_LC:case AOT_AAC_SSR:case AOT_AAC_LTP:case AOT_ER_AAC_LC:case AOT_ER_AAC_LD:if ((ret = decode_ga_specific_config(ac, avctx, gb, get_bit_alignment,m4ac, m4ac->chan_config)) < 0)return ret;break;

通过下面代码块解析AudioSpecificConfig中的ELDSpecificConfig(channelConfiguration):

    case AOT_ER_AAC_ELD:if ((ret = decode_eld_specific_config(ac, avctx, gb,m4ac, m4ac->chan_config)) < 0)return ret;break;

相关文章:

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

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

UDP组播测试

支持组播的接口&#xff1a; ip a | grep MULTICAST 环回接口虽然显示不支持组播&#xff0c;实际也可以用于本地测试。 添加路由&#xff08;非必须&#xff1f;&#xff09;&#xff1a; ip route add 239.0.0.0/24 via 10.10.10.206 dev eth0 开放防火墙&#xff1a; 查…...

【Nas】X-Doc:jellyfin“该客户端与媒体不兼容,服务器未发送兼容的媒体格式”问题解决方案

【Nas】X-Doc&#xff1a;jellyfin“该客户端与媒体不兼容&#xff0c;服务器未发送兼容的媒体格式”问题解决方案 当使用Jellyfin播放视频时出现“该客户端与媒体不兼容&#xff0c;服务器未发送兼容的媒体格式”&#xff0c;这是与硬件解码和ffmpeg设置有关系&#xff0c;具体…...

504 Gateway Time-outopenresty

504 Gateway Time-out openresty 问题背景&#xff1a; 当自己点开知乎页面以后&#xff0c;发现官网没有出现任何问题&#xff0c;点击官网以后开始出现各种各样的报错&#xff01; 一下是来源ai的介绍&#xff1a;&#xff08;通过搜索这种形式帮助自己进行记忆&#xff09;…...

SpringBoot篇(自动装配原理)

目录 一、自动装配机制 1. 简介 2. 自动装配主要依靠三个核心的关键技术 3. run()方法加载启动类 4. 注解SpringBootApplication包含了多个注解 4.1 SpringBootConfiguration 4.2 ComponentScan 4.3 EnableAutoConfiguration 5. SpringBootApplication一共做了三件事 …...

《Web性能权威指南》-WebRTC-读书笔记

本文是《Web性能权威指南》第四部分——WebRTC的读书笔记。 第一部分——网络技术概览&#xff0c;请参考网络技术概览&#xff1b; 第二部分——无线网络性能&#xff0c;请参考无线网络性能&#xff1b; 第三部分——HTTP&#xff0c;请参考HTTP&#xff1b; 第四部分——浏览…...

跨境电商独立站:打造你的全球品牌

什么是跨境电商独立站&#xff1f; 跨境电商独立站是指一个独立的电子商务网站&#xff0c;企业可以通过这个网站直接向全球消费者销售产品。与入驻亚马逊、eBay等第三方平台不同&#xff0c;独立站拥有完全自主权&#xff0c;可以自由定制店铺风格、营销策略&#xff0c;并直…...

基于uniapp微信小程序的旅游系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…...

怿星科技薛春宇丨智能汽车软件研发工具链国产化的挑战和探索

2024年7月25日&#xff0c;由上海良益企业管理咨询有限公司主办的“2024域控制器技术论坛“在上海成功举办&#xff0c;十位嘉宾做了精彩分享。“整零有道”将陆续刊出部分演讲的文字实录&#xff0c;以飨读者。 本期刊出怿星科技副总经理薛春宇的演讲实录&#xff1a;智能汽车…...

Flutter动画渐变

User experience is everything. One way to improve it is by making transitions between different UI elements smoother and more visually appealing. This is where the AnimatedCrossFade widget comes in handy. 用户体验就是一切。改善用户体验的方法之一就是让不同…...

Python毕业设计选题:基于Web学生会网站的设计与实现-django

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 系统首页界面 用户注册界面 用户登录界面 校内报道界面 品牌活动界面 个人中心界面 …...

如何选购高性价比百元头戴式耳机?六大选购技巧加性价比耳机推荐

在日益繁忙的生活中&#xff0c;头戴式耳机已成为许多人享受音乐、放松心情的重要工具。然而&#xff0c;市面上的头戴式耳机种类繁多&#xff0c;价格各异&#xff0c;如何选购高性价比百元头戴式耳机&#xff1f;成为了许多消费者的难题。为了帮助大家更好地做出选择&#xf…...

Java爬虫的京东“寻宝记”:揭秘商品类目信息

开篇&#xff1a;Java特工的神秘任务 在这个数据驱动的时代&#xff0c;我们就像一群特工&#xff0c;穿梭在数字的海洋中&#xff0c;寻找着隐藏的宝藏——商品类目信息。今天&#xff0c;我们将带领你一起&#xff0c;用Java这把精密的瑞士军刀&#xff0c;深入京东的神秘领…...

React前端框架

React 是一个用于构建用户界面的 JavaScript 库&#xff0c;由 Facebook 开发和维护。React 采用组件化的开发方式&#xff0c;使得开发者可以构建可复用的 UI 组件&#xff0c;从而提高开发效率和代码的可维护性。 React 的基本概念 组件&#xff1a;React 的核心概念是组件…...

React-query vs. 神秘新工具:前端开发的新较量

流畅的分页体验&#xff1a;AlovaJS的分页请求策略 在现代web应用中&#xff0c;分页是一个常见的功能需求。无论是浏览商品列表、查看文章集合&#xff0c;还是管理后台的数据表格&#xff0c;用户都需要一种高效且流畅的方式来浏览大量数据。然而&#xff0c;实现一个流畅且…...

TensorFlow面试整理-分布式

在深度学习的训练过程中,随着数据量和模型的复杂性增加,单个 GPU 或 CPU 无法满足高效训练的需求。TensorFlow 提供了强大的 分布式训练 功能,通过并行处理加速训练过程。分布式训练可以在多个 GPU、多个机器甚至是 TPU 上运行。以下是分布式训练的关键概念及其使用方法。 1…...

OceanBase 回收站机制详解

OceanBase 回收站机制详解 在 OceanBase 数据库中&#xff0c;回收站机制用于在执行 DROP 或 TRUNCATE 等操作后&#xff0c;临时保存被删除的对象&#xff0c;以便在需要时进行恢复。以下是对回收站机制的详细说明&#xff1a; 1. 不同租户对回收站的访问权限 SYS 租户 权…...

Java特工队:潜入京东,高效获取商品详情的绝密行动

在这个由代码和逻辑编织的电商世界里&#xff0c;京东商品详情就像是被锁在高塔中的神秘卷轴&#xff0c;等待着勇敢的Java特工队成员去解救。今天&#xff0c;我们要讲述的是如何装备你的Java代码装备&#xff0c;化身为一名编程界的特工&#xff0c;潜入京东的API网络&#x…...

车易泊相机 —— 智能车位管理的得力助手

在当今社会&#xff0c;停车问题日益成为城市管理和人们日常生活中的一大难题。寻找车位耗费时间、车位被非法占用、停车管理效率低下等问题层出不穷。然而&#xff0c;车易泊相机的出现&#xff0c;为车位管理带来了全新的解决方案。 一、车易泊相机的强大功能 车易泊相机是一…...

C++初阶(七)--类和对象(4)

目录 ​编辑 一、再谈构造函数 1.构造函数体赋值 2.初始化列表 二、类型转换 1.隐式类型转换 2.explicit关键字 3.类类型之间的对象隐式转换 三、static成员函数 1.概念 2.特性 3.面试题&#xff1a; 四、友元函数 1.基本介绍 2.回顾&#xff1a; 3.友元类&am…...

Crawl4AI浏览器配置文件创建与键盘交互处理终极指南:打造个性化爬虫身份

Crawl4AI浏览器配置文件创建与键盘交互处理终极指南&#xff1a;打造个性化爬虫身份 【免费下载链接】crawl4ai &#x1f525;&#x1f577;️ Crawl4AI: Open-source LLM Friendly Web Crawler & Scrapper 项目地址: https://gitcode.com/GitHub_Trending/craw/crawl4ai…...

OpenClaw任务编排:用Qwen3.5-4B-Claude实现爬虫+分析闭环

OpenClaw任务编排&#xff1a;用Qwen3.5-4B-Claude实现爬虫分析闭环 1. 为什么需要自动化任务编排 去年我接手了一个市场调研项目&#xff0c;需要每周从20多个网站抓取产品价格数据&#xff0c;清洗后生成趋势图表。最初用Python脚本手动Excel处理&#xff0c;每次要花3小时…...

量化模型精度补偿方案:百川2-13B-4bits在OpenClaw复杂推理中的表现提升

量化模型精度补偿方案&#xff1a;百川2-13B-4bits在OpenClaw复杂推理中的表现提升 1. 量化模型的精度挑战与补偿需求 当我第一次尝试将百川2-13B-4bits量化模型接入OpenClaw进行自动化任务处理时&#xff0c;遇到了一个典型问题&#xff1a;在简单的文件整理和网页操作任务中…...

2026年小学英语学习小程序排行榜

对于小学生而言&#xff0c;英语学习早已打破“只背单词、只刷习题”的单一模式&#xff0c;听、说、读、写全方位同步训练&#xff0c;才是提升英语能力的关键。2026年&#xff0c;市面上涌现出多款优质小学英语学习小程序&#xff0c;覆盖单词记忆、听力训练、阅读提升、语法…...

从安装到跑通第一个旋转立方体:Ubuntu 22.04 + OpenGL完整开发环境搭建实录

从零到旋转立方体&#xff1a;Ubuntu 22.04下OpenGL开发环境实战指南 刚接触图形编程时&#xff0c;最令人兴奋的莫过于看到自己编写的代码在屏幕上"活"起来。本文将带你从零开始&#xff0c;在Ubuntu 22.04系统上搭建完整的OpenGL开发环境&#xff0c;并最终实现一个…...

Mojo项目无法import本地.py模块?工程师连夜修复的6种路径/环境变量/Loader级配置错误

第一章&#xff1a;Mojo项目无法import本地.py模块的根本原因剖析Mojo 语言虽兼容 Python 语法&#xff0c;但其运行时环境与 CPython 截然不同——它基于 LLVM 编译为原生机器码&#xff0c;并通过 Mojo Runtime 执行&#xff0c;**不依赖 Python 解释器进程**。因此&#xff…...

这次终于选对了!降AI率软件深度测评与推荐

2026年真正好用的AI论文降重与改写工具&#xff0c;核心看降重效果、去AI味、格式保留、学术适配四大指标。综合实测&#xff0c;千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队&#xff0c;覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 …...

避坑指南:关系数据库设计中90%人会犯的完整性约束错误(附真实案例)

避坑指南&#xff1a;关系数据库设计中90%人会犯的完整性约束错误&#xff08;附真实案例&#xff09; 在电商大促期间&#xff0c;某平台突然出现大量"幽灵订单"——用户支付成功后订单消失&#xff0c;而库存却异常扣减。技术团队紧急排查发现&#xff0c;问题根源…...

OpenClaw安全指南:百川2-13B模型权限管控与敏感操作防护

OpenClaw安全指南&#xff1a;百川2-13B模型权限管控与敏感操作防护 1. 为什么需要安全防护机制 去年冬天的一个深夜&#xff0c;我的OpenClaw经历了一次"惊魂时刻"。当时我让AI助手整理财务表格&#xff0c;结果它误将包含个人银行账号的临时文件上传到了云存储。…...

避开这3个坑!用Solidworks链阵列做皮带挡板时90%人会犯的错误

避开这3个坑&#xff01;用Solidworks链阵列做皮带挡板时90%人会犯的错误 在机械设计领域&#xff0c;Solidworks的链阵列功能是创建皮带挡板这类重复性结构的利器。但看似简单的操作背后&#xff0c;却隐藏着几个容易导致失败的陷阱。很多中级用户在使用链阵列功能时&#xff…...