P11 FFmpe时间基和时间戳

 前言 

                             

从本章开始我们将要学习嵌入式音视频的学习了 ,使用的瑞芯微的开发板

🎬 个人主页:@ChenPi

🐻推荐专栏1: 《C++_@ChenPi的博客-CSDN博客》✨✨✨ 

🔥 推荐专栏2: 《Linux C应用编程(概念类)_@ChenPi的博客-CSDN博客》✨✨✨

🛸推荐专栏3:《嵌入式音视频_@ChenPi的博客-CSDN博客》
🌺本篇简介  :本章主要讲解ffmpeg中关于时间的概念,时间基和时间戳,时间转换,

                        时间比较

01  FFmpeg时间基与时间戳

1.1 时间基

时间基也叫时间基准,他代表的是每个刻度是多少秒。比方说视频的帧率为30FPS,那它的时间刻度为{1,30}。相当于1秒内划分出了30个等分,也就是每个30分之1秒显示一帧画面

 这里画的没有很严谨,大概就是这样

 结构体定义在rational.h这个头文件中

  • num:它是numerator的缩小,代表的是分子
  • den:它是denominator的缩小,代表的是分母

 视频时间基都是以帧率为单位,比方说50帧。FFmpeg就以AVRational video_base= {1,50}来表示

在音频时间基都是以采样率为单位,比方说音频采样率是48000HZ。

FFmpeg就以AVRational audio_timebase = {1,48000}来表示

对于分装格式而言:FLV封装格式的timebase为{1,1000},ts的封装格式timebase为{1,90000}

 

从上图ffplay的信息我们可以看到有很多关于时间基的信息:

  1. tbr:表示帧率,该帧率是一个基准,通常来说tbr和fps是一致的
  2. tbn:表示视频流timebase(时间基),比方说:TS格式的数据timebase是90000,flv格式的视频流timebase为1000
  3. tbc:表示视频流codec timebase,这个值一般为帧率的两倍。比方说:帧率是30fps,则tbc是60

 1.2 时间戳(PTS,DTS)

时间戳指的是单位时间轴内占了多少个格子,时间戳的单位不是具体的秒数,而是时间刻度。

只有时间基和时间戳结合在一起的时候,才能表达出时间是多少

比如以尺子为例:PTS = 30,timebase = {1,30},那么每个刻度就是1/30厘米了

所以这把尺子的长度 = pts * time_base = 30 * 1/30 = 1厘米

 PTS全称是Presentation Time Stamp(显示时间戳),它主要的作用是度量解码后的视频帧什么时候显示出来。

视频PTS计算:n为第n帧视频帧,timebase是{1framerate},fpsframerate

pts = n *(( 1 / timebase) / fps):

所以pts = pts++;

举例子:n = 1, pts = 1

        n = 2, pts = 2

        n =3, pts = 3

音频PTS计算:n为第n帧音频帧,nb_samples指的是采样个数(AAC默认1024),timebase是{1,samplerate},samplerate是采样率

num_pkt = samplerate/nb_samples

pts = n * ( ( 1/ timebase) / num_pkt)

pts = pts+1024

举例子:n = 1, pts = 1024

        n = 2, pts = 2048

        n = 3, pts = 3072

1.3 DTS

表示的是压缩解码的时间戳,在没有B帧的情况下PTS 等于 DTS。假设编码的里面引入了B帧,则还要计算B帧的时间。

没有B帧:dts = pts

存在B帧:dts = pts + b_time

 02 时间转换的原理:

在FFMPEG中由于不同的复合流,时间基是不同的,比方说:ts的时间基time_base= {1,90000},假设一个视频time_base = {1,30},我们需要合成mpegts文件,它就需要把time_base = {1,30}占的格子转换成time_base = {1,90000}占的格子。

  

在FFMPEG中用以下的API进行时间基转换:

  

void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst);

上面这个api的用法是,把AVPacket的时间基tb_src转换成时间基tb_dst

  • 第一个参数:AVPacket结构体指针
  • 第二个参数:源时间基
  • 第三个参数:目的时间基

下面我们用H264和AAC时间基TS转换的例子来说明这个转换时间基的用法:

视频H264时间基转换成MPEGTS时间基:

**DST_VIDEO_PTS = VIDEO_PTS * VIDEO_TIME_BASE / DST_TIME_BASE

H264 {1,30}                                              MPEGTS {1,90000}

pts = 1                                                       pts = 3000

pts = 2            av_packet_rescale_ts      pts = 6000

pts = 3                                                       pts = 9000

pts = 4                                                       pts = 12000

                                           

音频AAC时间基转换成MPEGTS时间基:

**DST_AUDIO_PTS = AUDIO_PTS * AUDIO_TIME_BASE / DST_TIME_BASE

AAC {1,48000}                                           MPEGTS {1,90000}

pts =1024                                                    pts = 1920

pts =2048           av_packet_rescale_ts    pts = 3840

pts =3072                                                    pts = 5760

pts =4096                                                    pts = 7680

从上述推导的结果可以看出来,如果使用av_packet_rescale_ts的API对视频时间基进行转换,实际上是使用DST_VIDEO_PTS = VIDEO_PTS * VIDEO_TIME_BASE / DST_TIME_BASE去计算推流的视频时间戳。

同理用av_packet_rescale_ts对音频时间基进行转换,实际上是使用DST_AUDIO_PTS = AUDIO_PTS * AUDIO_TIME_BASE / DST_TIME_BASE去计算我们真实推流的音频时间戳。

以上图来看的话就是DST_AUDIO_PTS  = 1024 * 1/48000/1/96000

  03 FFMPEG时间戳的比较:

    

int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b)
  1. 第一个参数:ts_a它指的是当前相对tb_a的时间戳
  2. 第二个参数:ts_a相对应的时间基
  3. 第三个参数:ts_b它指的是当前相对tb_a的时间戳
  4. 第四个参数:ts_b相对应的时间基

返回值判断:

当ret == -1, ts_a的时间戳快过ts_b时间戳。

当ret ==  1, ts_a的时间戳慢过ts_b时间戳。

当ret ==  0, ts_a的时间戳等于ts_b时间戳

av_compare_ts它的主要作用是进行时间戳进行实时比较,它能够实时保证当前的时间戳是准确无误的。它不会出现时间戳混乱的情况,所谓混乱的情况就相当于:视频时间戳当成音频时间戳处理,音频时间戳当成视频时间戳处理。

下面这张图是编码视频、音频然后进行时间戳比较然后合成复合流的流程:

  

视频时间戳参考视频帧率进行比较、音频时间戳进行比较(这里我们默认tb_a时间基是视频时间基、tb_b时间基是音频时间基)。所以当比较的结果ret <= 0的时候,则要取出视频数据,否则就取出音频数据。取出视频数据后则利用av_packet_rescale_ts进行时间转换、同样取出音频数据后也要对其进行时间转换。音视频数据进行时间转换后,则用av_interleaved_write_frame对复合流进行写入操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/231490.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣1944.队列中可以看到的人数--单调栈

思路&#xff1a; 由题知一个人能 看到 他右边另一个人的条件是这两人之间的所有人都比他们两人 矮 &#xff0c;也就是说&#xff0c;在自己右边第一个比自己高的人后面的人就肯定看不到了那么只需要找到右边第一个比自己高的人与自己之间的所有满足要求的人就行了&#xff0…

mysql保姆安装教程

前言&#xff1a;考完研回来&#xff0c;重新配置数据库的相关环境&#xff0c;按照本方法安装请确保你之前的MySQL已完全清除干净。 一.下载install文件 1.进入Mysql官网&#xff0c;点击下载 2.选择MySQL Installer for Windows 3.推荐选择第二个安装包 4.不登陆&#xff0c…

23 导航栏

效果演示 实现了一个响应式的导航栏&#xff0c;当鼠标悬停在导航栏上的某个选项上时&#xff0c;对应的横条会从左到右地移动&#xff0c;从而实现了导航栏的动态效果。 Code <div class"flex"><ul><li>1</li><li>2</li><l…

怎么快速修复mfc140.dll文件?解决mfc140.dll缺失的方法

面对计算机报告的 ​mfc140.dll​ 文件遗失错误&#xff0c;这通常表明系统中缺少一个关键的动态链接库文件&#xff0c;该文件对于运行以 Microsoft Foundation Class (MFC) 库编写的程序十分重要&#xff0c;尤其是那些需要图形界面的应用程序和一些游戏。若没有这个文件&…

【AI视野·今日Robot 机器人论文速览 第六十六期】Tue, 31 Oct 2023

AI视野今日CS.Robotics 机器人学论文速览 Tue, 31 Oct 2023 Totally 39 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers DEFT: Dexterous Fine-Tuning for Real-World Hand Policies Authors Aditya Kannan, Kenneth Shaw, Shikhar Bahl, Pragna Ma…

【Minikube Prometheus】基于Prometheus Grafana监控由Minikube创建的K8S集群

文章目录 1. 系统信息参数说明2. Docker安装3. minikube安装4. kubectl安装5. Helm安装6. 启动Kubernetes集群v1.28.37. 使用helm安装Prometheus8. 使用helm安装Grafana9. Grafana的Dashboard设定10. 设定Prometheus数据源11. 导入Kubernetes Dashboard12. 实验过程中的常见问题…

软件设计模式 --- 类,对象和工厂模式的引入

Q1&#xff1a;什么是软件设计模式&#xff1f; A&#xff1a;软件设计模式&#xff0c;又称设计模式。它是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。综上&…

vmware安装redhat 7.6 操作系统

vmware安装redhat 7.6 操作系统 1、下载redhat 7.6 操作系统镜像文件2、安装redhat 7.6操作系统3、配置redhat 7.6 操作系统3.1、配置静态IP地址 和 dns3.2、查看磁盘分区3.3、查看系统版本 1、下载redhat 7.6 操作系统镜像文件 链接: 盘盘 zwzg 文件名&#xff1a;rhel-serv…

JVM 常用知识和面试题

1. 什么是JVM内存结构&#xff1f; jvm将虚拟机分为5大区域&#xff0c;程序计数器、虚拟机栈、本地方法栈、java堆、方法区&#xff1b; 程序计数器&#xff1a;线程私有的&#xff0c;是一块很小的内存空间&#xff0c;作为当前线程的行号指示器&#xff0c;用于记录当前虚拟…

LeetCode-无重复字符的最长子串(3)

题目描述&#xff1a; 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 代码&#xff1a; class Solution {public int lengthOfLongestSubstring(String s) {Set<Character> occnew HashSet<Character>();int lens.length();int…

OpenCASCADE MFC例子

OpenCASCADE MFC例子 说明 一直对OpenCASCADE一直都比较感兴趣&#xff0c;这个例子是我参考这位大神C幼儿园中班小朋友的专栏做出来的OpenCASCADE_C幼儿园中班小朋友的博客-CSDN博客 不过我用的是vcpkg的方式安装OpenCASCADE&#xff0c;这个需要注意一下&#xff0c;可能需…

HackTheBox - Medium - Linux - Awkward

Awkward Awkward 是一款中等难度的机器&#xff0c;它突出显示了不会导致 RCE 的代码注入漏洞&#xff0c;而是 SSRF、LFI 和任意文件写入/追加漏洞。此外&#xff0c;该框还涉及通过不良的密码做法&#xff08;例如密码重用&#xff09;以及以纯文本形式存储密码来绕过身份验…

Mybatis缓存实现方式

文章目录 装饰器模式Cache 接口及核心实现Cache 接口装饰器1. BlockingCache2. FifoCache3. LruCache4. SoftCache5. WeakCache 小结 缓存是优化数据库性能的常用手段之一&#xff0c;我们在实践中经常使用的是 Memcached、Redis 等外部缓存组件&#xff0c;很多持久化框架提供…

【物联网】手把手完整实现STM32+ESP8266+MQTT+阿里云+APP应用——第3节-云产品流转配置

&#x1f31f;博主领域&#xff1a;嵌入式领域&人工智能&软件开发 本节目标&#xff1a;本节目标是进行云产品流转配置为后面实际的手机APP的接入做铺垫。云产品流转配置的目的是为了后面能够让后面实际做出来的手机APP可以控制STM32/MCU&#xff0c;STM32/MCU可以将数…

【自学笔记】01Java基础-07面向对象基础-01封装

记录学习Java基础中有关面向对象编程的基础知识&#xff0c;包括面向对象思想&#xff0c;构造方法&#xff0c;封装思想&#xff0c;JavaBean。 1 面向对象概述 1.1 什么是面向对象编程 严谨来说&#xff1a;   面向对象编程&#xff08;Object-Oriented Programming&…

《深入理解Java虚拟机(第三版)》读书笔记:虚拟机类加载机制、虚拟机字节码执行引擎、编译与优化

下文是阅读《深入理解Java虚拟机&#xff08;第3版&#xff09;》这本书的读书笔记&#xff0c;如有侵权&#xff0c;请联系删除。 文章目录 第6章 类文件结构第7章 虚拟机类加载机制7.2 类加载的时机7.3 类加载的过程7.4 类加载器7.5 Java模块化系统 第8章 虚拟机字节码执…

手动创建idea SpringBoot 项目

步骤一&#xff1a; 步骤二&#xff1a; 选择Spring initializer -> Project SDK 选择自己的JDK版本 ->Next 步骤三&#xff1a; Maven POM ->Next 步骤四&#xff1a; 根据JDK版本选择Spring Boot版本 11版本及以上JDK建议选用3.2版本&#xff0c;JDK为11版本…

大数据 - 大数据入门第一篇 | 关于大数据你了解多少?

&#x1f436;1.1 概述 大数据&#xff08;BigData):指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合&#xff0c;是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。 大数据主要解决、海量数据的采…

torch.meshgrid和np.meshgrid的区别

numpy中meshgrid&#xff1a; 把数组a当作一行&#xff0c;再根据数组b的长度扩充行。 把数组b当作一列&#xff0c;再根据数组a的长度扩充列。 torch中meshgrid&#xff1a; 把数组a当作一列&#xff0c;再根据数组b的长度扩充列。 把数组b当作一行&#xff0c;再根据数组a的…

最优化理论期末复习笔记 Part 2

数学基础线性代数 从行的角度从列的角度行列式的几何解释向量范数和矩阵范数 向量范数矩阵范数的更强的性质的意义 几种向量范数诱导的矩阵范数 1 范数诱导的矩阵范数无穷范数诱导的矩阵范数2 范数诱导的矩阵范数 各种范数之间的等价性向量与矩阵序列的收敛性 函数的可微性与展…