【音視頻】TS協議解析

參考博客:https://blog.csdn.net/rell336/article/details/38109621?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param

一、TS協議

1.1 TS流和其他流的關系

1. ES(Elementary Stream,基本碼流)

  • 定義:未經分段的原始媒體流,是連續的音頻、視頻或其他信息(如字幕)的原始數據序列。
  • 特點
    • 不分段,以連續碼流形式存在。
    • 是最底層的媒體數據,直接由編碼器生成(如H.264視頻流、AAC音頻流)。
    • 不包含傳輸控制信息,無法直接用于傳輸。

2. PES(Packetized Elementary Stream,分組的基本碼流)

  • 定義:將ES流分割為長度可變的數據包,并添加包頭后形成的流,用于承載ES流。
  • 作用:為ES流添加傳輸所需的控制信息,實現ES流的分組化傳輸。
  • 結構
    • PES包頭:包含時間戳(PTS/DTS)、數據長度、流類型等信息。
    • PES有效載荷:分割后的ES流片段。
  • 特點
    • 數據包長度可變,適合在可靠環境(如本地存儲)中使用。

3. TS(Transport Stream,傳輸流)

  • 定義:由固定長度(188字節)的數據包組成,用于在不可靠環境(如廣播電視、網絡傳輸)中傳輸多個節目。
  • 構成
    • 包含一個或多個節目,每個節目由音頻、視頻等ES流通過PES分組后封裝而成。
    • 插入PSI/SI表(節目特定信息/服務信息),用于描述節目結構和服務信息。
  • 關鍵特性
    • 固定包長:每個TS包為188字節(含4字節包頭),便于硬件快速處理。
    • 獨立解碼:從流中任意位置均可開始解碼,容錯性強。
    • PSI/SI重復傳輸:PSI/SI表按一定頻率重復發送,確保接收端能隨時獲取節目信息。

4. PS(Program Stream,節目流)

  • 定義:用于傳輸單個節目,由可變長度數據包組成的流,適用于可靠存儲或傳輸環境(如DVD光盤)。
  • 與TS流的核心區別
    • 包長度:PS包長度可變,TS包長度固定(188字節)。
    • 應用場景:PS流適合本地存儲(如文件),TS流適合實時傳輸(如廣播電視)。

四者關系

  1. ES流是原始媒體數據(如視頻幀、音頻采樣)。
  2. PES流是ES流的分組形式,添加時間戳等控制信息。
  3. TS流/PS流是PES流的進一步封裝:
    • TS流:固定包長,含多節目和PSI/SI,適合傳輸。
    • PS流:可變包長,單節目,適合存儲。

簡單來說,ES→PES→TS/PS的過程,是媒體數據從原始形式到可傳輸/存儲形式的封裝鏈。

1.2 TS包

TS包的?度:188 B或204 B,204 B?度是在188B后?增加了16 B的CRC校驗數據。
在這里插入圖片描述

  • sync_byte: 1B,固定值0x47,TS包的標識符,正常的TS包在0x47的包頭標識符往后188/204B之后仍然是0x47【下?個TS包的標識符】

  • transport_error_Indicator: 1bit,當其為1時,表示該TS包中?少有?個不可糾正的錯誤位,只有在錯誤糾正之后,該位才能重新置0【實際獲取TS包之后,該位為1的包丟棄】

  • payload_unit_start_indicator: 1bit,對于PSI數據包,該位為1時,表示該TS包是某個Section的第?個包,并且該包含有pointer_field,該變量的值意義在于,除了調整字段之外,往后pointer_field個字節開始,才是有效數據。對于空包來說,該值為0。

  • transport_priority: 1bit,表示傳輸優先級,對于相同PID的TS包,該字段置1的TS包擁有更?的優先級。PID:13bit,PID可以標識存儲于TS包中有效凈荷的數據的類型。PID?于TS包階段?于鑒別各種PSI/SI信息表、電視節?,區分?視頻的PES包等,是辨別碼流信息性質的關鍵。

  • transport_scrambling_control:2bit,?來指示傳送流包Payload的加擾?式。【傳送流包?部包括調整字段,則不應被加擾;空包也不加擾。】

Transport_scrambling_control描述
00未加擾
01用戶定義
10用戶定義
11用戶定義
  • adaption_field_control:2bit,表示傳送流包?部是否跟隨調整字段/Payload【如果全部是調整字段則不含payload】

  • continuity_counter: 4bit,隨著具有相同PID的TS包增加?增加,當它達到最?(31)時,?恢復為0,如果adaption_field_control = 00/10,該連續計數器不增加,因為不含payload。

1.3解析TS包

1.3.1獲取包?

TS包的包?有兩種——188B或者204B,在解析TS包之前,必須要先判斷TS包包?,以便后續進?分析。

1. 標準固定長度
  • 常規 TS 包:最常見的長度是 188 字節(包括 4 字節包頭 + 184 字節負載)。這是 DVB(歐洲數字電視標準)、ATSC(美國數字電視標準)等系統的默認長度。
  • 擴展長度:在某些場景(如 DVB-T2、ISDB-Tb)中,TS 包可能被封裝到更大的幀結構中,此時 TS 包長度可能為 204 字節(188 字節 + 16 字節前向糾錯碼)。但這種情況下,核心 TS 包本身仍為 188 字節,只是外部添加了額外的保護機制。
2. 通過同步字節識別包邊界

TS 包的起始位置由 同步字節(固定值 0x47)標識。接收端通過檢測連續的 0x47 來定位每個 TS 包的開始,并根據固定長度(如 188 字節)截取完整的包。例如:

0x47 [TS包頭4字節] [負載184字節] 0x47 [下一個TS包...]

如果遇到非 0x47 的字節,則表示傳輸錯誤或包丟失。

具體流程如下圖(以188B為例):

在這里插入圖片描述

1.3.2 解析TS包頭

在獲取包?之后,就要對包頭信息進?解析并獲取有效數據,需要定義?個結構體存儲數據:

/*TS包包頭的結構體*/
typedef struct CSTSPacketHeader_S
{BYTE ucSyncByte; //TS包的標識符BYTE ucTransport_error_indicator; //傳輸錯誤指示器,當值為時,表示該包有誤BYTE ucPayload_unit_start_indicator; //有效凈荷開始標記// 注:如果想要節省存儲空間,可以使用位域的方式定義結構體。BYTE——unsigned char,Word——unsigned short intBYTE ucTransport_priority; //傳輸的優先級WORD wPID; //TS包的ID,用于區分不同的sectionBYTE ucTransport_scrambling_control; //指示ts傳送流包有效凈荷的加擾方式BYTE ucAdaptation_field_control; //指示是否有調整字段和有效凈荷BYTE ucContinuity_counter; //隨著相同PID TS包的增加而增加
} TSPacketHeader;

假定包?為188,我們每獲取?個TS包,就裝進?個?度為188的BYTE型數組?,前4個BYTE就是包頭的數據了,獲取數據可以邏輯與,左右移,邏輯或的?法進?,具體例?如下:

pstTSHeader->wPID = ((pucTSBuffer[1]& 0x1f) << 8) | pucTSBuffer[2];

1.3.3 判斷TS包的有效性

在?個碼流中,并不全部都是有效的TS包,需要將?些?效TS包剔除

?效TS包的情況分為五種:

  1. 該TS包往后188B不是0x47的包頭標識符(TS包都是連續發送,如果出現包不連續的地?,說
    明該包數據傳送時出錯);
  2. TS包存在錯誤,即transport_error_Indicator的值為1;
  3. TS包全是調整字段(空包),即adaption_field_control的值為10(?進制);
  4. TS包的調整字段屬于保留的情況,即adaption_field_control的值為00(?進制);
  5. TS包被加擾,即transport_scrambling_control不為00,(如果有做解擾可以去掉這種情況);

對于這五種情況的TS包我們?律丟棄,直接獲取下?個TS包。

1.3.4 確定payload的起始位置

1. 定位 TS 包起始

每個 TS 包以 同步字節(固定值 0x47)開始。找到同步字節后,后續的 187 字節屬于當前 TS 包。

2. 解析 TS 包頭(4 字節)

TS 包頭的結構如下:

字節0: 同步字節 (0x47)
字節1: TEI(1) | PUSI(1) | TP(1) | PID(13)
字節2: PID(繼續)
字節3: TSC(2) | AFC(2) | CC(4)

其中關鍵字段:

  • AFC (Adaptation Field Control):位于字節 3 的第 4-5 位(2 比特),指示自適應區和有效載荷的存在情況:
    • 01無自適應區,僅有效載荷(Payload 從第 5 字節開始)。
    • 10僅有自適應區,無有效載荷(Payload 為空)。
    • 11自適應區后接有效載荷(需進一步計算 Payload 起始)。
    • 00:保留值,不應使用。
3. 根據 AFC 計算 Payload 起始
情況 1:AFC = 01(僅有效載荷)
  • Payload 起始位置:第 5 字節(即包頭后的第一個字節)。
情況 2:AFC = 10(僅自適應區)
  • 無有效載荷,TS 包僅包含包頭和自適應區。
情況 3:AFC = 11(自適應區 + 有效載荷)
  1. 讀取自適應區長度
    • 包頭后的第 1 個字節(即第 5 字節)是 自適應區長度adaptation_field_length),表示自適應區的總字節數(不包含自身)。
  2. 計算 Payload 起始
    • Payload 起始位置 = 包頭(4 字節) + 自適應區長度字節(1 字節) + 自適應區內容(adaptation_field_length 字節)。
    • 公式:Payload起始 = 5 + adaptation_field_length
4. 示例計算

假設 TS 包數據如下(十六進制):

47 40 00 11 05 FF 00 01 02 03 61 62 63 ...

解析步驟:

  1. 同步字節47 → 確認 TS 包起始。
  2. AFC 字段:字節 3 為 11 → 二進制 0001 0001 → AFC = 11(自適應區 + 有效載荷)。
  3. 自適應區長度:第 5 字節為 05 → 自適應區內容長度為 5 字節。
  4. Payload 起始:5(包頭 + 長度字節) + 5(自適應區內容) = 第 10 字節61)。

二、 Section

2.1 Section的概念

  • ?個TS數據包的最?凈荷為184個字節,當?個PSI/SI表的字節?度?于184字節時,就要對這個表進?分割,形成段(section)來傳送。

  • 分段機制主要是將?個數據表分割成多個數據段。 在PSI/SI表到TS包的轉換過程中,段起到了中介的作?。由于?個數據包只有188字節,?段的?度是可變的,EIT表的段限?4096字節,其余PSI/SI表的段限?為1024字節。因此,?個段要分成?部分插?到TS包的payload中。

  • 從TS碼流中可以獲取到TS包,TS包要組成Section,才能提取到想要的信息,所以?先要懂得怎么組section。

組Section之前要了解TS包在碼流中發送的?些情況:

  1. TS包發送的時候PID是?序的,連續的TS包的PID可能都是不?樣的;
  2. TS包發送的時候Section是相對有序的,也就是說,對于同?個PID的TS包,只有發完了?個Section,才會發送下?個Section,不然?法區分該TS包屬于哪?個Section,并且對于這個Section,TS包是有序發送的,否則數據會被打亂;
  3. 某個Section的第?個TS包有PSI/SI表的?些表頭信息(table_id,section_length等信息),我稱之為SectionHeader,后?的TS包就沒有,所以接收某個Section必須先拿到?包。

2.2 TS包組Section

  • TS包組section?先要找到該section的第?個TS包(下?簡稱為?包),?包含有該section的?度,可以?來判斷?個section是不是組完了。

  • 通過判斷TS包包頭中的Payload Unit Start Indicator,該值為1的話,就說明這個TS包是?包,可以開始組?個section,?包含有Section的頭部,結構類似下表。

說明:uimsbf 表示無符號整數,最高位在前;bslbf 表示二進制符號位在前(布爾類或標志位常用) ,可用于解析 MPEG - 2 傳輸流中節目關聯段(PAT)的結構。

字段名位寬編碼類型
table_id8uimsbf
section_syntax_indicator1bslbf
‘0’1bslbf
reserved2bslbf
section_length12uimsbf
transport_stream_id16uimsbf
reserved2bslbf
version_number5uimsbf
current_next_indicator1bslbf
section_number8uimsbf
last_section_number8uimsbf

拿到?包之后,要獲取section的?度,有效數據的第?個字節的后四位和第三個字節組成?個12bit的字段,該值就是section_length后?數據的?度,如果算上前?三個字節,整個section的?度就是section_length += 3

將section_length和TS包有效?度進?對?,

  1. 如果section_length > TS包的有效數據,證明后?還有其他的TS包,將section_length減去TS包有效數據?度,獲得剩余?度;
  2. 如果是section_length <= TS包的有效數據,證明該section已經結束了。

如果?個section還沒組完,那么就要獲取后續的TS包,后續的TS包應該是和原來相同PID,并且TS包頭中continuity_counter要?原來的?1(31的話要變成0),拿到包后要與剩余?度進?對?,重復上?的步驟。

2.3 組多個Section和判全判重

對于?些PSI/SI表來說,由于數據較多,有時候不??個section,怎么針對這個表將所有的section組全?

子表 Section 組包、判全與判重機制說明

在處理 PSI/SI 表(以 PAT 等為例)的分段 Section 時,需通過以下邏輯實現組包、判全與判重:

1. 子表 Section 數量與組包邏輯

每個子表的 Section 頭部包含 last_section_number 字段,規則如下:

  • 含義:標識當前子表最后一個 Section 的編號(section_number)。
  • 數量計算:子表總 Section 數 = last_section_number + 1(因 section_number 從 0 開始計數 )。
  • 組包方式:以鏈表(或數組)存儲同一子表的 Section,按 section_number 順序拼接,還原完整子表數據。
2. 版本控制(判重核心邏輯)

每個 Section 頭部包含 version_number 字段,用于標識子表版本:

  • 版本變更:若新 Section 的 version_number 與已存儲子表版本不一致,說明子表已更新,需:
    • 丟棄所有舊版本 Section。
    • 重新初始化接收流程,采集新版本 Section。
  • 版本未變:繼續校驗 section_number,判斷是否重復或缺失。
3. 判全與判重邏輯

通過 標記數組 跟蹤 Section 接收狀態,流程如下:

步驟操作邏輯關鍵判斷
1初始化標記數組last_section_number + 1 為長度,初始值全為 0(未接收)
2接收新 Section解析其 section_number
3判重校驗若標記數組中 section_number 對應下標值為 1,說明該 Section 已接收過,丟棄
4標記接收狀態若未重復,將標記數組中 section_number 對應下標值置為 1
5判全校驗遍歷標記數組,若下標 0 ~ last_section_number 對應值全為 1,說明子表所有 Section 已收全,可組裝完整子表

更多資料:https://github.com/0voice

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/88557.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/88557.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/88557.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

uniapp 日期組件可選擇年月

month-picker 月份選擇器組件 組件介紹 month-picker 是一個用于選擇年月的自定義組件&#xff0c;基于 uni-app 開發&#xff0c;提供了簡潔的月份選擇功能。 解決彈框底部出現底部頁面區域 safe-area屬性設為true時&#xff0c;即可解決這個問題效果如圖功能特點 支持選擇年份…

從真人到數字分身:3D人臉掃描設備在高校數字人建模教學中的應用

在影視、動漫、游戲等數字創意產業蓬勃發展的當下&#xff0c;超寫實虛擬數字人憑借其高度逼真的形象&#xff0c;成為行業關注的焦點。無論是影視特效中栩栩如生的角色&#xff0c;還是游戲里精致的NPC&#xff0c;超寫實虛擬數字人的制作都離不開先進的技術支撐。而3D人臉掃描…

你以為大數據只是存?其實真正的“寶藏”藏在這招里——數據挖掘!

你以為大數據只是存&#xff1f;其實真正的“寶藏”藏在這招里——數據挖掘&#xff01; 曾經我也天真地以為&#xff0c;搞大數據就是會寫幾個SQL、部署個Hadoop集群&#xff0c;結果真到項目現場&#xff0c;甲方爸爸一句&#xff1a;“給我挖掘一下用戶的購買意圖”&#xf…

LeetCode經典題解:128、最長連續序列

“最長連續序列”是一道極具代表性的數組處理問題&#xff0c; 本文將帶你從直觀思路出發&#xff0c;逐步推導出最優解法&#xff0c;并通過場景化記憶技巧掌握核心邏輯。 一、題目描述 題目&#xff1a;給定一個未排序的整數數組 nums&#xff0c;找出數字連續的最長序列&…

電力分析儀的“雙語對話”:CCLinkIE與Modbus TCP的無縫連接

在工業自動化領域&#xff0c;協議兼容性問題如同“方言壁壘”&#xff0c;讓不同品牌、不同系統的設備難以高效協同。對于電力分析儀這類關鍵設備而言&#xff0c;如何打破CCLinkIE與Modbus TCP協議的“語言障礙”&#xff0c;已成為工程師優化系統集成的核心課題。 為何需要協…

暑假復習篇之文本編譯器

一、知識點補充【在此次示例代碼上顯示的關鍵用法】知識點1、JMenuBar&#xff1a;菜單欄的容器&#xff0c;通常添加到JFrame的頂部。關鍵用法&#xff1a;add&#xff1a; 添加菜單到菜單欄2、JMenu&#xff1a;菜單條目&#xff08;“文件” “編輯” 等&#xff09;&#x…

Linux自動化構建工具(一)

&#x1f381;個人主頁&#xff1a;工藤新一 &#x1f50d;系列專欄&#xff1a;C面向對象&#xff08;類和對象篇&#xff09; &#x1f31f;心中的天空之城&#xff0c;終會照亮我前方的路 &#x1f389;歡迎大家點贊&#x1f44d;評論&#x1f4dd;收藏?文章 文章目錄Li…

目標檢測流程圖繪制

目標檢測流程圖繪制作為一個長期科研的苦命人&#xff0c;我一般采用Processon。 一、目標檢測流程圖繪制的 “量身定制” 體驗 Processon 的繪圖元素庫對目標檢測領域極度友好&#xff0c;從基礎模塊到復雜結構都能精準匹配&#xff1a; ??核心組件一鍵調用&#xff1a;在右…

GitHub 趨勢日報 (2025年07月09日)

&#x1f4ca; 由 TrendForge 系統生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日報中的項目描述已自動翻譯為中文 &#x1f4c8; 今日獲星趨勢圖 今日獲星趨勢圖970genai-toolbox780WebAgent650rustfs451prompt-eng-interactive-tutorial246ai-a…

多云環境下的成本管理挑戰與對策 ——資源碎片化治理與華為CloudMatrix破局之道

一、危機&#xff1a;多云成本失控已成企業“隱形殺手”成本超支概率激增據Gartner 2024報告&#xff0c;采用多云策略的企業成本超支概率比單云企業高47%&#xff0c;主因資源碎片化導致的閑置浪費和管控失效。觸目驚心的數據&#xff1a;73%企業云成本占營收超20%&#xff0c…

Linux的基礎I/O

目錄 1、理解“文件” 1.1 狹義理解 1.2 廣義理解 1.3 文件操作的歸類認知 1.4 系統角度 2、回顧C文件接口 2.1 文件的打開與關閉 2.2 文件的讀寫函數 2.3 stdin & stdout & stderr 3、系統文件I/O 3.1 一種傳標志位的方式 3.2 文件的系統調用接口 3.2.1 o…

廣告匹配策略的智能化之路:人工智能大模型的方法和步驟

摘要 廣告匹配策略是指根據用戶的需求和偏好&#xff0c;向用戶推薦最合適的廣告的方法。廣告匹配策略的優化是數字化營銷的核心問題之一&#xff0c;也是提升廣告效果和收益的關鍵因素。本文介紹了如何利用人工智能大模型&#xff0c;從數據分析、廣告推薦、策略優化、效果評…

飛算JavaAI:重塑Java開發的“人機協同“新模式

引言 在Java開發領域&#xff0c;“效率"與"質量"的平衡始終是開發者面臨的核心挑戰——重復編碼消耗精力、復雜業務易出漏洞、老系統重構舉步維艱。飛算JavaAI的出現&#xff0c;并非簡單地用AI替代人工&#xff0c;而是構建了一套"AI處理機械勞動&#…

運行ssh -T git@github.com報錯

運行ssh -T gitgithub.com報錯 no such identity: /root/.ssh/id_rsa: No such file or directory gitssh.github.com: Permission denied (publickey). 如果我用的是ed25519而非rsa&#xff0c;有id_ed25519 則需要打開~/.ssh/config檢查一下是否寫錯了 vim ~/.ssh/config 然后…

20250710-2-Kubernetes 集群部署、配置和驗證-網絡組件存在的意義?_筆記

一、網絡組件的作用&#xfeff;1. 部署網絡組件的目的&#xfeff;核心功能&#xff1a;執行kubectl apply -f calico.yaml命令的主要目的是為Kubernetes集群部署網絡組件必要性&#xff1a;解決Pod間的跨節點通信問題建立集群范圍的網絡平面&#xff0c;使所有Pod處于同一網絡…

【牛客刷題】dd愛科學1.0

文章目錄 一、題目介紹1.1 題目描述1.2 輸入描述:1.3 輸出描述:1.4 示例1二、解題思路2.1 核心策略2.2 算法流程2.3 正確性證明三、算法實現四、關鍵步驟解析五、復雜度分析六、正確性驗證七、算法對比7.1 暴力搜索法7.2 動態規劃7.3 三種解法對比分析一、題目介紹 1.1 題目描…

跑步-Java刷題 藍橋云課

目錄 題目鏈接 題目 解題思路 代碼 題目鏈接 競賽中心 - 藍橋云課 題目 解題思路 用數組記錄每個月有多少天,再使用一個int型變量記錄是星期幾,遍歷即可 代碼 import java.util.Scanner; // 1:無需package // 2: 類名必須Main, 不可修改public class Main {public stat…

Qt常用控件之QWidget(二)

Qt常用控件&#xff08;二&#xff09;1.window frame2.windowTitle3.windowIcon&#x1f31f;&#x1f31f;hello&#xff0c;各位讀者大大們你們好呀&#x1f31f;&#x1f31f; &#x1f680;&#x1f680;系列專欄&#xff1a;【Qt的學習】 &#x1f4dd;&#x1f4dd;本篇…

飛算Java AI:專為 Java 開發者打造的智能開發引擎

目錄 一&#xff0c;核心功能 1&#xff0c;智能編碼&#xff08;AI Coding&#xff09; 2&#xff0c;AI 驅動測試&#xff08;AI Testing&#xff09; 3&#xff0c;智能運維&#xff08;AIOps&#xff09; 4&#xff0c;工程化支持 二、注冊與上手&#xff1a;3 分鐘快…

基于開源AI大模型AI智能名片S2B2C商城小程序源碼的私域流量新生態構建

摘要&#xff1a;私域流量并非新生概念&#xff0c;企業持續構建和經營“企業 - 客戶”關系是其持續存在的關鍵&#xff0c;且會隨時代發展自我完善迭代。本文探討了開源AI大模型AI智能名片S2B2C商城小程序源碼在私域流量領域的應用價值。通過分析私域流量發展現狀與挑戰&#…