web-dev-qa-db-ja.com

H.264 over RTP-SPSを識別し、PPSフレーム

IPカメラからの生のH.264ストリームがRTPフレームにパックされています。生のH.264データをファイルに取得して、ffmpegで変換できるようにしたいです。 。

したがって、生のH.264ファイルにデータを書き込みたいときは、次のようにする必要があることがわかりました。

00 00 01 [SPS] 
00 00 01 [PPS]
00 00 01 [NALByte]
[PAYLOAD RTP Frame 1]     // Payload always without the first 2 Bytes -> NAL
[PAYLOAD RTP Frame 2]
[... until PAYLOAD Frame with Mark Bit received]  // From here its a new Video Frame
00 00 01 [NAL BYTE]
[PAYLOAD RTP Frame 1]
....

したがって、前のSPS通信からSession Description ProtocolからPPSRTSPを取得します。さらに、カメラは、ビデオストリーム自体を開始する前に、2つの単一メッセージでSPSPPSを送信します。

したがって、メッセージを次の順序でキャプチャします。

1. Preceding RTSP Communication here ( including SDP with SPS and PPS )
2. RTP Frame with Payload: 67 42 80 28 DA 01 40 16 C4    // This is the SPS 
3. RTP Frame with Payload: 68 CE 3C 80                   // This is the PPS
4. RTP Frame with Payload: ...  // Video Data

次に、ペイロード付きのフレームがいくつかあり、ある時点でa RTP Marker Bit = 1付きのフレーム。これは、(正しく理解できれば)完全なビデオフレームがあることを意味します。これ以降、プレフィックスを記述しますペイロードから(00 00 01)とNALを再度シーケンスし、同じ手順を続行します。

これで、カメラは8つの完全なビデオフレームごとにSPSPPSを再度送信します。 (上記の例に見られるように、2つのRTPフレームで)。特にPPSはストリーミングの間に変更される可能性があることを知っていますが、それは問題ではありません。

私の質問は今です:

1.8番目のビデオフレームごとにSPS/PPSを書き込む必要がありますか?

SPSPPSが変更されない場合は、ファイルの最初に書き込むだけで十分ですか?

2。SPS/PPSと通常のフレームを区別する方法RTPフレーム?

送信されたデータを解析する私のC++コードでは、RTP通常のペイロードのフレームとSPS/PPSを運ぶフレームを区別する必要があります。どうすればそれらを区別できますか?さて、SPS/PPSフレームは通常方法です小さいですが、これは信頼できる保存呼び出しではありません。無視する場合は、破棄できるデータを知る必要があるため、または書き込む必要がある場合は、その前に00 00 01プレフィックスを付ける必要があります。それらは8番目のビデオフレームごとに発生するという固定ルールですか?

14
Toby
  1. SPSとPPSが変更されない場合は、最初のものを除いて省略できます。
  2. 各NALのnal_unit_typeフィールドを解析する必要があります。SPSの場合、nal_unit_type == 7; PPSの場合、nal_unit_type == 8。

私が覚えているように、nal_unit_typeはフレームの最初のバイトの下位5ビットです。

nal_unit_type = frame[0] & 0x1f;
12
ciphor
  1. SPSとPPSは、ストリームの開始時に、ストリームの途中で変更された場合にのみ記述してください。

  2. SPSおよびPPSフレームは、NALタイプ24(STAP-A)または25(STAP-B)のSTAP NALユニット(通常はSTAP-A)にパックされます。STAP形式は RFC-3984セクション5.7.1

  3. マーカービットに依存せず、NALヘッダーの開始ビットと終了ビットを使用します。

  4. フラグメント化されたビデオフレームの場合、ペイロードの最初のバイトの5つのNALタイプビットと組み合わせた最初のフラグメント(F、NRI)の3つのNALユニットビットを使用してNALユニットを再生成する必要があります(開始ビットが1に設定されたパケットの場合のみ)チェック RFC-3984セクション5.8

    フラグメント化されたNALユニットのNALユニットタイプオクテットは、フラグメント化ユニットペイロードにそのまま含まれませんが、フラグメント化されたNALユニットのNALユニットタイプオクテットの情報は、FUインジケーターオクテットおよびFUヘッダーのタイプフィールド。

編集:フラグメンテーションユニットのNALユニット構築に関する詳細:

これは、FU-Aペイロードの最初の2バイトです(rtpヘッダーの直後)。

|  FU indicator |   FU header   |
+---------------+---------------+
|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|F|NRI|  Type   |S|E|R|  Type   |
+---------------+---------------+

nALユニットを構築するには、「FUヘッダー」から「タイプ」を、「FUインジケーター」から「F」と「NRI」を取得する必要があります。

ここ は単純な実装です

12
arash kordi