解析rtp包h264数据

 代码如下

const int 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;                        // 获取FU indicator的类型域,
    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; // 大模式会有问题
            *((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; // 大模式会有问题
        *pOutLen = len - RTP_HEADLEN + 4;
    }

    unsigned char *bufTmp = (unsigned char *)bufIn;
    if (bufTmp[1] & 0x80)
    {
        bFinishFrame = true; // rtp mark
    }
    else
    {
        bFinishFrame = false;
    }
    return bFinishFrame;
}

1.单个NAL包单元

12字节的RTP头后面的就是音视频数据,比较简单。一个封装单个NAL单元包到RTP的NAL单元流的RTP序号必须符合NAL单元的解码顺序。
对于 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 包即可.

   0                   1                   2                   3
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |F|NRI|  type   |                                               |
  +-+-+-+-+-+-+-+-+                                               |
  |                                                               |
  |               Bytes 2..n of a Single NAL unit                 |
  |                                                               |
  |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                               :...OPTIONAL RTP padding        |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


如有一个 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 个字节的开始码就可以了.

2、组合封包模式

当 NALU 的长度特别小时, 可以把几个 NALU 单元封在一个 RTP 包中.

3、FU-A的分片格式

数据比较大的H264视频包,被RTP分片发送。12字节的RTP头后面跟随的就是FU-A分片:
而当 NALU 的长度超过 MTU 时, 就必须对 NALU 单元进行分片封包. 也称为 Fragmentation Units (FUs).

   0                   1                   2                   3
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  | FU indicator  |   FU header  |                               |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
  |                                                               |
  |                         FU payload                            |
  |                                                               |
  |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                               :...OPTIONAL RTP padding        |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  Figure 14.  RTP payload format for FU-A

Figure 14.  RTP payload format for FU-A


FU indicator有以下格式:

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


FU指示字节的类型域Type=28表示FU-A。。NRI域的值必须根据分片NAL单元的NRI域的值设置。

FU header的格式如下: 

  +---------------+
  |0|1|2|3|4|5|6|7|
  +-+-+-+-+-+-+-+-+
  |S|E|R|  Type   |
  +---------------+


S: 1 bit 当设置成1,开始位指示分片NAL单元的开始。当跟随的FU荷载不是分片NAL单元荷载的开始,开始位设为0。

E: 1 bit 当设置成1, 结束位指示分片NAL单元的结束,即, 荷载的最后字节也是分片NAL单元的最后一个字节。
当跟随的FU荷载不是分片NAL单元的最后分片,结束位设置为0。

R: 1 bit
保留位必须设置为0,接收者必须忽略该位。

Type: 5 bits
NAL单元荷载类型
 

要注意地方:

拆包和解包
拆包:当编码器在编码时需要将原有一个NAL按照FU-A进行分片,原有的NAL的单元头与分片后的FU-A的单元头有如下关系:

原始的NAL头的前三位为FU indicator的前三位,原始的NAL头的后五位为FU header的后五位,

FU indicator与FU header的剩余位数根据实际情况决定。

解包:当接收端收到FU-A的分片数据,需要将所有的分片包组合还原成原始的NAl包时,FU-A的单元头与还原后的NAL的关系如下:

还原后的NAL头的八位是由FU indicator的前三位加FU header的后五位组成,即:

nal_unit_type = (fu_indicator & 0xe0) | (fu_header & 0x1f)
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值