第43月第29天 rtp分包

1.

NALU 头由一个字节组成, 它的语法如下:

,以00 00 00 01分割之后的下一个字节就是NALU类型,将其转为二进制数据后,

解读顺序为从左往右算,如下:

(1)第1位禁止位,值为1表示语法出错

(2)第2~3位为参考级别

(3)第4~8为是nal单元类型

例如上面00000001后有67,68以及65

其中0x67的二进制码为:

0110 0111

4-8为00111,转为十进制7,参考第二幅图:7对应序列参数集SPS

其中0x68的二进制码为:

0110 1000
4-8为01000,转为十进制8,参考第二幅图:8对应图像参数集PPS

其中0x65的二进制码为:

011 00101

4-8位为00101,转为十进制5,参考第二幅图:5对应IDR图像中的片(I帧)

所以判断是否为I帧的算法为:

(NALU类型 & 0001 1111) = 5 即 (NALU类型 & 31) = 5
比如0x65 & 31 = 5

rtp

对于 NALU 的长度小于 MTU 大小的包, 一般采用单一 NAL 单元模式.
对于一个原始的 H.264 NALU 单元常由[Start Code] [NALU Header] [NALU Payload]三部分组成, 其中 Start Code 用于标示这是一个
NALU 单元的开始, 必须是 “00 00 00 01” 或 “00 00 01”, NALU 头仅一个字节, 其后都是 NALU 单元内容.

打包时去除 “00 00 01” 或 “00 00 00 01” 的开始码, 把其他数据封包的 RTP 包即可.

如有一个 H.264 的 NALU 是这样的:

[00 00 00 01 67 42 A0 1E 23 56 0E 2F … ]

这是一个序列参数集 NAL 单元. [00 00 00 01] 是四个字节的开始码, 67 是 NALU 头, 42 开始的数据是 NALU 内容.

封装成 RTP 包将如下:

[ RTP Header ] [ 67 42 A0 1E 23 56 0E 2F ]

即只要去掉 4 个字节的开始码就可以了.

nal

FU indicator有以下格式:

+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+

FU指示字节的类型域的28,29表示FU-A和FU-B。NRI域的值必须根据分片NAL单元的NRI域的值设置。(此处Type就是rtp分片类型) 见下表

.Type Packet Type name
---------------------------------------------------------
0 undefined -
1-23 NAL unit Single NAL unit packet per H.264
24 STAP-A Single-time aggregation packet
25 STAP-B Single-time aggregation packet
26 MTAP16 Multi-time aggregation packet
27 MTAP24 Multi-time aggregation packet
28 FU-A Fragmentation unit
29 FU-B Fragmentation unit
30-31 undefined

#define RTP_HEADLEN 12

bool UnpackRTPH264( void  *  bufIn, int len,   void **  pBufOut, int   *  pOutLen)

{

     *pOutLen  =   0 ;

    if  (len  < RTP_HEADLEN)

    {

       return   false ;

    }

 

   unsigned char *  src  = (unsigned  char* )bufIn +  RTP_HEADLEN;

   unsigned char  head1 =   * src; // 获取第一个字节

   unsigned  char  head2 =  * (src + 1 ); // 获取第二个字节

   unsigned  char  nal = head1 &   0x1f; // 获取FUindicator的类型域,

   unsigned  char  flag = head2 &   0xe0 ; // 获取FU header的前三位,判断当前是分包的开始、中间或结束

   unsigned  char  nal_fua = (head1 &   0xe0 )  | (head2 &   0x1f); // FU_A nal

   bool  bFinishFrame =   false ;

    if  (nal == 0x1c ) // 判断NAL的类型为0x1c=28,说明是FU-A分片

    {// fu-a

       if  (flag== 0x80 ) // 开始

        {

           * pBufOut =  src - 3 ;

           * (( int * )( * pBufOut))  =   0x01000000 ; // zyf:大模式会有问题

            * ((char * )( * pBufOut) + 4)  = nal_fua;

           *  pOutLen =  len - RTP_HEADLEN +   3 ;

       }

       else   if (flag == 0x40 ) // 结束

        {

           * pBufOut =  src + 2 ;

           *  pOutLen =  len - RTP_HEADLEN -   2 ;

       }

       else // 中间

        {

           * pBufOut =  src + 2 ;

           *  pOutLen =  len - RTP_HEADLEN -   2 ;

       }

    }

    else // 单包数据

    {

       * pBufOut =  src - 4 ;

       * (( int * )( * pBufOut))  =   0x01000000 ; // zyf:大模式会有问题

        *  pOutLen =  len - RTP_HEADLEN +   4 ;

    }

 

   unsigned char *  bufTmp  = (unsigned char* )bufIn;

    if  (bufTmp[ 1 ]  &  0x80 )

    {

       bFinishFrame =   true ; // rtpmark

    }

    else

    {

       bFinishFrame =   false ;

    }

    return  bFinishFrame;

}

https://blog.csdn.net/machh/article/details/52165292

https://blog.csdn.net/duan_jin_hui/article/details/67638024

原文地址:https://www.cnblogs.com/javastart/p/12800258.html