2012-03-08 163 views
10

我有一個來自IP攝像機的原始H.264流,打包在RTP幀中。我想將原始H.264數據轉換爲文件,以便我可以將它轉換爲ffmpegH.264 over RTP - 識別SPS和PPS幀

所以,當我想將數據寫入到我生的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] 
.... 

所以我得到的SPSPPSSession Description Protocol出來的我前面的RTSP通信。此外,在開始使用視頻流本身之前,相機會在兩條單獨消息中發送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 

再就是出現一些框架的有效載荷,並在某些時候RTP框架與Marker Bit = 1。這意味着(如果我說得對)我有一個完整的視頻框架。因此,我再次從有效載荷中寫入前綴序列(00 00 01)和NAL,並繼續執行相同的過程。

現在我的相機每隔8個完整的視頻幀發送給我SPSPPS。 (同樣在兩個RTP幀中,如上例所示)。我知道特別是PPS可以在流媒體之間改變,但這不是問題。

我的問題,現在:

1.我是否需要寫的SPS/PPS每8個視頻幀?

如果我的SPS和我的PPS不改變它應該足以讓他們寫在我的文件的開頭,沒有更多?

2.如何區分SPS/PPS和普通RTP幀?

在我解析傳輸數據的C++代碼中,我需要區分具有正常有效負載的RTP幀和攜帶SPS/PPS的RTP幀。我怎樣才能區分它們?好的SPS/PPS幀通常是小的,但這不是一個救人的呼籲依靠。因爲如果我忽略它們,我需要知道可以扔掉哪些數據,或者如果我需要寫出它們,我需要將00 00 01前綴放在它們前面。 ?或者它是一個固定的規則,他們每8個視頻幀發生?

+0

感謝您的這個問題。我和你有同樣的問題。我通過live555源代碼閱讀,不知道爲什麼他們保存每個數據包/框架。閱讀完這篇文章後,事情就變得很清楚了。作爲基於live555實現的建議,標記位僅用於其他編解碼器,H264具有自己的start_bit和end_bit來表示幀的開始/結束,標記位不用於H264。 – user534498 2015-03-31 01:50:24

回答

10
  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; 
+0

這意味着'SPS'和'PPS'幀的前2個字節也是某種「NAL狀態」,就像每個其他RTP幀的前兩個字節一樣?或換句話說 - 我期望7或8的SPS和PPS的nal_unit_type字段與我期望的28相同的字段意味着它的視頻數據? – Toby 2012-03-08 13:43:04

+2

有關nal_unit_type的詳細定義,您可以參考H.264文檔。 btw,(payload [0]&0x1f)== 28表示這是一個分段的視頻幀,在這種情況下,實際的nal_unit_type應該是(payload [1]&0x1f)。這在RFC3984中定義。 – ciphor 2012-03-08 13:55:04

+0

是的,我剛剛閱讀並得到它......但你怎麼知道nal_unit_type = 28是零碎的視頻幀? RFC 3984引用http://www-ee.uta.edu/dip/courses/ee5356/H264systems.pdf表7.1(頁63) - 那裏代碼28將歸入「未指定」。? – Toby 2012-03-08 14:04:53

10
  1. 你應該寫SPS和PPS在流的開始,只有當他們在流的中間改變。

  2. SPS和PPS幀用NAL類型24(STAP-A)或25(STAP-B)STAP格式RFC-3984 section 5.7.1

  3. 唐描述裝在一個STAP NAL單元(通常STAP-A)不依賴於標記位,使用NAL頭中的起始位和結束位。

  4. 對於分段視頻幀,您應該使用第一個片段(F,NRI)的3個NAL單元位與有效負載中第一個字節的5個NAL類型位(僅用於啓動位設置爲1的數據包)重新生成NAL單元RFC-3984 section 5.8

    零散 NAL單元的NAL單元類型字節未在分片單元的有效負載, 而是 片NAL單元的NAL單元類型字節的信息在被傳送包括作爲這樣在分片單元的指示符字段中以及在的類型字段中的F和NRI字段FU頭。

編輯:約NAL單元構造用於分片單元更多的解釋:

這是前兩個字節的FU-A的有效載荷的(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 Header」和「F」和「NRI」中從「FU indicator」中取「Type」

here是一個簡單的實現

+0

你能解釋第4項嗎?我已經閱讀過規格說明部分以及您多次引用的簡介,我不明白它描述的是什麼。這是否意味着應根據這些規則重構FU指示符,並丟棄FU報頭,並丟棄有效載荷的前5位,並將現在重建的FU指示符與有效負載(少於前5位)串聯起來?謝謝 – Joshua 2014-01-27 04:33:34

+1

@Joshua:我加了一些解釋 – 2014-01-27 08:14:05

+0

謝謝,代碼示例很優雅,我很感謝你的簡單解釋。事後看來,你引用的blurb是直接的,但是你在第4項中的解釋建議使用有效載荷中的位,因此我的困惑。我現在明白你的意思了。 – Joshua 2014-01-27 16:11:47