H264原始碼流格式分析

1.H264碼流結構組成

H.264裸碼流(Raw Bitstream)數據主要由一系列的NALU(網絡抽象層單元)組成。每個NALU包含一個NAL頭和一個RBSP(原始字節序列載荷)。

1.1 H.264碼流層次

H.264碼流的結構可以分為兩個層次:VCL(視頻編碼層)和NAL(網絡抽象層)。下圖為H.264碼流中的層次圖:

VCL層:負責對視頻的原始數據進行壓縮。VCL數據編碼器直接輸出的原始數據比特串(SODB),表示圖像被壓縮后的編碼比特流。

  • SODB:生成壓縮原始的圖像編碼數據比特串。
  • 編碼圖像:宏塊進行的幀內編碼/幀間編碼/熵編碼等處理。

NAL層:負責將VCL數據封裝成NAL單元(NALU),并在網絡上傳輸或存儲到磁盤上。每個NAL單元之前需要添加StartCodePrefix,形成H.264碼流。NAL層還處理拆包和組包的工作,以適應網絡傳輸的最大傳輸單元(通常為1500字節)。

1.2 NALU網絡層組成

一個NALU由兩個主要部分組成:

  • 頭部(Header):

    NALU的頭部包含了關于該單元的一些元數據信息,例如NAL單元類型(如序列參數集、圖像參數集、幀數據單元等),NALU的優先級、參考幀標識、重要性指示等。頭部的信息有助于解碼器正確解析和處理每個NAL單元。

  • 載荷(Payload):

    NALU的載荷部分包含了實際的編碼數據。這些數據可以是幀的視頻數據、補充增強信息或其他特定于編碼標準的數據。在視頻解碼過程中,解碼器通過解析頭部信息來識別NALU的類型,并且根據類型和載荷數據進行相應的解碼和處理。

在H.264/AVC中,定義了多種NALU的類型,以適應不同的應用場景。常見的類型包括:

幀內預測(I)片:僅使用當前幀的信息進行編碼。

預測(P)片:使用前一幀的信息進行編碼。

雙向預測(B)片:使用前一幀和后一幀的信息進行編碼。

1.3 序列參數集SPS

序列參數集(Sequence Parameter Set,SPS)包含了描述視頻序列全局參數的信息,這些參數對于解碼器正確解碼視頻流至關重要。以下是SPS的一些主要內容和結構:

  1. profile_idc:標識H.264碼流的profile,例如Baseline、Main、High等。
  2. level_idc:標識碼流的Level,定義了最大分辨率、最大幀率等參數。
  3. seq_parameter_set_id:序列參數集的ID,用于標識不同的SPS。
  4. log2_max_frame_num_minus4:用于計算frame_num的最大值,frame_num標識圖像的解碼順序。
  5. pic_order_cnt_type:指明圖像播放順序的編碼方法。
  6. log2_max_pic_order_cnt_lsb_minus4:用于計算POC(Picture Order Count)的最大值。
  7. max_num_ref_frames:指定參考幀隊列的最大長度。
  8. gaps_in_frame_num_value_allowed_flag:指示是否允許frame_num不連續。
  9. pic_width_in_mbs_minus1:圖像寬度,以宏塊為單位。
  10. pic_height_in_map_units_minus1:圖像高度,以宏塊為單位。

SPS中的信息對于解碼器初始化和正確解碼視頻流至關重要。如果SPS數據丟失或損壞,解碼器可能無法正確解碼視頻。

1.4 圖像參數集PPS

圖像參數集(Picture Parameter Set,PPS)包含了與單個圖像編碼相關的參數,這些參數用于控制圖像的編碼方式。以下是PPS的一些主要內容和結構:

  1. pic_parameter_set_id:當前PPS的唯一ID,取值范圍為0-255。
  2. seq_parameter_set_id:指明該PPS對應的SPS(序列參數集)ID。
  3. entropy_coding_mode_flag:表示使用的熵編碼類型,0為CAVLC,1為CABAC。
  4. num_slice_groups_minus1:表示slice group的數量,通常為0。
  5. num_ref_idx_l0_default_active_minus1num_ref_idx_l1_default_active_minus1:表示P/B slice的前向和后向參考幀的最大個數減1。
  6. weighted_pred_flag:表示P slice的預測權重方式,0為默認預測權重,1為顯式方式。
  7. weighted_bipred_flag:表示B slice的預測權重方式,0為默認預測權重,1為顯式方式,2為隱式方式。
  8. pic_init_qp_minus26:用于計算Y分量的初始QP值。
  9. chroma_qp_index_offset:表示Cb分量QP相對于slice QP的偏移量。
  10. deblocking_filter_control_present_flag:表示是否存在去塊效應濾波器的控制語法元素。
  11. constrained_intra_pred_flag:表示幀內預測方式是否存在限制條件。
  12. transform_8x8_mode_flag:表示是否使用8x8大小的DCT變換方式。
  13. pic_scaling_matrix_present_flag:表示量化參數矩陣是否存在。
  14. second_chroma_qp_index_offset:表示Cr分量QP相對于slice QP的偏移量。

PPS中的信息對于解碼器正確解碼視頻流至關重要。PPS通常緊跟在SPS之后,并且可以有多個,因為不同的slice group可能有不同的參數設置。

2.常用的兩種NALU格式

2.1 AnnexB

AnnexB是一種常見的NALU(網絡抽象層單元)封裝格式,主要用于H.264和H.265視頻編碼標準。AnnexB格式的基本結構如下:

[開始代碼] [NALU單元] [開始代碼] [NALU單元] ...

每個NALU單元由一個開始代碼和隨后的原始字節數據組成,通過分隔符0x00 00 00 01或者0x00 00 01區分不同的NALU單元。如果在RBSP(原始字節流載荷)中出現了0x000000、0x000001、0x000002或0x000003這樣的序列,就需要插入一個0x03字節來避免這些序列被誤識別。例如,將0x000001變成0x00000301,這樣在解碼時可以去除0x03字節,恢復原始數據。這種方法確保了數據的完整性和正確解碼。例如:

  • 原始數據:0x000001?插入“模擬預防”字節后:0x00000301?解碼時去除0x03字節,恢復為:0x000001

  • 原始數據:0x000000?插入“模擬預防”字節后:0x00000300?解碼時去除0x03字節,恢復為:0x000000

  • 原始數據:0x000002?插入“模擬預防”字節后:0x00000302?解碼時去除0x03字節,恢復為:0x000002

  • 原始數據:0x000003?插入“模擬預防”字節后:0x00000303?解碼時去除0x03字節,恢復為:0x000003

如果插入的數據本身包含了“模擬預防”字節(例如0x00000301),編碼器會將其轉義為0x0000030301。

2.2 AVCC

AVCC(AVC Configuration)格式是一種用于存儲和傳輸H.264視頻流的格式,通常用于MP4、MKV等容器中。與Annex B格式不同,AVCC格式不使用起始碼(start code)來分隔NALU(網絡抽象層單元),而是使用NALU長度前綴。

AVCC格式結構:

  1. 頭部信息(extradata):
    • 包含SPS(序列參數集)和PPS(圖像參數集)等參數信息。
    • 頭部信息的格式如下:
      • 第1字節:版本號(通常為0x01)
      • 第2字節:AVC Profile(與第一個SPS的第2字節相同)
      • 第3字節:AVC Compatibility(與第一個SPS的第3字節相同)
      • 第4字節:AVC Level(與第一個SPS的第4字節相同)
      • 第5字節:保留位(前6位全1),后2位表示NALU長度字段的字節數減1(通常為3,即4字節)
      • 第6字節:保留位(前3位全1),后5位表示SPS的個數(通常為1)
      • 后續字節:SPS數據(包括16位SPS長度和SPS NALU數據)
      • PPS數據(包括16位PPS長度和PPS NALU數據)
  2. NALU數據:
    • 每個NALU前面都有一個長度前綴(通常為4字節),表示該NALU的長度。
    • NALU數據不包含起始碼。

假設有一個NALU數據為0x65 88 84 21,其長度為4字節。在AVCC格式中,這個NALU會被存儲為:

0x00 00 00 04 65 88 84 21

其中,0x00 00 00 04表示NALU的長度為4字節,后面的65 88 84 21是實際的NALU數據。

在解析AVCC格式時,需要先讀取頭部信息(extradata),然后根據NALU長度前綴來提取每個NALU的數據。

2.3 AnnexB和AVCC的優缺點

Annex B和AVCC是H.264視頻編碼中常見的兩種NALU(網絡抽象層單元)封裝格式。它們各有優缺點,適用于不同的應用場景。以下是它們的優劣之處:

Annex B
優點簡單直接:使用起始碼(start code)0x0000010x00000001來分隔NALU,便于解析和同步。
廣泛支持:許多硬件解碼器和流媒體協議(如RTSP、RTP)默認支持Annex B格式。
實時流媒體:適合實時流媒體傳輸,因為起始碼可以快速定位NALU的邊界。
缺點額外開銷:起始碼會增加一些額外的字節,導致數據冗余。
不適合文件存儲:在文件存儲中,起始碼的存在可能會增加文件大小,不如AVCC格式高效。
AVCC
優點高效存儲:使用NALU長度前綴(通常為4字節)來標識NALU的長度,減少了數據冗余,適合文件存儲。
靈活性高:適用于多種容器格式(如MP4、MKV),便于在不同平臺和設備之間傳輸和存儲。
標準化:AVCC格式在許多多媒體框架和庫(如FFmpeg、GStreamer)中得到廣泛支持。
缺點解析復雜:需要解析NALU長度前綴,增加了解碼器的復雜性。
實時性較差:不如Annex B格式適合實時流媒體傳輸,因為需要額外的步驟來解析NALU長度。

選擇建議

  • 實時流媒體傳輸:推薦使用Annex B格式,因其簡單直接,便于實時解析和同步。
  • 文件存儲和傳輸:推薦使用AVCC格式,因其高效存儲和靈活性,適合在不同平臺和設備之間傳輸和存儲。

3.碼流中的重要參數

3.1 量化參數(QP值)

QP(Quantization Parameter,量化參數)是H.264視頻編碼中用于控制視頻壓縮的質量和比特率。QP值直接影響視頻的量化步長(Qstep),從而影響視頻的壓縮程度和圖像質量。QP值的作用:

  1. 控制壓縮質量:QP值越小,量化越精細,保留的圖像細節越多,視頻質量越高,但比特率也越高。相反,QP值越大,量化越粗糙,丟失的細節越多,視頻質量下降,但比特率降低。
  2. 調節比特率:通過調整QP值,可以在視頻質量和比特率之間找到一個平衡點,以滿足不同的應用需求。

QP值的范圍,在H.264標準中,QP值的取值范圍為0到51:

  • QP = 0:量化最精細,視頻質量最高,比特率最大。
  • QP = 51:量化最粗糙,視頻質量最低,比特率最小。

假設你有一個視頻片段,使用不同的QP值進行編碼:

  • QP = 20:視頻質量較高,細節保留較多,但比特率較高。
  • QP = 40:視頻質量較低,細節丟失較多,但比特率較低。

QP值與量化步長(Qstep)之間存在一個對數關系。具體來說,QP每增加6,Qstep大約增加一倍。這個關系使得編碼器可以在不同的QP值下靈活調整視頻的壓縮程度。

  • 低QP值:適用于需要高質量視頻的場景,如高清電影、專業視頻制作。
  • 高QP值:適用于對比特率要求較高的場景,如實時視頻傳輸、低帶寬環境。

3.2 碼率

碼率(Bitrate)是指單位時間內傳輸的數據量,通常以kbps(千比特每秒)或Mbps(兆比特每秒)為單位。碼率在視頻和音頻編碼中起著至關重要的作用,直接影響到文件的質量和大小。

  1. 視頻質量:碼率越高,視頻質量越好,因為更多的數據可以用來表示圖像細節。反之,碼率越低,視頻質量越差。
  2. 文件大小:碼率越高,文件大小越大。對于同一段視頻,較高的碼率會導致更大的文件。
  3. 傳輸效率:在流媒體傳輸中,碼率決定了視頻流的帶寬需求。較高的碼率需要更高的網絡帶寬。

碼率的基本計算公式為:

碼率 (kbps)=\frac{文件大小 (KB)×8}{時間 (秒)}

碼率控制模式:

  1. 恒定碼率(CBR):碼率在整個視頻中保持恒定,適用于帶寬穩定的環境。
  2. 可變碼率(VBR):碼率根據視頻內容的復雜度動態調整,通常在保證質量的同時節省帶寬。
  3. 平均碼率(ABR):在指定的文件大小內,動態調整碼率以平衡質量和文件大小。

假設一個視頻文件大小為500MB,時長為10分鐘(600秒),其碼率計算如下:

碼率 (kbps)=\frac{500×1024×8}{600}≈6826.67 kbps

如何選擇合適的碼率?

  • 高質量需求:如高清電影、專業視頻制作,建議使用較高的碼率。
  • 實時傳輸:如視頻會議、直播,建議使用適中的碼率以平衡質量和帶寬需求。
  • 低帶寬環境:如移動網絡,建議使用較低的碼率以減少緩沖和卡頓。

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

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

相關文章

【C語言設計模式學習筆記1】面向接口編程/簡單工廠模式/多態

面向接口編程可以提供更高級的抽象,實現的時候,外部不需要知道內部的具體實現,最簡單的是使用簡單工廠模式來進行實現,比如一個Sensor具有多種表示形式,這時候可以在給Sensor結構體添加一個enum類型的type,…

AI大模型(二)基于Deepseek搭建本地可視化交互UI

AI大模型(二)基于Deepseek搭建本地可視化交互UI DeepSeek開源大模型在榜單上以黑馬之姿橫掃多項評測,其社區熱度指數暴漲、一躍成為近期內影響力最高的話題,這個來自中國團隊的模型向世界證明:讓每個普通人都能擁有媲…

C++基礎系列【2】C++基本語法

本文作為入門文檔&#xff0c;簡要介紹C的非常基本的語法&#xff0c;后面章節會詳細介紹C的各個語法。 C 程序結構 C程序的基本結構包括頭文件、命名空間、類和函數等。 下面我們通過Hello&#xff0c;World來展示這些元素。 #include <iostream> // 包含標準輸入輸…

【C語言】球球大作戰游戲

目錄 1. 前期準備 2. 玩家操作 3. 生成地圖 4. 敵人移動 5. 吃掉小球 6. 完整代碼 1. 前期準備 游戲設定:小球的位置、小球的半徑、以及小球的顏色 這里我們可以用一個結構體數組來存放這些要素,以方便初始化小球的信息。 struct Ball {int x;int y;float r;DWORD c…

圖的基本術語——非八股文

我之前只看到了數據結構與算法的冰山一角&#xff0c;感覺這些術語只會讓知識越來越難理解&#xff0c;現在來看&#xff0c;他們完美抽象一些概念和知識&#xff0c;非常重要。 本篇概念肯定總結不全&#xff0c;只有遇到的會寫上&#xff0c;持續更新&#xff0c;之前文章已經…

oracle: 表分區>>范圍分區,列表分區,散列分區/哈希分區,間隔分區,參考分區,組合分區,子分區/復合分區/組合分區

分區表 是將一個邏輯上的大表按照特定的規則劃分為多個物理上的子表&#xff0c;這些子表稱為分區。 分區可以基于不同的維度&#xff0c;如時間、數值范圍、字符串值等&#xff0c;將數據分散存儲在不同的分區 中&#xff0c;以提高數據管理的效率和查詢性能&#xff0c;同時…

【單層神經網絡】基于MXNet的線性回歸實現(底層實現)

寫在前面 剛開始先從普通的尋優算法開始&#xff0c;熟悉一下學習訓練過程下面將使用梯度下降法尋優&#xff0c;但這大概只能是局部最優&#xff0c;它并不是一個十分優秀的尋優算法 整體流程 生成訓練數據集&#xff08;實際工程中&#xff0c;需要從實際對象身上采集數據…

本地快速部署DeepSeek-R1模型——2025新年賀歲

一晃年初六了&#xff0c;春節長假余額馬上歸零了。今天下午在我的電腦上成功部署了DeepSeek-R1模型&#xff0c;抽個時間和大家簡單分享一下過程&#xff1a; 概述 DeepSeek模型 是一家由中國知名量化私募巨頭幻方量化創立的人工智能公司&#xff0c;致力于開發高效、高性能…

C++11詳解(一) -- 列表初始化,右值引用和移動語義

文章目錄 1.列表初始化1.1 C98傳統的{}1.2 C11中的{}1.3 C11中的std::initializer_list 2.右值引用和移動語義2.1左值和右值2.2左值引用和右值引用2.3 引用延長生命周期2.4左值和右值的參數匹配問題2.5右值引用和移動語義的使用場景2.5.1左值引用主要使用場景2.5.2移動構造和移…

在K8S中,pending狀態一般由什么原因導致的?

在Kubernetes中&#xff0c;資源或Pod處于Pending狀態可能有多種原因引起。以下是一些常見的原因和詳細解釋&#xff1a; 資源不足 概述&#xff1a;當集群中的資源不足以滿足Pod或服務的需求時&#xff0c;它們可能會被至于Pending狀態。這通常涉及到CPU、內存、存儲或其他資…

手寫MVVM框架-構建虛擬dom樹

MVVM的核心之一就是虛擬dom樹&#xff0c;我們這一章節就先構建一個虛擬dom樹 首先我們需要創建一個VNode的類 // 當前類的位置是src/vnode/index.js export default class VNode{constructor(tag, // 標簽名稱&#xff08;英文大寫&#xff09;ele, // 對應真實節點children,…

linux內核源代碼中__init的作用?

在 Linux 內核源代碼中&#xff0c;__init是一個特殊的宏&#xff0c;用于標記在內核初始化階段使用的變量或函數。這個宏的作用是告訴內核編譯器和鏈接器&#xff0c;被標記的變量或函數只在內核的初始化階段使用&#xff0c;在系統啟動完成后就不再需要了。因此&#xff0c;這…

【大數據技術】教程03:本機PyCharm遠程連接虛擬機Python

本機PyCharm遠程連接虛擬機Python 注意:本文需要使用PyCharm專業版。 pycharm-professional-2024.1.4VMware Workstation Pro 16CentOS-Stream-10-latest-x86_64-dvd1.iso寫在前面 本文主要介紹如何使用本地PyCharm遠程連接虛擬機,運行Python腳本,提高編程效率。 注意: …

pytorch實現門控循環單元 (GRU)

人工智能例子匯總&#xff1a;AI常見的算法和例子-CSDN博客 特性GRULSTM計算效率更快&#xff0c;參數更少相對較慢&#xff0c;參數更多結構復雜度只有兩個門&#xff08;更新門和重置門&#xff09;三個門&#xff08;輸入門、遺忘門、輸出門&#xff09;處理長時依賴一般適…

PAT甲級1032、sharing

題目 To store English words, one method is to use linked lists and store a word letter by letter. To save some space, we may let the words share the same sublist if they share the same suffix. For example, loading and being are stored as showed in Figure …

最小生成樹kruskal算法

文章目錄 kruskal算法的思想模板 kruskal算法的思想 模板 #include <bits/stdc.h> #define lowbit(x) ((x)&(-x)) #define int long long #define endl \n #define PII pair<int,int> #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); using na…

為何在Kubernetes容器中以root身份運行存在風險?

作者&#xff1a;馬辛瓦西奧內克&#xff08;Marcin Wasiucionek&#xff09; 引言 在Kubernetes安全領域&#xff0c;一個常見的建議是讓容器以非root用戶身份運行。但是&#xff0c;在容器中以root身份運行&#xff0c;實際會帶來哪些安全隱患呢&#xff1f;在Docker鏡像和…

js --- 獲取時間戳

介紹 使用js獲取當前時間戳 語法 Date.now()

ConcurrentHashMap線程安全:分段鎖 到 synchronized + CAS

專欄系列文章地址&#xff1a;https://blog.csdn.net/qq_26437925/article/details/145290162 本文目標&#xff1a; 理解ConcurrentHashMap為什么線程安全&#xff1b;ConcurrentHashMap的具體細節還需要進一步研究 目錄 ConcurrentHashMap介紹JDK7的分段鎖實現JDK8的synchr…

Vue和Java使用AES加密傳輸

背景&#xff1a;Vue對參數進行加密&#xff0c;對響應進行解密。Java對參數進行解密&#xff0c;對響應進行解密。不攔截文件上傳類請求、GET請求。 【1】前端配置 安裝crypto npm install crypto-js編寫加解密工具類encrypt.js import CryptoJS from crypto-jsconst KEY …