关于Rtp封包方式之一的 FU-A分包方式

       RFC3984H.264baseline码流在RTP方式下传输的规范,这里只讨论FU-A分包方式,因为工作上刚刚用到,就记下来。

       FU_A一种分片封包的方式,就是将一个过大的NALU 单元封装成多个 RTP 包,这就不同以往那种单个NALU封装成单个RTP包方式,当然解析方式就不一样了。多个rtp包表示一个NALU单元,就涉及那个rtp包是这个NALU的开始,那个是结束,哪些是中间数据。当然,你可能关心的是I帧怎么解析。用Wireshark你可一非常直观的看到。

1.    SPS,以0x27开头,一般SPS数据量不大

2.     PPS,以0x28开头

3.     FU_A封包标志以及开始:RTP头+FU_A,FU_A 一般两个字节,包括FU indicator一个字节和FU header一个字节,看下图

其中0x3C包含FU indicator, 0x85包含FU header,但是3C和85不只包含这两个信息,还有其他信息,真正的FU indicator= 0x3C&1F = 28, FU header = 0x85&0xE0 = 0x80.所以,如果FU indicator为28,代表使用FU_A封包。FU header为0x80表示第一个RTP包。

4.     FU_A中间包以及结束的标志

FU header = 0x45&E0 = 0x40: 表示一个NALU使用FU_A方式封包结束,其他值代表中间的包

5.     I帧标志

找到FU header,让其后5位与上0x1F,如果结果是0x5,则该包位I帧数据,如上图0x5&0x1f= 0x5,所以上图标记的这包RTP数据位I帧的数据。一般PPS,SPS包的RTP头不需要用FU_A方式结尾。

代码实现的解包:从RTP中分拆出H264数据

         //功能:解码RTP H.264视频

// 参数:1.RTP包缓冲地址 2.RTP包数据大小 3.H264输出地址 4.输出数据大小

// 返回:true:表示一帧结束  false:FU-A分片未结束或帧未结束

#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;

}  

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值