H.264 FU-A RTP 断片化の修正: RTSP ビデオが壊れる理由 (パケット損失、NAL 再構成)

H.264 FU-A RTP フラグメンテーションによる壊れた RTSP ビデオを修正します。フラグメントの欠落、開始/終了ビットのバグ、NAL 再構成の失敗、パケット損失、MTU、およびデコーダ エラーを実際の診断コマンドでカバーします。

h264 ふあ, rtp フラグメンテーション, rtspビデオ, パケットロス, ナルユニットの再組み立て, h264デコーダエラー, rtsp 診断

H.264 over RTP はデコーダのバグのように見えますが、実際にはパケット化の問題です。 RTSP セッションは機能します。 DESCRIBE は有効な SDP を返します。セットアップは成功します。 PLAY は 200 OK を返します。 RTP パケットは、H.264 にマッピングされた正しいペイロード タイプで到着します。それでも、ビデオにはブロックの破損、フリーズ、ブラック フレーム、またはデコーダ エラーが表示されます。

ログではエラーは次のようになります。

[h264 @ 0x...] invalid NAL unit size
[h264 @ 0x...] missing picture in access unit
[h264 @ 0x...] non-existing PPS 0 referenced
[h264 @ 0x...] decode_slice_header error
[h264 @ 0x...] no frame!

The fast answer

Why fragmentation exists

The structure of an FU-A packet

Each FU-A RTP packet contains:

Byte 0: FU indicator
  bit 7: F (forbidden_zero_bit) — normally 0
  bits 6-5: NRI (nal_ref_idc) — priority
  bits 4-0: Type = 28 (FU-A)
Byte 1: FU header
  bit 7: S (Start) — 1 for first fragment
  bit 6: E (End) — 1 for last fragment
  bit 5: R (Reserved) — always 0
  bits 4-0: Type — original NAL unit type (1=non-IDR, 5=IDR, 7=SPS, 8=PPS)
Byte 2+: Fragment payload — the actual NAL unit data

1 つの NAL ユニットの完全な FU-A シーケンス:

Packet 1: FU indicator (type=28) | FU header (S=1, E=0, type=5) | payload[0..N]
Packet 2: FU indicator (type=28) | FU header (S=0, E=0, type=5) | payload[N+1..M]
Packet 3: FU indicator (type=28) | FU header (S=0, E=0, type=5) | payload[M+1..P]
Packet 4: FU indicator (type=28) | FU header (S=0, E=1, type=5) | payload[P+1..END]

The RTP marker bit

Failure modes: what breaks and why

Failure 1: Missing middle fragment

Expected:  1000(S)  1001(M)  1002(M)  1003(E|marker)
Received:  1000(S)  1001(M)  [LOST]   1003(E|marker)

リアセンブラーは開始フラグメント、1 つの中間フラグメント、次に終了フラグメントを認識しますが、ペイロード バイトは接続されません。再組み立てされた NAL ユニットには隙間があります。

症状:

  • フレームの横帯のブロック破損
  • デコーダが「無効な NAL ユニット サイズ」を報告する
  • 破損は 1 つのアクセス ユニットに限定されます (次の IDR で解消されます)

失敗 2: 開始フラグメントの欠落

Expected:  1000(S)  1001(M)  1002(E)
Received:  [LOST]   1001(M)  1002(E)

Failure 3: Missing end fragment

Expected:  1000(S)  1001(M)  1002(E|marker)
Received:  1000(S)  1001(M)  [LOST]

再アセンブラーは最後のフラグメントを決して認識しません。 NAL ユニットの境界は決して確認されません。デコーダは、到着しないさらなるデータを待ちます。

症状:

  • ビデオがフリーズする
  • デコーダーが「アクセス ユニットに画像がありません」と報告する
  • 次の完全なアクセス ユニットが到着するまで再生が停止します

失敗 4: フラグメントの順序が乱れている

Expected:  1000(S)  1001(M)  1002(E)
Received:  1000(S)  1002(E)  1001(M)

Diagnostic workflow

Step 1: Confirm H.264 payload mapping

m=video 0 RTP/AVP 96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=4D0029;sprop-parameter-sets=...
  • 「packetization-mode=1」は非インターリーブモードを意味します(FU-Aがサポートされています)
  • 「packetization-mode=0」はシングル NAL ユニット モードを意味します (断片化なし - 非常に限定的)

ステップ 2: RTP シーケンス番号を追跡する

キャプチャで、ビデオ トラックの RTP シーケンス番号を確認します。ギャップはパケット損失を示します。

Seq 1000: FU-A Start, NAL type 5 (IDR)
Seq 1001: FU-A middle
Seq 1003: FU-A End, marker=1   ← gap at 1002

Step 3: Inspect FU-A headers

Byte 0 (FU indicator):
  0x7C = NRI=3, Type=28 (FU-A)

バイト 1 (FU ヘッダー):
  0x85 = S=1、E=0、R=0、Type=5 (IDR スライス) ← IDR の開始フラグメント
  0x45 = S=0、E=0、R=0、Type=5 ← 中央のフラグメント
  0x65 = S=0、E=1、R=0、Type=5 ← 終了フラグメント。この NAL がアクセスユニット末尾の場合だけマーカーを設定

探す値が間違っています:

  • 非開始パケットの S=1 → 再アセンブラの混乱
  • E=1 より前にマーカーを設定 → 誤ったアクセスユニット境界
  • E=1 でも後続 NAL がある場合は、マーカー未設定が正しいことがあります
  • シーケンス途中でタイプが変更される → エンコーダーのバグまたはストリームの破損

ステップ 4: 完全に再組み立てされたことを確認する

各 NAL ユニットについて:

  1. 開始フラグメントを見つけます (S=1)
  2. 最後のフラグメント (E=1) まで連続するシーケンス番号をたどります。
  3. フラグメントを数えます。配列ギャップがないことを確認する
  4. マーカーをアクセスユニット境界と照合し、すべての FU-A 終了フラグメントには要求しません。
  5. すべてのフラグメントのタイムスタンプと NAL タイプが同じであることを確認します。

ステップ 5: トランスポート モードを比較する

UDP と TCP をインターリーブして同じストリームを実行します。 TCP ではビデオが正常でも、UDP では破損している場合、問題はエンコーダやデコーダの問題ではなく、ネットワーク パケット損失です。

ステップ 6: IDR と非 IDR の分析

IDR フレームはより大きく、NAL ユニットごとにより多くの FU-A フラグメントを必要とします。フラグメントが多い = パケット損失の危険性が高くなります。破損が主にシーンの変更時または数秒ごと (IDR 間隔で) に発生する場合、IDR フレームが被害者になります。

修正オプション:

  • IDR フレーム サイズを小さくします (キーフレームの解像度またはビットレートを下げます)。
  • IDR 間隔を長くします (大きなフレームは少なくなりますが、損失からの回復が遅くなります)
  • エンコーダーでの FU-A の MTU を削減します (フラグメントは増えますが、それぞれのフラグメントが小さくなり、IP フラグメンテーションが引き起こされる可能性が低くなります)。

回復戦略

再アセンブラーで

  • 部分的なデータをデコーダに供給するのではなく、損傷したアクセスユニットを完全に削除します
  • RTCP 経由で新しい IDR フレームをリクエストします (カメラでサポートされている場合)
  • 次の IDR フレームを待ちます (デコーダは自動的に回復します)。

エンコーダで

  • NAL ユニット サイズ制限を下げて、アクセス ユニットあたりのフラグメントを削減します。
  • 完全な IDR フレーム (小さいキーフレーム) の代わりに定期的なイントラリフレッシュを使用します。
  • RTP スタックがサポートしている場合、FEC (前方誤り訂正) を有効にします。

ネットワークで

  • パケット損失が避けられない場合は、UDP から TCP インターリーブに切り替える
  • パス MTU 検出が機能することを確認します (IP フラグメンテーションを回避します)。
  • 混雑したリンク上の RTP トラフィックを優先する

FU-Aではないとき

すべての H.264 破損が FU-A 断片化であるわけではありません。チェック:

  • SPS/PPS が欠落しています: 「存在しない PPS」などのデコーダ エラー — SDP sprop-parameter-sets を確認してください
  • 間違ったプロファイル/レベル: デコーダーはストリームの複雑さを処理できません
  • エンコーダのバグ: エンコーダは無効な NAL ユニット構文を生成します
  • ソースのビットストリーム破損: ネットワークではなく、カメラのエンコーダが壊れています

RTP パケットが完全なシーケンス番号と正しい FU-A ヘッダーで到着してもデコーダが失敗する場合、問題はトランスポートではなく H.264 ビットストリーム自体にあります。

<!-- rtsp-localized-evidence-foundation-v1:start -->

「H.264 FU-A RTP 断片化の修正: RTSP ビデオが壊れる理由 (パケット損失、NAL 再構成)」を再現可能に検証する手順

結論から言うと、黒画面や一つのステータスコードだけでは障害の所在を証明できません。信頼できる診断では、RTSP の要求と応答、合意した Transport、有効な Session、その後の RTP シーケンス番号、タイムスタンプ、RTCP の証拠を一つの時系列につなげます。「H.264 FU-A RTP 断片化の修正: RTSP ビデオが壊れる理由 (パケット損失、NAL 再構成)」では表示症状に近い層から調べますが、制御、ネットワーク、デコーダーの問題を混同しないよう同じ記録時刻を使います。

カメラ、ファイアウォール、VMS の設定を変える前に、小さな基準テストを作ります。パスワードを除いた RTSP URL、時刻、パス、要求した Transport、サーバー応答、最初のメディアパケット到着時刻を記録してください。機器が対応する場合は UDP と TCP interleaved を別々に試します。パス、認証情報、Transport を同時に変えると、二回目の成功がどの変更によるものか分かりません。

確認層 保存する証拠 判断する質問
RTSP メソッド、状態、ヘッダー、CSeq、Session サーバーはその操作を受理したか
SDP control、payload type、clock rate、codec 期待するトラックが記述されているか
Transport client_port、server_port、interleaved 両端が同じ経路を使うか
RTP SSRC、sequence、timestamp、marker メディア単位が説明可能な順序で届くか
RTCP sender report、CNAME、BYE 時計、識別子、終了を追跡できるか
Decoder SPS/PPS/VPS、packetization mode 受信 payload で初期化できるか

「メディアが届かない」と「届くが復号できない」を分けます。SETUP と PLAY が成功しても RTP がなければ、UDP 経路、NAT、ファイアウォール、Transport 応答を調べます。シーケンスの穴は損失または並べ替えを示します。連続した RTP があるのに映像がなければ、payload type、clock rate、フレーム境界、H.264 または H.265 のパラメーターへ進みます。この境界はプレーヤーの一般的なエラーより有用です。

引用できる短い回答はどう書きますか

三文で、最後に成功した操作、最初に失敗した証拠、二つの原因を分ける次の試験を書きます。例は「DESCRIBE、SETUP、PLAY は成功した。通知されたクライアントポートに RTP が届かない。TCP interleaved の再試験で UDP 遮断とメディアパス誤りを分ける」です。応答やパケットなしにカメラやネットワーク全体を原因と断定しません。

再現に必要な最小情報は何ですか

OPTIONS、DESCRIBE、SETUP、PLAY、SDP、Transport 応答、秘密を除いた Session を保存します。RTP は SSRC、最初と最後のシーケンス、clock rate、欠落数、収録時間を記録します。VLC や別 VMS の成否は差分試験として有用ですが、成功したクライアントが全規則を正しく扱う証明ではありません。

サーバーとクライアントのどちらを調べますか

メソッド拒否、存在しない control URL、不一致 Transport、説明のない SSRC や時計変更はサーバー側を調べます。期限切れ nonce の再利用、Session 欠落、ポートを開かない UDP 要求、各 NAL 終端を access unit 終端とみなす処理はクライアント側を調べます。中間経路の問題では、各結論にパケットと時刻を添えます。

報告前に何を確認しますか

新しい接続で再試験し、二つの時系列を最初の相違点まで比較します。パスワードと完全な Authorization 値を削除し、結論を CSeq、sequence、timestamp に結び付けます。関連する RTSP ガイドで周辺手順を確認し、RTSP Inspectorで RTSP ストリームをローカルに試験してください。カメラ映像を公開サービスへアップロードする必要はありません。

<!-- rtsp-localized-evidence-foundation-v1:end -->