1. 程式人生 > >流媒體傳輸協議---RTP---荷載PS流

流媒體傳輸協議---RTP---荷載PS流

轉自:https://blog.csdn.net/chen495810242/article/details/39207305

  針對H264 做如下PS 封裝:每個IDR NALU 前一般都會包含SPS、PPS 等NALU,因此將SPS、PPS、IDR 的NALU 封裝為一個PS 包,包括ps 頭,然後加上PS system header,PS system map,PES header+h264 raw data。所以一個IDR NALU PS 包由外到內順序是:PSheader| PS system header | PS system Map | PES header | h264 raw data

。對於其它非關鍵幀的PS 包,就簡單多了,直接加上PS頭和PES 頭就可以了。順序為:PS header | PES header | h264raw data。以上是對只有視訊video 的情況,如果要把音訊Audio也打包進PS 封裝,也可以。當有音訊資料時,將資料加上PES header 放到視訊PES 後就可以了。順序如下:PS 包=PS頭|PES(video)|PES(audio),再用RTP 封裝傳送就可以了。

        GB28181 對RTP 傳輸的資料負載型別有規定(參考GB28181 附錄B),負載型別中96-127

        RFC2250 建議96 表示PS 封裝,建議97 為MPEG-4,建議98 為H264

        即我們接收到的RTP 包首先需要判斷負載型別,若負載型別為96,則採用PS 解複用,將音視訊分開解碼。若負載型別為98,直接按照H264 的解碼型別解碼。

        注:此方法不一定準確,取決於打包格式是否標準

PS 包中的流型別(stream type)的取值如下:

1)        MPEG-4 視訊流: 0x10;

2)        H.264 視訊流: 0x1B;

3)        SVAC 視訊流: 0x80;

4)        G.711 音訊流: 0x90;

5)        G.722.1 音訊流: 0x92;

6)        G.723.1 音訊流: 0x93;

7)        G.729 音訊流: 0x99;

8)       SVAC音訊流: 0x9B。
3.1、PS包頭

 


                                                 圖7

1)        Pack start code:包起始碼欄位,值為0x000001BA的位串,用來標誌一個包的開始

2)        System clock reference base,system clock reference extenstion:系統時鐘參考欄位

3)        Pack stuffing length :包填充長度欄位,3 位整數,規定該欄位後填充位元組的個數

80 60 53 1f 00 94 89 00 00 0000 00 00 00 01 ba €`S..??........?

7e ff 3e fb 44 01 00 5f 6b f8 00 00 01 e0 14 53 ~.>?D.._k?...?.S

80 80 05 2f bf cf bed1 1c 42 56 7b 13 58 0a 1e €€./????.BV{.X..

08 b1 4f 33 69 35 0453 6d 33 a8 04 15 58 d9 21 .?O3i5.Sm3?..X?!

9741 b9 f1 75 3d 94 2b 1f bc 0b b2 b4 97 bf 93 ?A??u=?+.?.?????
前12位是RTP Header,這裡不再贅述;

000001ba是包頭起始碼;

接下來的9位包括了SCR,SCRE,MUXRate,具體看圖7

最後一位是保留位(0xf8),定義了是否有擴充套件,二進位制如下

1111 1000

前5位跳過,後3位指示了擴充套件長度,這裡是0.

3.2、系統標題

 

                                                           圖8
Systemheader當且僅當pack是第一個資料包時才存在,即PS包頭之後就是系統標題。取值0x000001BB的位串,指出系統標題的開始,暫時不需要處理,讀取Header Length直接跳過即可
3.3、節目對映流
Systemheader當且僅當pack是第一個資料包時才存在,即系統標題之後就是節目流對映。取值0x000001BC的位串,指出節目流對映的開始,暫時不需要處理,讀取Header Length直接跳過即可。前5位元組的結構同系統標題,見圖8。


取一段碼流分析系統標題和節目對映流

00 00 01 ba 45 a9 d4 5c 34 0100 5f 6b f8 00 00  ...?E??\4.._k?..

01 bb 00 0c 80 cc f5 04 e1 7f e0 e0 e8 c0 c0 20  .?..€??.?.?????

00 00 01 bc 00 1e e1 ff00 00 00 18 1b e0 00 0c ...?..?......?..

2a 0a 7f ff 00 00 0708 1f fe a0 5a 90 c0 00 00  *........??Z??..

00 00 00 00 00 00 01 e0 7f e0 80 80 0521 6a 75  .......?.?€€.!ju
前14個位元組是PS包頭(注意,沒有擴充套件);

接下來的00 00 01 bb是系統標題起始碼;

接下來的00 0c說明了系統標題的長度(不包括起始碼和長度位元組本身);

接下來的12個位元組是系統標題的具體內容,這裡不做解析;

繼續看到00 00 01 bc,這是節目對映流起始碼;

緊接著的00 1e同樣代表長度;

跳過e1 ff,基本沒用;

接下來是00 18,代表基本流長度,說明了後面還有24個位元組;

接下來的1b,意思是H264編碼格式;

下一個位元組e0,意思是視訊流;

接下里00 0c,同樣代表接下的長度12個位元組;

跳過這12個位元組,看到90,這是G.711音訊格式;

下一個位元組是c0,代表音訊流;

接下來的00 00同樣代表長度,這裡是0;

接下來4個位元組是CRC,迴圈冗餘校驗。

到這裡節目對映流解析完畢。(好累)。

 

 

好戲還在後頭呢。

3.4、PES分組頭部

 


                                                         圖9

別被這麼長的圖嚇到,其實原理相同,但是,你必須處理其中的每一位。

1)        Packet start code prefix:值為0x000001的位串,它和後面的stream id 構成了標識分組開始的分組起始碼,用來標誌一個包的開始。

2)        Stream id:在節目流中,它規定了基本流的號碼和型別。0x(C0~DF)指音訊,0x(E0~EF)為視訊

3)        PES packet length:16 位欄位,指出了PES 分組中跟在該欄位後的位元組數目。值為0 表示PES 分組長度要麼沒有規定要麼沒有限制。這種情況只允許出現在有效負載包含來源於傳輸流分組中某個視訊基本流的位元組的PES 分組中。

4)        PTS_DTS:2 位欄位。當值為'10'時,PTS 欄位應出現在PES 分組標題中;當值為'11'時,PTS 欄位和DTS 欄位都應出現在PES 分組標題中;當值為'00'時,PTS 欄位和DTS 欄位都不出現在PES分組標題中。值'01'是不允許的。

5)        ESCR:1位。置'1'時表示ESCR 基礎和擴充套件欄位出現在PES 分組標題中;值為'0'表示沒有ESCR 欄位。

6)        ESrate:1 位。置'1'時表示ES rate 欄位出現在PES 分組標題中;值為'0'表示沒有ES rate 欄位。

7)        DSMtrick mode:1 位。置'1'時表示有8 位特技方式欄位;值為'0'表示沒有該欄位。

8)        Additionalinfo:1 位。附加版權資訊標誌欄位。置'1'時表示有附加拷貝資訊欄位;值為'0'表示沒有該欄位。

9)        CRC:1 位。置'1'時表示CRC 欄位出現在PES 分組標題中;值為'0'表示沒有該欄位。

10)    Extensionflag:1 位標誌。置'1'時表示PES 分組標題中有擴充套件欄位;值為'0'表示沒有該欄位。

PES header data length: 8 位。PES 標題資料長度欄位。指出包含在PES 分組標題中的可選欄位和任何填充位元組所佔用的總位元組數。該欄位之前的位元組指出了有無可選欄位。


老規矩,上碼流:

00 00 01 e0 21 33 80 80 05 2b 5f df 5c 95 71 84 ...?!3€€.+_?\?q?

aa e4 e9 e9 ec 40 cc17 e0 68 7b 23 f6 89 df 90 [email protected]?.?h{#????

a9d4 be 74 b9 67 ad 34 6d f0 92 0d 5a 48 dd 13 ???t?g?4m??.ZH?.

00 00 01是起始碼;
e0是視訊流;

21 33 是幀長度;

接下來的兩個80 80見下面的二進位制解析;

下一個位元組05指出了可選欄位的長度,前一位元組指出了有無可選欄位;

接下來的5位元組是PTS;

第7、8位元組的二進位制如下:

1000 0000 1000 0000

按順序解析:

第7個位元組:

10                         是標誌位,必須是10;

00                         是加擾控制欄位,‘00’表示沒有加密,剩下的01,10,11由使用者自定義;

0                           是優先順序,1為高,0為低;

0                           是資料對齊指示欄位;

0                           是版權欄位;

0                           是原始或拷貝欄位。置'1'時表示相關PES分組有效負載的內容是原始的;'0'表示內容是一份拷貝;

第8個位元組:

10                         是PTS_DTS欄位,這裡是10,表示有PTS,沒有DTS;

0                           是ESCR標誌欄位,這裡為0,表示沒有該段;

0                           是ES速率標誌欄位,,這裡為0,表示沒有該段;

0                           是DSM特技方式標誌欄位,,這裡為0,表示沒有該段;

0                           是附加版權資訊標誌欄位,,這裡為0,表示沒有該段;

0                           是PESCRC標誌欄位,,這裡為0,表示沒有該段;

0                           是PES擴充套件標誌欄位,,這裡為0,表示沒有該段;

本段碼流只有PTS,貼一下解析函式

unsigned long parse_time_stamp (const unsigned char *p)
{
unsigned long b;
//共33位,溢位後從0開始
unsigned long val;

//第1個位元組的第5、6、7位
b = *p++;
val = (b & 0x0e) << 29;

//第2個位元組的8位和第3個位元組的前7位
b = (*(p++)) << 8;
b += *(p++);
val += ((b & 0xfffe) << 14);

//第4個位元組的8位和第5個位元組的前7位
b = (*(p++)) << 8;
b += *(p++);
val += ((b & 0xfffe) >> 1);

return val;
}

其他欄位可參考協議解析

 

ps:

遇到00 00 01 bd的,這個是私有流的標識

ps:

另外,有的hk攝像頭回調然後解讀出來的原始h.264碼流,有的一包裡只有分界符資料(nal_unit_type=9)或補充增強資訊單元(nal_unit_type=6),如果直接送入解碼器,有可能會出現問題,這裡的處理方式要麼丟棄這兩個部分,要麼和之後的資料合起來,再送入解碼器裡,如有遇到的朋友可以交流一下:)