在流媒體開發中,從 H.264 原始碼流(ES)提取呈現時間戳(PTS)是關鍵技術。本文系統整理從 NALU 分割、SPS 解析幀率、Slice 類型判斷、幀邊界偵測,到兩種 PTS 計算方法的完整流程,並提供核心程式碼片段與公式推導。
H.264 ES 資料以 NALU(Network Abstraction Layer Unit)為單位傳輸/儲存。每個 NALU = NALU Header + RBSP(Raw Byte Sequence Payload)。
第一步:將位元流分割為獨立 NALU(依起始碼 0x000001 或 0x00000001 切分)。
nal_type == 0x07 為 SPS(Sequence Parameter Set)。time_scale 與 num_units_in_tick,幀率公式:fps = time_scale / num_units_in_tick
注意:標準中此值通常為實際幀率的 2 倍(因場編碼),後續計算需除以 2 或對應調整。
// nal_type 範圍 1~5 為 Slice 類型
if (i_nal_type < 1 || i_nal_type > 5) {
// 找到 Slice NALU
}
掃描 NALU 資料,若某位元組與 0x80 邏輯與為真,視為幀邊界(實為 first_mb_in_slice == 0 的副作用)。
for (uint32_t i = 3; i < nal_length; i++) {
if (p_nal[i] & 0x80) {
// 找到 frame_begin:上一幀結束、下一幀開始
}
}
first_mb_in_slice完整解析 Slice Header,若 first_mb_in_slice == 0(UE 解碼後),即為新幀開始。VLC 採用 nal_type + slice_type 組合判斷。
根據 slice_type 對映:
switch (slice_type) {
case 2: case 7: case 4: case 9: flags = I_FRAME; break; // I
case 0: case 5: case 3: case 8: flags = P_FRAME; break; // P
case 1: case 6: flags = B_FRAME; break; // B
default: flags = 0; break;
}
H.264 編碼順序 ≠ 顯示順序。例:
編碼順序: I P B B I P B B ...
顯示順序: 1 4 2 3 5 8 6 7 ...
公式:
PTS = 1000 * (display_order) * (time_scale / num_units_in_tick)
需緩存至少一個 GOP 才能確知 P 幀的顯示位置(因其在後續 B 幀之後)。
pic_order_cnt_lsb(無需幀緩存)每個 Slice Header 含 pic_order_cnt_lsb,表示該幀在當前 GOP 內的顯示順序(以 2 為單位遞增)。
公式:
pts = 1000 * (i_frame_counter * 2 + pic_order_cnt_lsb) * (time_scale / num_units_in_tick)
// 或等價
pts = 1000 * (i_frame_counter + pic_order_cnt_lsb / 2) * (time_scale / num_units_in_tick / 2)
i_frame_counter:最近一個 IDR 幀(I 幀)的幀序號(以 2 為單位累加)。pic_order_cnt_lsb:當前幀在 GOP 內的相對顯示順序(0, 2, 4, 6...)。幀類型: I P B B I P B B I P B ...
第幾幀: 1 2 3 4 5 6 7 8 9 10 11 ...
顯示順序: 1 4 2 3 5 8 6 7 9 12 10 ...
POC lsb: 0 6 2 4 0 6 2 4 0 6 2 ...
第 11 幀(B 幀)PTS 計算:1000 * (9*2 + 2) * (time_scale/num_units_in_tick)。
上述 PTS 基準為 1ms(1000 Hz)。MPEG-TS 要求 90 kHz 基準,故最終須乘以 90:
PTS_90k = PTS_1ms * 90
推測與場編碼有關:SPS 中 time_scale/num_units_in_tick = 2 * fps,POC 以 2 遞增,對應頂場/底場。SPS 中的 offset_for_top_to_bottom_field 或可指示場結構,但屬推測,待專家確認。
掌握 NALU 分割、SPS/Slice 解析、POC 機制,即可在無容器封裝的裸流中精準重建 PTS。方法二(POC 法)因無需緩存、延遲低,更適合即時串流解析場景。