音視頻學習(三十七):pts和dts

概念

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;常見設計特征包括一致性、明細級建模、保留歷…