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的一些主要內容和結構:
- profile_idc:標識H.264碼流的profile,例如Baseline、Main、High等。
- level_idc:標識碼流的Level,定義了最大分辨率、最大幀率等參數。
- seq_parameter_set_id:序列參數集的ID,用于標識不同的SPS。
- log2_max_frame_num_minus4:用于計算frame_num的最大值,frame_num標識圖像的解碼順序。
- pic_order_cnt_type:指明圖像播放順序的編碼方法。
- log2_max_pic_order_cnt_lsb_minus4:用于計算POC(Picture Order Count)的最大值。
- max_num_ref_frames:指定參考幀隊列的最大長度。
- gaps_in_frame_num_value_allowed_flag:指示是否允許frame_num不連續。
- pic_width_in_mbs_minus1:圖像寬度,以宏塊為單位。
- pic_height_in_map_units_minus1:圖像高度,以宏塊為單位。
SPS中的信息對于解碼器初始化和正確解碼視頻流至關重要。如果SPS數據丟失或損壞,解碼器可能無法正確解碼視頻。
1.4 圖像參數集PPS
圖像參數集(Picture Parameter Set,PPS)包含了與單個圖像編碼相關的參數,這些參數用于控制圖像的編碼方式。以下是PPS的一些主要內容和結構:
- pic_parameter_set_id:當前PPS的唯一ID,取值范圍為0-255。
- seq_parameter_set_id:指明該PPS對應的SPS(序列參數集)ID。
- entropy_coding_mode_flag:表示使用的熵編碼類型,0為CAVLC,1為CABAC。
- num_slice_groups_minus1:表示slice group的數量,通常為0。
- num_ref_idx_l0_default_active_minus1和num_ref_idx_l1_default_active_minus1:表示P/B slice的前向和后向參考幀的最大個數減1。
- weighted_pred_flag:表示P slice的預測權重方式,0為默認預測權重,1為顯式方式。
- weighted_bipred_flag:表示B slice的預測權重方式,0為默認預測權重,1為顯式方式,2為隱式方式。
- pic_init_qp_minus26:用于計算Y分量的初始QP值。
- chroma_qp_index_offset:表示Cb分量QP相對于slice QP的偏移量。
- deblocking_filter_control_present_flag:表示是否存在去塊效應濾波器的控制語法元素。
- constrained_intra_pred_flag:表示幀內預測方式是否存在限制條件。
- transform_8x8_mode_flag:表示是否使用8x8大小的DCT變換方式。
- pic_scaling_matrix_present_flag:表示量化參數矩陣是否存在。
- 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格式結構:
- 頭部信息(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數據)
- 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)0x000001 或0x00000001 來分隔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值的作用:
- 控制壓縮質量:QP值越小,量化越精細,保留的圖像細節越多,視頻質量越高,但比特率也越高。相反,QP值越大,量化越粗糙,丟失的細節越多,視頻質量下降,但比特率降低。
- 調節比特率:通過調整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(兆比特每秒)為單位。碼率在視頻和音頻編碼中起著至關重要的作用,直接影響到文件的質量和大小。
- 視頻質量:碼率越高,視頻質量越好,因為更多的數據可以用來表示圖像細節。反之,碼率越低,視頻質量越差。
- 文件大小:碼率越高,文件大小越大。對于同一段視頻,較高的碼率會導致更大的文件。
- 傳輸效率:在流媒體傳輸中,碼率決定了視頻流的帶寬需求。較高的碼率需要更高的網絡帶寬。
碼率的基本計算公式為:
碼率 (kbps)=\frac{文件大小 (KB)×8}{時間 (秒)}
碼率控制模式:
- 恒定碼率(CBR):碼率在整個視頻中保持恒定,適用于帶寬穩定的環境。
- 可變碼率(VBR):碼率根據視頻內容的復雜度動態調整,通常在保證質量的同時節省帶寬。
- 平均碼率(ABR):在指定的文件大小內,動態調整碼率以平衡質量和文件大小。
假設一個視頻文件大小為500MB,時長為10分鐘(600秒),其碼率計算如下:
碼率 (kbps)=\frac{500×1024×8}{600}≈6826.67 kbps
如何選擇合適的碼率?
- 高質量需求:如高清電影、專業視頻制作,建議使用較高的碼率。
- 實時傳輸:如視頻會議、直播,建議使用適中的碼率以平衡質量和帶寬需求。
- 低帶寬環境:如移動網絡,建議使用較低的碼率以減少緩沖和卡頓。