RTP封装h264

文章部分借用网上搜索到的资料

 

网络抽象层单元类型 (NALU):

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

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

F: 1个比特.
  forbidden_zero_bit. 在 H.264 规范中规定了这一位必须为 0.

NRI: 2个比特.
  nal_ref_idc. 取00~11,似乎指示这个NALU的重要性,如00的NALU解码器可以丢弃它而不影响图像的回放. 

Type: 5个比特.
  nal_unit_type. 这个NALU单元的类型.简述如下:

  0     没有定义
  1-23  NAL单元  单个 NAL 单元包

  24    STAP-A   单一时间的组合包
  25    STAP-B   单一时间的组合包
  26    MTAP16   多个时间的组合包
  27    MTAP24   多个时间的组合包
  28    FU-A     分片的单元
  29    FU-B     分片的单元
  30-31 没有定义

h264仅用1-23,24以后的用在RTP H264负载类型头中

 

不同类型的NALU的重要性指示如下表所示:

nal_unit_type

NAL类型

nal_reference_bit

0

未使用

 0

1

非IDR的片

此片属于参考帧,则不等于0,

不属于参考帧,则等与0

2

片数据A分区

同上

3

片数据B分区

同上

4

片数据C分区

同上

5

IDR图像的片

5

6

补充增强信息单元(SEI)

0

7

序列参数集

非0

8

图像参数集

非0

9

分界符

0

10

序列结束

0

11

码流结束

0

12

填充

0

13..23

保留

 0

24..31

不保留

 0

 

 

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
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |V=2|P|X|  CC   |M|     PT      |       sequence number         |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                           timestamp                           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |           synchronization source (SSRC) identifier            |
      +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
      |            contributing source (CSRC) identifiers             |
      |                             ....                              |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      VRTP协议的版本号,占2bits,当前协议版本号为2
      P填充标志,占1bit,如果P=1,则在该报文的尾部填充一个或多个额外的八位组,它们不是有效载荷的一部分。
      X扩展标志,占1bit,如果X=1,则在RTP报头后跟有一个扩展报头
      CCCSRC计数器,占4位,指示CSRC 标识符的个数
      M1bit,标记解释由设置定义,目的在于允许重要事件在包流中标记出来。如不同的有效载荷有不同的含义,对于视频,标记一帧的结束;对于音频,标记会话的开始。

      负载类型 Payload type(PT): 7bits
      注:rfc里面对一些早期的格式定义了这个payload type。但是后来的,如h264并没有分配,那就用96来代替。因此现在96以上都不表示特定的格式,具体表示什么要用sdp或者其他协议来协商。

      序列号 Sequence number(SN): 16bits,用于标识发送者所发送的RTP报文的序列号,每发送一个报文,序列号增1,序列号的初始值是随机产生的。可以用于检查丢包以及进行数据包排序。
      时间戳 Timestamp: 32bits,必须使用90kHz时钟频率。

      同步信源(SSRC)标识符32bits,用于标识同步信源。该标识符是随机随机产生的,参加同一视频会议的两个同步信源不能有相同的SSRC。
      特约信源(CSRC)标识符每个CSRC标识符占32bits,可以有0~15个。每个CSRC标识了包含在该RTP报文有效载荷中的所有特约信源。

 

上面介绍了NALU和RTP header的基本结构,下面介绍的全部都是RTP PayLoad的部分

Rtp负载第一个字节的结构如下,它和H.264的NALU头结构一致,可以把它认为是RTP h264负载类型字节,完全是多增加的一个字节,不影响后面的NALU结构

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

这里的Type类型除1-23外还可取以下值:

  24    STAP-A   单一时间的组合包
  25    STAP-B   单一时间的组合包
  26    MTAP16   多个时间的组合包
  27    MTAP24   多个时间的组合包
  28    FU-A     分片的单元
  29    FU-B     分片的单元

如果使用1-23就是:单一NAL单元模式

SDP文件描述和封包的关联:

m=video 49170 RTP/AVP 98
a=rtpmap:98 H264/90000
a=fmtp:98 profile-level-id=42A01E; packetization-mode=1; sprop-parameter-sets=Z0IACpZTBYmI,aMljiA==

packetization-mode:  表示支持的封包模式. 

当 packetization-mode 的值为 0 时或不存在时, 必须使用单一 NALU 单元模式.
当 packetization-mode 的值为 1 时必须使用非交错(non-interleaved)封包模式.
当 packetization-mode 的值为 2 时必须使用交错(interleaved)封包模式.

每个打包方式允许的NAL单元类型总结(yes = 允许, no = 不允许, ig = 忽略)

      Type   Packet    Single NAL    Non-Interleaved    Interleaved
                       Unit Mode           Mode             Mode
      -------------------------------------------------------------

      0      undefined     ig               ig               ig
      1-23   NAL unit     yes              yes               no
      24     STAP-A        no              yes               no
      25     STAP-B        no               no              yes
      26     MTAP16        no               no              yes
      27     MTAP24        no               no              yes
      28     FU-A          no              yes              yes
      29     FU-B          no               no              yes
      30-31  undefined     ig               ig               ig

 

封包介绍:

 

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

 

组合封包模式

  其次, 当 NALU 的长度特别小时, 可以把几个 NALU 单元封在一个 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
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                          RTP Header                           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |STAP-A NAL HDR |         NALU 1 Size           | NALU 1 HDR    |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                         NALU 1 Data                           |
      :                                                               :
      +               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |               | NALU 2 Size                   | NALU 2 HDR    |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                         NALU 2 Data                           |
      :                                                               :
      |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                               :...OPTIONAL RTP padding        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

这里只介绍STAP-A模式,如果是STAP-B的话会多加入一个DON域,另外还有MTAP16、MTAP24,具体不介绍,可以看rfc文档,文章尾贴一个链接可以去看。

转载的话注明一下作者:jwybobo2007 出处:http://blog.csdn.net/jwybobo2007/article/details/7054140

例:

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

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

[00 00 00 01 68 42 B0 12 58 6A D4 FF ... ]

封装成 RTP 包将如下:

[ RTP Header ] [78 (STAP-A头,占用1个字节)] [第一个NALU长度 (占用两个字节)] [ 67 42 A0 1E 23 56 0E 2F ] [第二个NALU长度 (占用两个字节)] [68 42 B0 12 58 6A D4 FF ... ]

 

分片的单元:

  当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

   The FU indicator octet has the following format:

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

   别被名字吓到这个格式就是上面提到的RTP h264负载类型,Type为FU-A

   The FU header has the following format:

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

   S bit为1表示分片的NAL开始,当它为1时,E不能为1

   E bit为1表示结束,当它为1,S不能为1

   R bit保留位

   Type就是NALU头中的Type,取1-23的那个值

例:

0x7C85=01111100 10000101 (开始包)

0x7C05=01111100 00000101 (中间包)

0x7C45=01111100 01000101 (结束包)

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

  [00 00 00 01 65 42 A0 1E 23 56 0E 2F ...  02 17 C8 FD F1 B9 C7 53 59 72 ... CB FF FF F4 1A D5 C4 18 A8 ... F1 B9 C7 1D A5 FA 13 0B ...]

封装成 RTP 包将如下:

[ RTP Header ] [ 7C 85 42 A0 1E 23 56 0E 2F ...]

[ RTP Header ] [ 7C 05 02 17 C8 FD F1 B9 C7 53 59 72 ...]

[ RTP Header ] [ 7C 05 CB FF FF F4 1A D5 C4 18 A8 ...]

[ RTP Header ] [ 7C 45 F1 B9 C7 1D A5 FA 13 0B ...]

 

附:

一个翻译过的rfc3984文档,翻译的有点乱,凑货的看看

http://wenku.baidu.com/view/0f612e1ec5da50e2524d7f32.html

  • 24
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
以下是一个简单的例程,用于封装H.265视频数据为RTP包: ```c #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> // RTP相关头文件 #include <netinet/in.h> #include <arpa/inet.h> // H.265视频帧头部长度 #define H265_FRAME_HEADER_SIZE 4 // RTP包头部长度 #define RTP_HEADER_SIZE 12 // RTP包最大大小 #define RTP_PACKET_MAX_SIZE 1500 // RTP会话结构体 typedef struct { int sockfd; // RTP套接字 struct sockaddr_in dest_addr; // 目标地址信息 uint16_t seq_num; // 序列号 uint32_t timestamp; // 时间戳 } RTPSession; // 初始化RTP会话 void init_rtp_session(RTPSession *session, const char *dest_ip, uint16_t dest_port) { // 创建RTP套接字 session->sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 设置目标地址信息 memset(&session->dest_addr, 0, sizeof(session->dest_addr)); session->dest_addr.sin_family = AF_INET; session->dest_addr.sin_port = htons(dest_port); session->dest_addr.sin_addr.s_addr = inet_addr(dest_ip); // 初始化序列号和时间戳 session->seq_num = 0; session->timestamp = 0; } // 发送RTP包 void send_rtp_packet(RTPSession *session, uint8_t *data, size_t size) { uint8_t packet[RTP_PACKET_MAX_SIZE]; uint16_t seq_num = htons(session->seq_num++); uint32_t timestamp = htonl(session->timestamp); // 封装RTP头部 memcpy(packet, &seq_num, sizeof(seq_num)); memcpy(packet + 2, &timestamp, sizeof(timestamp)); memcpy(packet + RTP_HEADER_SIZE, data, size); // 发送RTP包 sendto(session->sockfd, packet, size + RTP_HEADER_SIZE, 0, (struct sockaddr *)&session->dest_addr, sizeof(session->dest_addr)); // 更新时间戳 session->timestamp += 90000 / 30; // 假设每秒30帧 } int main() { RTPSession session; const char *dest_ip = "127.0.0.1"; uint16_t dest_port = 5004; // 初始化RTP会话 init_rtp_session(&session, dest_ip, dest_port); // H.265视频数据 uint8_t h265_data[] = {0x00, 0x00, 0x00, 0x01, /* H.265帧数据 */}; // 发送RTP包 send_rtp_packet(&session, h265_data + H265_FRAME_HEADER_SIZE, sizeof(h265_data) - H265_FRAME_HEADER_SIZE); return 0; } ``` 这个例程假设你已经有了H.265编码的视频帧数据,其中h265_data是一个包含完整H.265视频帧的字节数组。它从H.265帧数据中剥离出真正的视频数据,并将其封装RTP包,然后通过UDP套接字发送到指定的目标地址。 注意,这只是一个简单的例程,实际应用中可能需要更多的错误处理和优化。此外,确保目标地址和端口与你的实际需求相匹配。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值