音视频入门基础:FLV专题(22)——FFmpeg源码中,获取FLV文件音频信息的实现(中)
本文接着《音视频入门基础:FLV专题(21)——FFmpeg源码中,获取FLV文件音频信息的实现(上)》,继续讲解FFmpeg获取FLV文件的音频信息到底是从哪个地方获取的。本文的一级标题从“四”开始。
四、音频采样率
(一)FFmpeg源码中,获取FLV文件音频采样率的实现
FLV文件中名称为“onMetadata”的Script Tag、每个Audio Tag的AudioTagHeader、AudioSpecificConfig都包含音频采样率信息。但是FFmpeg获取FLV文件的音频采样率,是从AudioSpecificConfig的samplingFrequencyIndex属性中获取的、而忽略另外两个地方的音频采样率信息。
由《音视频入门基础:AAC专题(11)——AudioSpecificConfig简介》可以知道,FLV文件中的音频为AAC时,正常情况下它必定存在一个Audio Tag包含Audio Specific Config,而Audio Specific Config中存在一个占4位的samplingFrequencyIndex属性,表示音频的采样频率:
由《音视频入门基础:AAC专题(12)——FFmpeg源码中,解码AudioSpecificConfig的实现》可以知道,ff_mpeg4audio_get_config_gb函数中,通过语句:c->sample_rate = get_sample_rate(gb, &c->sampling_index)获取AudioSpecificConfig的samplingFrequencyIndex属性。执行decode_audio_specific_config_gb函数后,m4ac指向的变量会得到从AudioSpecificConfig中解码出来的属性:
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];
}
然后在decode_audio_specific_config_gb函数外部,通过aac_decode_frame_int函数将上一步得到的samplingFrequencyIndex属性赋值给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函数中将profile打印出来:
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);}
//...}
//...
}
(二)修改Audio Specific Config中的samplingFrequencyIndex属性验证
下面我们做一个验证:
FLV文件video1.flv的Audio Specific Config中的samplingFrequencyIndex属性的值为4,对应的音频采样频率为44100Hz:
用ffmpeg -i video1.flv命令可以查看到video1.flv文件的音频采样频率为44100Hz:
我们用Notepad++修改video1.flv文件的Audio Specific Config中的samplingFrequencyIndex属性,把它的值从4改为0。修改完成后把文件名称改为“video1_AudioSpecificConfig.flv”:
用flvAnalyser工具打开修改后的FLV文件video1_AudioSpecificConfig.flv,可以看到Audio Specific Config中的samplingFrequencyIndex属性的值确实被修改为了0,对应音频采样频率变为了96000Hz:
用“ffmpeg -i video1_AudioSpecificConfig.flv”命令可以查看到FLV文件的音频采样频率确实变为96000Hz了:
用ffplay播放video1_AudioSpecificConfig.flv会发现没有声音,从而证明FFmpeg获取FLV文件的音频采样率,是从AudioSpecificConfig的samplingFrequencyIndex属性中获取的。由于video1_AudioSpecificConfig.flv文件的samplingFrequencyIndex属性被修改了, 所以它的音频采样频率信息不正确,导致用ffplay播放不出来:
但是要注意的是:每种音视频SDK和音视频播放器获取音频采样率的位置都不同,比如FFmpeg是从AudioSpecificConfig的samplingFrequencyIndex属性中获取的,但是VLC是从Audio Tag的AudioTagHeader中获取的。
用VLC播放video1_AudioSpecificConfig.flv,会发现其显示的音频采样频率还是修改前的44100Hz,可以正常播放声音。因为VLC获取FLV文件的音频采样频率是从Audio Tag的AudioTagHeader中获取:
五、音频声道数
(一)FFmpeg源码中,获取FLV文件音频声道数的实现
FLV文件中名称为“onMetadata”的Script Tag、每个Audio Tag的AudioTagHeader、AudioSpecificConfig都包含音频声道数信息。FFmpeg获取FLV文件的音频声道数,主要是从Audio Tag的AudioTagHeader中的SoundType属性获取的。
由《音视频入门基础:FLV专题(18)——Audio Tag简介》可以知道,Audio Tag的AudioTagHeader中存在一个占1位的SoundType属性,表示音频声道数:
0:单声道
1:立体声
由《音视频入门基础:FLV专题(19)——FFmpeg源码中,解码Audio Tag的AudioTagHeader,并提取AUDIODATA的实现》可以知道,FFmpeg源码中使用flv_read_packet函数来读取每个Tag的信息。如果判断出该Tag为Audio Tag,flv_read_packet函数中会通过下面代码块将AudioTagHeader的SoundType属性提取出来,转换得到音频音频声道数。将音频声道数目存贮到局部变量channels中:
channels = (flags & FLV_AUDIO_CHANNEL_MASK) == FLV_STEREO ? 2 : 1;
将上述得到的音频声道数目赋值给st->codecpar->ch_layout。st->codecpar为指向一个AVCodecParameters类型变量的指针:
if (!av_channel_layout_check(&st->codecpar->ch_layout) ||!st->codecpar->sample_rate ||!st->codecpar->bits_per_coded_sample) {av_channel_layout_default(&st->codecpar->ch_layout, channels);//...}
然后在flv_read_packet函数外部,通过avcodec_parameters_to_context函数将AVCodecParameters的ch_layout赋值给AVCodecContext的ch_layout:
int avcodec_parameters_to_context(AVCodecContext *codec,const AVCodecParameters *par)
{
//...switch (par->codec_type) {case AVMEDIA_TYPE_AUDIO:ret = av_channel_layout_copy(&codec->ch_layout, &par->ch_layout);//....break;}
//...
}
然后在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;}
//...
}
(二)修改Audio Specific Config中的channelConfiguration属性验证
下面我们做一个验证:
FLV文件video1.flv的Audio Tag的AudioTagHeader中的SoundType属性值为1,对应的音频声道数为立体声(双声道)。这里由于flvAnalyser工具的局限性没办法直接看到AudioTagHeader中的SoundType属性,但是按照《音视频入门基础:FLV专题(18)——Audio Tag简介》中讲述的格式,自己换算一下SoundType的值就出来了。0xAF等于二进制的0b10101111,SoundFormat占4位,SoundRate占2位,SoundSize占1位,所以这里SoundType的值就是1:
该文件的Audio Specific Config中的channelConfiguration属性的值为2,对应的音频声道数也为双声道:
用ffmpeg -i video1.flv命令可以查看到video1.flv文件的音频声道数为双声道:
我们用Notepad++修改video1.flv文件的Audio Specific Config中的channelConfiguration属性,把它的值从2改为1。修改完成后把文件名称改为“video1_AudioSpecificConfig1.flv”。用flvAnalyser工具打开修改后的FLV文件video1_AudioSpecificConfig1.flv,可以看到Audio Specific Config中的channelConfiguration属性的值确实被修改为了1,对应音频声道数为单声道:
但是用“ffmpeg -i video1_AudioSpecificConfig1.flv”命令查看到FLV文件,发现其音频声道数还是为双声道。因为FFmpeg获取FLV文件的音频声道数,主要是从Audio Tag的AudioTagHeader中的SoundType属性获取,所以修改Audio Specific Config中的channelConfiguration属性对音频声道数没有影响:
但是这并不意味着对FFmpeg源码来讲,Audio Specific Config中的channelConfiguration属性没有意义,相反FFmpeg同样会参考channelConfiguration属性。比如,把Audio Specific Config中的channelConfiguration属性修改为4,重新使用“ffmpeg -i video1_AudioSpecificConfig1.flv”命令,会发现报错:“channel element 1.0 is not allocated”:
把Audio Specific Config中的channelConfiguration属性修改为0,重新使用“ffmpeg -i video1_AudioSpecificConfig1.flv”命令,会发现报错:“ Could not find codec parameters for stream 1 (Audio: aac, 44100 Hz, 0 channels, fltp, 136 kb/s): unspecified number of channels
”:
所以FFmpeg获取FLV文件的音频声道数,主要是从Audio Tag的AudioTagHeader中的SoundType属性获取,但是它也会参考Audio Specific Config中的channelConfiguration属性。
六、FFmpeg获取FLV文件音频采样率和音频声道数总结
从上面我们可以知道,FLV文件中名称为“onMetadata”的Script Tag、每个Audio Tag的AudioTagHeader、AudioSpecificConfig都会包含音频信息,每种音视频SDK或者音视频播放器获取音频信息时获取的位置和策略可能都不一样。所以很多时候我们播放FLV文件音频的时候,会发现用ffplay能播,但用vlc无法播放;或者反过来用vlc能播,但是用ffplay无法播放。当FLV文件中某些地方的音频信息不正确,但是其它地方音频信息正确时,就会发生某些播放器能正常播放,其它播放器无法播放的情况。所以一定要搞清楚我们使用的音视频SDK和播放器到底获取的是哪个位置的音频信息。
相关文章:

音视频入门基础:FLV专题(22)——FFmpeg源码中,获取FLV文件音频信息的实现(中)
本文接着《音视频入门基础:FLV专题(21)——FFmpeg源码中,获取FLV文件音频信息的实现(上)》,继续讲解FFmpeg获取FLV文件的音频信息到底是从哪个地方获取的。本文的一级标题从“四”开始。 四、音…...

Chrome与火狐哪个浏览器的性能表现更好
在数字时代,浏览器是我们日常生活中不可或缺的工具。无论是工作、学习还是娱乐,一个好的浏览器都能显著提高我们的效率和体验。市场上有许多优秀的浏览器,其中Google Chrome和Mozilla Firefox无疑是最受欢迎的两款。本文将比较这两款浏览器的…...
uniapp在js方法中,获取当前用户的uid(uni-id-user)表中的用户id
// 1.判断当前用的权限 let uid uniCloud.getCurrentUserInfo().uid //获取当前用户的uid // 用户uid等于发布者id或者用户权限等于admin或者用户角色等于webmaster if (uid this.item.user_id[0]._id || this.uniIDHasRole…...

影响神经网络速度的因素- FLOPs、MAC、并行度以及计算平台
影响神经网络速度的四个主要因素分别是 FLOPs(浮点操作数)、MAC(内存访问成本)、并行度以及计算平台。这些因素共同作用,直接影响到神经网络的计算速度和资源需求。 1. FLOPs(Floating Point Operations&a…...

【万字详解】如何在微信小程序的 Taro 框架中设置静态图片 assets/image 的 Base64 转换上限值
设置方法 mini 中提供了 imageUrlLoaderOption 和 postcss.url 。 其中: config.limit 和 imageUrlLoaderOption.limit 服务于 Taro 的 MiniWebpackModule.js , 值的写法要 ()KB * 1024。 config.maxSize 服务于 postcss-url 的…...
复合选择器,CSS特性,背景属性,显示模式(HTML)
目录 复合选择器,CSS特性,背景属性,显示模式知识点: 练习一: 练习二: 复合选择器,CSS特性,背景属性,显示模式知识点: 复合选择器:后代选择器 :父选择器 子选择器(中间用空格隔开) eg:对div中的span进行设置,会对后代中的所有span都进行设置 选中所有后代(后代选择器.html)…...

加密货币行业与2024年美国大选
加密货币行业经历了近十年的飞速发展,尤其是在比特币、以太坊等主要加密资产的兴起之后,越来越多的美国人开始将其视为一种财富积累或交易的工具。然而,尽管这一新兴行业的市场规模在持续扩大,但加密货币仍面临着重重监管难题&…...
Hive SQL中判断内容包含情况的全面指南
Hive SQL中判断内容包含情况的实用指南 在 Hive SQL 的数据处理与分析世界里,判断字段是否包含特定内容是一项非常重要的操作。今天,我将为大家详细介绍 Hive SQL 中实现这一功能的多种方法,并附上相应的表创建和数据插入语句。 一、准备工作 - 表创建与数据插入 首先,我…...

匿名管道 Linux
目录 管道 pipe创建一个管道 让子进程写入,父进程读取 如何把消息发送/写入给父进程 父进程该怎么读取呢 管道本质 结论:管道的特征: 测试管道大小 写端退了,测试结果 测试子进程一直写,父进程读一会就退出 …...
苍穹外卖WebSocket无法建立连接 (修改前端代码)
我在部署nginx 反向代理服务器时,把80端口改成了90端口(不与80端口的Tomcat冲突)。 但黑马的资料里定义了前端连接nginx的端口号默认为80,造成连接不上的问题,此时只需要修改前端的端口号,使其知道如何连接到修改后的后端端口。 …...
音频内容理解
音频内容理解是音频处理和理解领域的一个重要方向,它涉及到从环境声音中提取语义信息,并能够对这些声音进行解释和描述。以下是音频内容理解的几个关键应用: 1. 音频问答(Audio Question Answering, AQA) 在这个任务…...

MQTT实用示例集:Air201版
今天贴出的是Air201版关于MQTT实用示例集,希望大家喜欢。 本示例教你通过使用脚本代码,对Air201模组进行MQTT链接操作。 操作例程包括: MQTT单链接 MQTT多链接 MQTT SSL不带证书链接 MQTT SSL带证书链接 大家可根据自身需求,…...
Day23 opencv图像预处理
图像预处理 在计算机视觉和图像处理领域,图像预处理是一个重要的步骤,它能够提高后续处理(如特征提取、目标检测等)的准确性和效率。OpenCV 提供了许多图像预处理的函数和方法,常见的操作包括图像空间转换、图像大小调…...

优化模型训练过程中的显存使用率、GPU使用率
参考:https://blog.51cto.com/u_16099172/7398948 问题:用小数据集训练显存使用率、GPU使用率正常,但是用大数据集训练GPU使用率一直是0. 小数据: 大数据: 1、我理解GPU内存占用率显存使用率,由模型的大小…...

RocketMQ学习笔记
RocketMQ笔记 文章目录 一、引言⼆、RocketMQ介绍RocketMQ的由来 三、RocketMQ的基本概念1 技术架构2 部署架构 四、快速开始1.下载RocketMQ2.安装RocketMQ3.启动NameServer4.启动Broker5.使⽤发送和接收消息验证MQ6.关闭服务器 五、搭建RocketMQ集群1.RocketMQ集群模式2.搭建主…...

Linux第三讲:环境基础开发工具使用
Linux第三讲:环境基础开发工具使用 1.Linux软件包管理器yum1.1什么是软件包管理器1.2操作系统生态问题1.3什么是yum源 2.vim详解2.1什么是vim2.2vim的多模式讲解2.2.1命令模式的诸多指令2.2.1.1gg和nshiftg2.2.1.2shift$和shift^2.2.1.3上、下、左、右2.2.1.4w和b2.…...
日本TikTok直播的未来:专线网络助力创作者突破极限
近年来,随着短视频平台的崛起,尤其是TikTok(国际版抖音)成为全球范围内广受欢迎的社交娱乐平台,直播功能的加入无疑为内容创作者提供了更广阔的展示舞台。在日本,TikTok直播不仅使得年轻人能够实时与粉丝互…...
如何在家庭网络中设置静态IP地址:一份实用指南
在家庭网络环境中,IP地址扮演着至关重要的角色。大多数家庭用户依赖路由器的DHCP(动态主机配置协议)来自动分配IP地址,但在某些情况下,手动设置静态IP地址能为家庭网络带来更多的便利性与稳定性,尤其是在涉…...

qt QFile详解
1、概述 QFile类是Qt框架中用于读取和写入文本和二进制文件资源的I/O工具类。它继承自QFileDevice类,后者又继承自QIODevice类。QFile类提供了一个接口,允许开发者以二进制模式或文本模式对文件进行读写操作。默认情况下,QFile假定文件内容为…...

ESP8266 自定义固件烧录-Tcpsocket固件
一、固件介绍 固件为自定义开发的一个适配物联网项目的开源固件,支持网页配网、支持网页tcpsocket服务器配置、支持串口波特率设置。 方便、快捷、稳定! 二、烧录说明 固件及工具打包下载地址: https://download.csdn.net/download/flyai…...

剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分: 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...
华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)
题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...

HTTPS证书一年多少钱?
HTTPS证书作为保障网站数据传输安全的重要工具,成为众多网站运营者的必备选择。然而,面对市场上种类繁多的HTTPS证书,其一年费用究竟是多少,又受哪些因素影响呢? 首先,HTTPS证书通常在PinTrust这样的专业平…...
StarRocks 全面向量化执行引擎深度解析
StarRocks 全面向量化执行引擎深度解析 StarRocks 的向量化执行引擎是其高性能的核心设计,相比传统行式处理引擎(如MySQL),性能可提升 5-10倍。以下是分层拆解: 1. 向量化 vs 传统行式处理 维度行式处理向量化处理数…...