音视频入门基础:WAV专题(9)——FFmpeg源码中计算WAV音频文件每个packet的duration和duration_time的实现
一、引言
从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以显示WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的duration和duration_time:
这个“duration”实际是AVPacket结构体中的成员变量duration,为该音频packet占用的以AVStream的time_base为单位的时间值。而“duration_time”为该音频packet占用的以秒为单位的时间值。这两个值通过fftools/ffprobe.c中的show_packet函数打印出来:
static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int packet_idx)
{
//...print_duration_ts("duration", pkt->duration);print_duration_time("duration_time", pkt->duration, &st->time_base);
//...
}
本文讲述“duration”和“duration_time”的值是怎样被计算出来的。如果想直接看结论,可以跳到本文的最后,直接看“总结”。
二、FFmpeg源码中计算WAV音频文件每个packet的duration和duration_time的实现
(一)得到每个packet的duration
FFmpeg对WAV音频文件进行解封装(解复用)时,会调用avformat_find_stream_info函数,而该函数底层会调用compute_pkt_fields函数:
static void compute_pkt_fields(AVFormatContext *s, AVStream *st,AVCodecParserContext *pc, AVPacket *pkt,int64_t next_dts, int64_t next_pts)
{
//...if (pkt->duration <= 0) {compute_frame_duration(s, &num, &den, st, pc, pkt);if (den && num) {duration = (AVRational) {num, den};pkt->duration = av_rescale_rnd(1,num * (int64_t) st->time_base.den,den * (int64_t) st->time_base.num,AV_ROUND_DOWN);}}
//...
}
compute_pkt_fields函数内部,由于AVPacket结构体被初始化后,其成员变量duration会是0,(新版本的FFmpeg源码一般使用get_packet_defaults函数进行初始化,具体可以参考:《FFmpeg源码:av_init_packet、get_packet_defaults、av_packet_alloc函数分析》),所以会执行下面if语句为真时括号里的内容:
if (pkt->duration <= 0) {
//...
}
通过compute_frame_duration函数,让变量num被赋值为该音频packet占用的以AVStream的time_base为单位的时间值,让变量den被赋值为该音频的采样频率(单位为Hz):
compute_frame_duration(s, &num, &den, st, pc, pkt);
从文章《FFmpeg源码:compute_frame_duration函数分析》中可以知道,compute_frame_duration函数内部调用了av_get_audio_frame_duration2函数。而从《FFmpeg源码:get_audio_frame_duration、av_get_audio_frame_duration2函数分析》中可以知道,av_get_audio_frame_duration2函数内部又通过get_audio_frame_duration函数来计算某个音频packet占用的时间值。计算公式是:该音频packet占用的以AVStream的time_base为单位的时间值 = packet的大小(单位为字节)×8÷(音频的采样位数×声道数量),比如,某个音频packet的大小为16384字节、音频的采样位数为16位、声道数为2,则该音频packet占用的时间值(以AVStream的time_base为单位)为:16384×8÷(16×2)= 4096。
关于av_rescale_rnd函数的用法可以参考:《FFmpeg源码:av_rescale_rnd、av_rescale_q_rnd、av_rescale_q、av_add_stable函数分析》。最后通过av_rescale_rnd函数得到AVPacket结构体的成员变量duration。下面语句相当于执行了:pkt->duration = 1 × num × st->time_base.den ÷ (den × st->time_base.num):
pkt->duration = av_rescale_rnd(1,num * (int64_t) st->time_base.den,den * (int64_t) st->time_base.num,AV_ROUND_DOWN);
而从上面我们可以知道,变量num为该音频packet占用的以AVStream的time_base为单位的时间值,变量den为该音频的采样频率(单位为Hz)。根据《音视频入门基础:WAV专题(8)——FFmpeg源码中计算WAV音频文件AVStream的time_base的实现》我们又可以知道WAV音频文件AVStream的time_base(st->time_base)为音频采样频率的倒数。
所以语句pkt->duration = 1 × num × st->time_base.den ÷ (den × st->time_base.num)等价于
pkt->duration = num。
从而让AVPacket结构体中的成员变量duration可以被赋值为该音频packet占用的以AVStream的time_base为单位的时间值。
(二)得到每个packet的duration_time
duration和duration_time是通过fftools/ffprobe.c中的show_packet函数打印出来:
static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int packet_idx)
{
//...print_duration_ts("duration", pkt->duration);print_duration_time("duration_time", pkt->duration, &st->time_base);
//...
}
print_duration_time为宏定义:
#define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1)
而writer_print_time函数的定义为:
static void writer_print_time(WriterContext *wctx, const char *key,int64_t ts, const AVRational *time_base, int is_duration)
{char buf[128];if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT);} else {double d = ts * av_q2d(*time_base);struct unit_value uv;uv.val.d = d;uv.unit = unit_second_str;value_string(buf, sizeof(buf), uv);writer_print_string(wctx, key, buf, 0);}
}
其中,writer_print_time函数的形参ts为该音频packet占用的以AVStream的time_base为单位的时间值,形参time_base为AVStream的time_base。
关于av_q2d函数的用法可以参考:《FFmpeg有理数相关的源码:AVRational结构体和其相关的函数分析》。duration_time实际上是由writer_print_time函数中的下面语句计算出来的:
double d = ts * av_q2d(*time_base);
简单点来讲duration_time = duration × time_base。
三、总结
对于WAV音频文件:
AVPacket的“duration”为该音频packet占用的以AVStream的time_base为单位的时间值,其值等于: packet的大小(单位为字节)×8÷(音频的采样位数×声道数量),比如,某个音频packet的大小为16384字节、音频的采样位数为16位、声道数为2,则该音频packet的duration等于:16384×8÷(16×2)= 4096。
而“duration_time”为该音频packet占用的以秒为单位的时间值,其值等于:duration × time_base。比如,某个音频packet的duration为4096,time_base为44100分之一,其duration_time为4096乘以44100分之一,等于0.092880。
相关文章:

音视频入门基础:WAV专题(9)——FFmpeg源码中计算WAV音频文件每个packet的duration和duration_time的实现
一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以显示WAV音频文件每个packet(也称为数据包或多媒体包)的信息࿰…...

AI写的论文查重率高吗?分享6款实测AI论文生成免费网站
在当今学术研究和论文写作领域,AI技术的迅猛发展为研究人员提供了极大的便利。特别是AI论文自动生成助手,它们不仅能够提高写作效率,还能帮助生成高质量的论文内容。以下是六款经过实测且免费的AI论文生成网站推荐: 一、千笔-AIP…...

【专题】2024年8月中国企业跨境、出海、国际化、全球化行业报告汇总PDF合集分享(附原数据表)
原文链接: https://tecdat.cn/?p37584 在全球化浪潮汹涌澎湃的当下,中国企业积极探索海外市场,开启了出海跨境的新征程。本报告合集旨在全面梳理出海跨境全球化行业的发展态势,涵盖多个领域的深度洞察。 从游戏、快消品、医疗器…...

[算法]单调栈解法
目录 739. 每日温度 - 力扣(LeetCode) 42. 接雨水 - 力扣(LeetCode) 84. 柱状图中最大的矩形 - 力扣(LeetCode) 739. 每日温度 - 力扣(LeetCode) 解法: 通常是一维数…...
构建数据安全防线:MySQL数据备份策略的文档化实践
在数据驱动的商业环境中,数据备份策略是确保数据安全和业务连续性的关键。MySQL,作为广泛使用的数据库管理系统,其数据备份策略的文档化对于规范备份流程、提高恢复效率和满足合规要求至关重要。本文将深入探讨如何在MySQL中实现数据备份的策…...

4. GIS前端工程师岗位职责、技术要求和常见面试题
本系列文章目录: 1. GIS开发工程师岗位职责、技术要求和常见面试题 2. GIS数据工程师岗位职责、技术要求和常见面试题 3. GIS后端工程师岗位职责、技术要求和常见面试题 4. GIS前端工程师岗位职责、技术要求和常见面试题 5. GIS工程师岗位职责、技术要求和常见面试…...

软件测试-Selenium+python自动化测试
目录 会用到谷歌浏览器Chrome测试,需要下载一个Chromedriver(Chrome for Testing availability)对应自己的浏览器版本号选择。 一、元素定位 对html网页中的元素进行定位,同时进行部分操作。 1.1一个简单的模板 from selenium import webdriver from selenium.webdrive…...

SpringBoot与Minio的极速之旅:解锁文件切片上传新境界
目录 一、前言 二、对象存储(Object Storage)介绍 (1)对象存储的特点 (2)Minio 与对象存储 (3)对象存储其他存储方式的区别 (4)对象存储的应用场景 三、…...

Java 7.3 - 分布式 id
分布式 ID 介绍 什么是 ID? ID 就是 数据的唯一标识。 什么是分布式 ID? 分布式 ID 是 分布式系统中的 ID,它不存在于现实生活,只存在于分布式系统中。 分库分表: 一个项目,在上线初期使用的是单机 My…...

144. 腾讯云Redis数据库
文章目录 一、Redis 的主要功能特性二、Redis 的典型应用场景三、Redis 的演进过程四、Redis 的架构设计五、Redis 的数据类型及操作命令六、腾讯云数据库 Redis七、总结 Redis 是一种由 C 语言开发的 NoSQL 数据库,以其高性能的键值对存储和多种应用场景而闻名。本…...
基于单片机的自动浇花控制写设计任务书
一、内容要求: 任务 随着社会的进步,人们的生活质量越来越高。在家里养养盆花可以陶冶情操,丰富生活。同时盆花可以通过光合作用吸收二氧化碳,净化室内空气,在有花木的地方空气中阴离子聚集较多,所以空气…...

从零到精通:用C++ STL string优化代码
目录 1:为什么要学习string类 2:标准库中的string类 2.1:string类(了解) 2.2:总结 3:string类的常用接口 3.1:string类对象的常见构造 3.1.1:代码1 3.1.2:代码2 3.2:string类对象的遍历操作 3.2.1:代码1(begin end) 3.2.2:代码2(rbegin rend) 3.3:string类对象的…...

鸿蒙轻内核M核源码分析系列五 时间管理
往期知识点记录: 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总 持续更新中…… 在鸿蒙轻内核源码分析上一篇文章中,我们剖析了中断的源码,简单提到了Tick中断。本文会继续分析Tick和时间相关的源…...
Python Opencv鼠标回调
使用 OpenCV 的 cv2.setMouseCallback() 方法来捕捉鼠标事件,并实现以下功能: 实时在鼠标指针附近显示其位置的像素坐标。通过左键双击,将像素坐标记录到数组中。通过右键点击,取消上一次添加的坐标。 下面是实现代码的示例&…...

Ubuntu环境的MySql下载安装
下载压缩包 此文章下载的mysql版本位5.7.29 sudo wget https://downloads.mysql.com/archives/get/p/23/file/mysql-server_5.7.29-1ubuntu18.04_amd64.deb-bundle.tar解压缩 sudo tar -xvf mysql-server_5.7.29-1ubuntu18.04_amd64.deb-bundle.tar命令解释 -x:…...

Android系统去掉WIFI模块
先说应用场景,有些特定设备,不能连接wifi。需要隐藏的模块,QS面板模块的wifi,还有设置里面的wifi.由于QS属于SystemUI,熟悉SystemUI之后,就可以直接去SystemUi那里找,找到QSTitle 默认配置的地方。 一、…...
代码随想录 -- 二叉树 -- 翻转二叉树
226. 翻转二叉树 - 力扣(LeetCode) 递归比较简单 class Solution(object):def invertTree(self, root):if rootNone:returnnode rootif node.left or node.right:tempnode.leftnode.leftnode.rightnode.righttempself.invertTree(node.left)self.inve…...
Node.js之文件复制
1.方式一:readFile // 导入fs模块 const fs require("fs") // 导入process模块 const process require("process")// 读取文件内容 let data fs.writeFileSync(./test.txt) // 写入文件内容 fs.writeFileSync(./test1.txt, data) 2.方式二&…...

新手c语言讲解及题目分享(十六)--文件系统专项练习
在我刚开始学习c语言的时候就跳过了这一章节,但在后面慢慢发现这一章节还是比较重要的,如果你报考了计算机二级c语言的话,你应该可以看到后面的三个大题有时会涉及到这章。所以说这章还是非常重要的。 目录 前言 一.打开文件 1.Fopen( )函数返回值 2&…...

RabbitMQ本地Ubuntu系统环境部署与无公网IP远程连接服务端实战演示
文章目录 前言1.安装erlang 语言2.安装rabbitMQ3. 安装内网穿透工具3.1 安装cpolar内网穿透3.2 创建HTTP隧道 4. 公网远程连接5.固定公网TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 💡 推荐 前些天发现了一个巨牛的人工智能学习网站&am…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...

如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...