概念

PTS(Presentation Time Stamp)显示时间戳

  • 表示:该帧应该在什么时间被显示/播放
  • 主要用于:同步音频与视频,控制播放节奏。
  • 举例:视频帧 A 的 PTS 是 300ms,表示应在视频播放第 300 毫秒时显示。

DTS(Decoding Time Stamp)解码时间戳

  • 表示:该帧应该在什么时间被解码
  • 主要用于:解码器按正确顺序解码帧(尤其对于有 B 帧的视频)。

作用

因为视频编码中存在帧的重排序:

编码时为了压缩率更高,视频通常采用如下三种帧类型:

  • I帧(关键帧):可以独立解码。
  • P帧(预测帧):依赖前面的帧。
  • B帧(双向预测帧):依赖前后帧。

这就导致:

显示顺序 ≠ 解码顺序

因此,必须使用 PTS 控制显示顺序,使用 DTS 控制解码顺序

示例

假设视频帧顺序如下(按显示顺序):

帧类型显示顺序 (PTS)解码顺序 (DTS)
I00
B12
B23
P31

解码器必须这样处理:

  1. 先解码 I(DTS=0)
  2. 再解码 P(DTS=1)
  3. 然后可以解码 B(DTS=2,依赖 I 和 P)
  4. 然后解码下一帧 B(DTS=3)

但播放时按照 PTS 排序:I → B → B → P

赋值

1. 没有B帧的情况(PTS = DTS)

例如只使用 I 帧 + P 帧:

int64_t pts = frame_index * frame_interval;  // 单位:时间基(如1/90000)
int64_t dts = pts;
  • frame_interval = 时间基 / 帧率,例如:1/25fps => 每帧间隔 3600(如果时间基是 90000)

2. 有B帧的情况(PTS ≠ DTS)

例如 IBBP 结构(假设 GOP = IPBBP):

  • 编码顺序:I P B B P
  • 显示顺序:I B B P P
帧类型编码顺序DTSPTS
I000
P113
B221
B332
P444

通常:PTS = 显示顺序 * frame_interval,DTS = 编码顺序 * frame_interval。

这种关系在 H.264/H.265 中通过 AVC reorder bufferDecoding Order Number (DON) 推导。

示例

  • 帧率:25fps → 每帧间隔 3600(以时间基 1/90000 为例)
  • GOP结构:I B B P 循环
  • 显示顺序:I B B P I B B P ...
  • 编码顺序:I P B B I P B B ...

代码(c++):

#include <iostream>
#include <vector>
#include <string>
#include <map>enum FrameType {I_FRAME,P_FRAME,B_FRAME
};struct Frame {int display_index;   // 显示顺序编号int encode_index;    // 编码顺序编号int64_t pts;         // 显示时间戳int64_t dts;         // 解码时间戳FrameType type;
};// 模拟一个 GOP(IBBP)
std::vector<Frame> generate_gop_with_bframes(int gop_size, int frame_interval) {std::vector<Frame> display_order; // 显示顺序std::vector<Frame> encode_order;  // 编码顺序// 构造 GOP:显示顺序 I B B P(假设gop_size是4或其倍数)for (int gop_index = 0; gop_index < gop_size / 4; ++gop_index) {int base = gop_index * 4;display_order.push_back({base + 0, -1, 0, 0, I_FRAME});display_order.push_back({base + 1, -1, 0, 0, B_FRAME});display_order.push_back({base + 2, -1, 0, 0, B_FRAME});display_order.push_back({base + 3, -1, 0, 0, P_FRAME});}// 编码顺序为 I P B Bfor (int gop_index = 0; gop_index < gop_size / 4; ++gop_index) {int base = gop_index * 4;encode_order.push_back({base + 0, -1, 0, 0, I_FRAME});encode_order.push_back({base + 3, -1, 0, 0, P_FRAME});encode_order.push_back({base + 1, -1, 0, 0, B_FRAME});encode_order.push_back({base + 2, -1, 0, 0, B_FRAME});}// 构建最终帧列表,赋值PTS(按显示顺序)和 DTS(按编码顺序)std::map<int, Frame> frame_map;for (size_t i = 0; i < display_order.size(); ++i) {int display_index = display_order[i].display_index;frame_map[display_index].display_index = display_index;frame_map[display_index].pts = i * frame_interval;frame_map[display_index].type = display_order[i].type;}for (size_t i = 0; i < encode_order.size(); ++i) {int display_index = encode_order[i].display_index;frame_map[display_index].encode_index = i;frame_map[display_index].dts = i * frame_interval;}// 按编码顺序输出结果std::vector<Frame> result;for (const auto& [_, frame] : frame_map) {result.push_back(frame);}// 根据 DTS 排序std::sort(result.begin(), result.end(), [](const Frame& a, const Frame& b) {return a.dts < b.dts;});return result;
}std::string frame_type_str(FrameType type) {switch (type) {case I_FRAME: return "I";case P_FRAME: return "P";case B_FRAME: return "B";default: return "?";}
}int main() {int gop_size = 8;  // 2组 IBBPint fps = 25;int time_base = 90000;int frame_interval = time_base / fps;std::vector<Frame> frames = generate_gop_with_bframes(gop_size, frame_interval);std::cout << "Idx\tType\tPTS\t\tDTS\n";for (const auto& f : frames) {std::cout << f.display_index << "\t" << frame_type_str(f.type)<< "\t" << f.pts << "\t" << f.dts << "\n";}return 0;
}

结果输出:

Idx	Type	PTS		DTS
0	I	0		0
3	P	10800	3600
1	B	3600	7200
2	B	7200	10800
4	I	14400	14400
7	P	25200	18000
5	B	18000	21600
6	B	21600	25200

时间基

概念

时间基是一个分数,表示时间戳的单位,即:

1 time_base = 1 / 秒数

通俗讲:

如果时间基是 {1, 25},则时间戳单位为 1/25 秒,每递增 1,表示时间过去了 1/25 秒(即一帧)。

使用场景

场景用途说明
编码器 time_base控制 frame->pts 的单位
AVStream time_base控制 packet->pts/dts 在封装文件中的时间戳单位
音视频同步不同 stream 间通过统一时间基换算进行对齐
时间戳转换不同模块交互时需要 av_rescale_q() 进行换算

常见时间基含义

时间基 {num, den}表示含义常见用途
{1, 25}每单位 = 1/25 秒25fps 视频
{1, 1000}每单位 = 1msMP4/FLV 封装层常用
{1, 90000}每单位 = 1/90000 秒MPEG-TS、RTSP 常用
{1, 48000}每单位 = 一个采样周期48kHz 音频
{1, AV_TIME_BASE}每单位 = 微秒(1/1000000s)FFmpeg 通用时间单位

设置建议

视频编码器(AVCodecContext)

codec_ctx->time_base = (AVRational){1, fps};
场景示例
25fps 视频{1, 25}
30fps 视频{1, 30}
60fps 视频{1, 60}

表示每帧间隔 1/25、1/30 秒,AVFrame->pts 从 0 开始每帧加 1。

音频编码器

codec_ctx->time_base = (AVRational){1, sample_rate};
场景示例
48kHz 音频{1, 48000}
44.1kHz 音频{1, 44100}

表示每个采样点对应 1/48000 秒,AVFrame->pts 表示采样点偏移量。

封装层 AVStream(非常重要!)

stream->time_base = (AVRational){1, 1000};   // 推荐毫秒单位
// 或者 MPEG TS 常用:
stream->time_base = (AVRational){1, 90000};
容器格式建议 time_base
MP4、FLV{1, 1000}(毫秒)
MPEG-TS{1, 90000}
MKV{1, 1000} 或自动适配

所有 AVPacket->pts/dts 必须用 av_rescale_q() 将帧时间戳从 codec_ctx 的 time_base 转换为 stream 的 time_base。

时间戳换算方式(必做)

pkt.pts = av_rescale_q(frame->pts, codec_ctx->time_base, stream->time_base);
pkt.dts = pkt.pts;

如果有 B 帧,还需考虑 DTS 与 PTS 的排序差异。

音视频同步建议

音频和视频流的时间戳必须使用统一时间轴对齐,即都转为同一 stream time_base 参与比较:

video_pts_in_ms = av_rescale_q(video_pkt.pts, video_stream->time_base, {1, 1000});
audio_pts_in_ms = av_rescale_q(audio_pkt.pts, audio_stream->time_base, {1, 1000});

设置错误的后果

错误类型可能后果
time_base 设置过小或过大时间戳溢出、精度不足、播放不同步
编解码器与封装器 time_base 不匹配封装时间戳错误、seek异常、播放异常
不进行时间基转换时间戳错乱,播放器无法正确识别帧时间
不同 stream 使用不统一单位音视频同步失败,seek 错位

总结

模块推荐时间基备注
视频编码器{1, fps}如 25fps = {1, 25}
音频编码器{1, sample_rate}如 48kHz = {1, 48000}
视频流封装{1, 1000}单位为毫秒,通用适配性好
音频流封装{1, 1000}同上
MPEG TS 封装{1, 90000}对应 MPEG 时间基
时间戳转换函数av_rescale_q()必须用于编码→封装间的换算

影响

控制解码顺序(DTS)

描述:

  • DTS 决定帧在解码器中何时被解码,尤其在存在 B 帧(双向预测帧)时。

影响:

  • 解码顺序错误将导致解码失败或花屏,因为 B 帧依赖前后帧数据,必须在参考帧解码后才能处理。
  • 没有正确处理 DTS 会导致视频数据丢帧或无法还原图像。

控制播放顺序(PTS)

描述:

  • PTS 决定帧在播放器中何时显示

影响:

  • 如果 PTS 错乱,视频会播放顺序错乱、跳帧、画面抖动
  • 音视频同步将失败,导致“嘴型不对”,“声画不同步”。

音视频同步(PTS)

描述:

  • 音频和视频通过 PTS 对齐,实现声画同步

影响:

  • 若视频帧 PTS 落后于音频帧,会导致“声音先到画面后到”;
  • 若 PTS 提前或延迟跳变,导致“卡顿”、“快进”或“时间线错乱”。

播放器缓冲管理(PTS + DTS)

描述:

播放器使用 PTS 判断是否需要缓冲、跳帧或提前渲染;用 DTS 提前解码数据填充缓冲区。

影响:

  • DTS 错误可能导致解码器提前耗尽帧,导致播放中断。
  • PTS 不连续或跳变会导致播放卡顿、缓冲策略错误。

B帧重排序处理(PTS ≠ DTS)

描述:

编码器会将帧重排序以压缩效率最大化(I-P-B结构),导致 PTS ≠ DTS。

影响:

  • 解码器必须根据 DTS 顺序输入数据,但播放器必须按 PTS 顺序显示。
  • 如播放器或解码器未处理重排序,会导致播放异常,如花屏、跳帧。

封装格式要求(TS、MP4、FLV等)

描述:

不同封装格式对 PTS 和 DTS 有不同要求:

  • MPEG-TS 通常包含 PTS 和 DTS;
  • MP4 要求明确记录帧的 PTS 和 DTS;
  • FLV 仅含 PTS,要求解码器自己推算 DTS。

影响:

  • 若格式需要 DTS 而未提供,播放器解码会出错;
  • 在流媒体中时间戳错误影响服务端/客户端播放稳定性。

播放器时间轴与播放速率控制(PTS)

描述:

播放器以 PTS 为时间基准,控制渲染速率(帧率)、快进/慢放等行为。

影响:

  • 时间戳不单调递增将破坏时间轴,导致跳帧、时间错乱;
  • 快进时无法准确跳转至目标 PTS 会导致 seek 错位。

硬件解码器行为(DTS)

描述:

一些硬件解码器(如 GPU 解码)依赖 DTS 正确排序,确保流水线处理。

影响:

  • 错误 DTS 会导致解码器 crash、丢帧、处理错误。

转码与重新封装流程依赖 PTS/DTS

描述:

转码器/复用器如 FFmpeg 需要依靠 PTS/DTS 判断帧间顺序与时长。

影响:

  • 时间戳错误会导致输出文件乱序、播放错乱或封装失败。

时间基转换和流同步影响(PTS)

描述:

不同编码器/封装器的 time_base 不同,PTS/DTS 需要合理缩放转换。

影响:

  • 转换错误会导致输出帧率不对、时间戳跳变或超大。

对比

影响点PTS(播放)DTS(解码)
控制显示顺序主要依据不相关
控制解码顺序不相关主要依据
B帧重排序决定实际显示顺序决定输入解码顺序
音视频同步用于声画对齐无直接作用
播放器缓冲控制决定渲染点提前解码填充缓冲区
seek/快进精准定位关键依据不直接参与
格式封装要求必需项某些格式必须
硬件解码器正确性依赖 DTS 重排序结果必须严格准确
转码/封装时间戳计算控制封装播放顺序控制帧顺序完整性

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

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

相关文章

关于数据库的慢查询

1.数据库的慢查询慢查询是指执行时间超过预设阈值的数据库查询操作。它是数据库性能优化的一个重要指标和切入点。慢查询的主要特点执行时间长&#xff1a;超过了数据库系统设定的慢查询阈值&#xff08;如MySQL默认是10秒&#xff09;资源消耗大&#xff1a;可能占用大量CPU、…

【Rust日报】 Python 核心开发者对 Rust 的期望

半月刊&#xff1a;The Embedded Rustacean Issue #49亮点&#xff1a;&#x1f4e2; 乐鑫 DevCon 2025 演讲嘉宾征集&#x1f9ba; CISA 和 NSA 参与内存安全对话&#x1f510; 微软宣布 RIFT &#xff08;Rust 恶意软件分析工具&#xff09;&#x1f4b0;️ Nordic 收购 Memf…

vue是什么

Vue简介Vue&#xff08;Vue.js&#xff09;是一个用于构建用户界面的渐进式JavaScript框架。它专注于视图层&#xff0c;易于集成到现有项目中&#xff0c;也可用于开发复杂的单页面应用&#xff08;SPA&#xff09;。Vue的核心特点是轻量、灵活和高效&#xff0c;通过数据绑定…

10分钟掌握 Nginx 配置文件结构

在实际部署前端或后端项目时&#xff0c;Nginx 配置文件&#xff08;nginx.conf&#xff09; 是我们无法绕开的第一道门槛。 本文将带你用10分钟掌握 nginx.conf 的核心结构与常见配置方法&#xff0c;并提供一篇完整的实战文档链接&#xff0c;适合初学者快速掌握。 &#x1…

典型的前后端交互数据示例

提供几种典型的前后端交互数据示例&#xff1a; 前端如何组织数据&#xff0c;以及后端如何接收数据。 文章目录1. POST请求后端实体类接收前端js后端接收结果查看2. GET请求后端实体类接收前端js后端接收结果查看3. GET请求后端基本类型接收前端js后端接收结果查看1. POST请求…

计算机毕业设计springboot影视周边推荐系统 基于SpringBoot的电影衍生品智能推荐平台 JavaWeb实现的影视文化周边个性化服务系统

计算机毕业设计springboot影视周边推荐系统6c31q9 &#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。疫情之后&#xff0c;线上娱乐需求激增&#xff0c;人们对电影及其衍生商品的关…

(4)机器学习小白入门YOLOv :图片标注实操手册

(1)机器学习小白入门YOLOv &#xff1a;从概念到实践 (2)机器学习小白入门 YOLOv&#xff1a;从模块优化到工程部署 (3)机器学习小白入门 YOLOv&#xff1a; 解锁图片分类新技能 (4)机器学习小白入门YOLOv &#xff1a;图片标注实操手册 (5)机器学习小白入门 YOLOv&#xff1a;…

【JMeter】调试方法

文章目录取样器&#xff1a;发送请求、接收响应>>察看结果树断言&#xff1a;验证响应>>察看结果树提取器&#xff1a;创建变量>>调试取样器自定义断言&#xff1a;代码>>日志了解JMeter的内部细节&#xff0c;排查错误的原因。取样器&#xff1a;发送…

Vue框架之钩子函数详解

Vue框架之生命周期主要钩子函数详解一、Vue生命周期的整体流程二、创建阶段&#xff1a;初始化组件实例2.1 beforeCreate&#xff1a;实例创建前2.2 created&#xff1a;实例创建后三、挂载阶段&#xff1a;组件与DOM结合3.1 beforeMount&#xff1a;挂载前3.2 mounted&#xf…

Syntax Error: TypeError: Cannot set properties of undefined (setting ‘parent‘)

Date: 2025-07-12 19:21:24 author: lijianzhan使用npm run dev运行前端项目时报错&#xff0c;具体报错信息如下&#xff1a; ERROR Failed to compile with 1 error …

JAVA后端开发——类命名规范

引言良好的命名规范是软件工程的基石。它不仅能提升代码的可读性&#xff0c;还能降低团队协作的沟通成本&#xff0c;使项目在长期迭代中更易于维护。本规范结合了业界主流实践&#xff08;如阿里巴巴Java开发手册&#xff09;以及现代Web应用分层架构的特点&#xff0c;旨在提…

Ubuntu2404修改国内镜像

文章目录1 备份原文件2 修改文件内容Ubuntu2404修改国内镜像 2404和2204修改镜像的方式不一致 且镜像保存的位置也不一致&#xff0c;位置在/etc/apt/source.list.d/ubuntu.sources 参考&#xff1a;https://blog.csdn.net/Kiffy_Yam/article/details/145876447 1 备份原文件…

Chrome拓展 Video Speed Controller 等内嵌恶意后门

【高危】Chrome拓展 Video Speed Controller 等内嵌恶意后门 漏洞描述 当用户安装受影响版本的 Video Speed Controller 等Chrome拓展会窃取用户的浏览链接&#xff0c;并与攻击者可控的C2地址建立持久化连接&#xff0c;攻击者可将用户浏览器重定向到恶意网站。 MPS编号MPS…

Spring Ai Alibaba Gateway 实现存量应用转 MCP 工具

作者简介&#xff1a;你好&#xff0c;我是影子&#xff0c;Spring Ai Alibaba开源社区 Committer&#xff0c;持续分享Spring Ai Alibaba最新进展 业界各类AI工程相关的方案 最近有断时间没更了&#xff0c;熟悉我的朋友知道我刚结束完毕业旅行&#xff0c;最近也因为入职&a…

HTTP和HTTPS部分知识点

HTTP基本概念 超文本-传输-协议 协议 HTTP是一个用在计算机世界里的协议。它使用计算机可以理解的语言确立了一种计算机之间交流通信的规范(两个以上的参与者)&#xff0c;以及相关的各种控制和错误处理方式(行为约定和规范)。传输 HTTP协议是一个双向协议。是一个在计算机世界…

第10讲——一元函数积分学的几何应用

文章目录定积分计算平面图形的面积直角坐标系下参数方程下极坐标系下定积分计算旋转体的体积曲边梯形绕x轴旋转一周所得到的旋转体的体积曲边梯形绕y轴旋转一周所得到的旋转体的体积平面曲线绕定直线旋转定积分计算函数的平均值定积分计算平面光滑曲线的弧长曲线L绕x轴旋转一周…

Go从入门到精通(20)-一个简单web项目-服务搭建

Go从入门到精通&#xff08;15&#xff09;-包&#xff08;package&#xff09; Go从入门到精通&#xff08;9&#xff09;-函数 文章目录Go从入门到精通&#xff08;15&#xff09;-包&#xff08;package&#xff09;Go从入门到精通&#xff08;9&#xff09;-函数前言gogin…

Python爬虫实战:研究python-docx库相关技术

1. 引言 1.1 研究背景与意义 随着学术资源数字化程度的提高,科研工作者面临海量文献数据的筛选与分析挑战。传统人工调研方式效率低下,难以全面捕捉研究领域的动态趋势。自动化文献分析系统能够通过爬虫技术快速采集多源数据,并通过文本挖掘提取关键信息,为研究方向选择、…

Django中序列化与反序列化

1&#xff1a;序列化&#xff1a;将数据结构或对象状态转换为可以存储或传输的格式&#xff08;如JSON、XML&#xff09;的过程。在Web开发中&#xff0c;通常是将模型实例&#xff08;或查询集&#xff09;转换为JSON格式&#xff0c;以便通过HTTP响应发送给客户端。序列化&am…

【离线数仓项目】——电商域DWD层开发实战

摘要本文主要介绍了离线数仓项目中电商域DWD层的开发实战。DWD层是数据仓库架构中的明细数据层&#xff0c;对ODS层的原始数据进行清洗、规范、整合与业务建模。它具有数据清洗、标准化、业务建模、整合、维度挂载等作用&#xff0c;常见设计特征包括一致性、明细级建模、保留历…