RTP协议浅解

在工作中经常与RTP打交道,在这里总结一点工作经常使用和注意的地方。

基本概念

        RTP(Real-time Transport Protocol,实时传输协议)是一种用于在IP网络中传输多媒体数据的协议,由IETF(Internet Engineering Task Force)制定。其主要功能是提供端到端的实时数据传输服务,特别适用于音频、视频等多媒体数据的传输。

        RTP协议基于多播或单播进行连续传输媒体数据的实时传输服务,RTP通常与RTCP配合使用,RTP主要负责实时数据的传输,而RTCP则负责监控传输质量、提供控制信息和管理会话参与者的信息,RTCP通过周期性地发送统计信息和反馈报告,帮助RTP调整传输速率和解决网络拥塞问题。由于TCP需要较多的开销不适合传输实时数据,一般采用RTP/UDP来传输实时媒体数据(也可以用UDP/TCP)。

RTP传输H264数据的过程如下:

RTP封装H264

RTP报文

RTP报文由两部分组成:报头+有效负载(H264数据),RTP报头格式如下:

V:版本号,2比特,用来标志使用的RTP版本;

P:填充位,1比特,如果P=1,则在报文尾部将填充一个或多个额外的八位组,它们不是有效载荷的一部分。

X:扩展位,1比特,如果X=1,则在RTP头部后跟有扩展头(有些多路视频源的场合可以使用)。

CC:CSRC计数器,4比特,指示CSRC标识符的个数。主要用于多流组合传播,比如说有x个人发送RTP到网关边缘,边缘会把这x个RTP转发给另一个边缘,然后解码出原始流。

M:标记位,1比特,对于视频来说表示一帧的结束,对于音频标记会话的开始。

PT:载荷类型,7比特,标识RTP载荷的类型。

SN:序列号,16比特,标识发送这发送的RTP报文的序列号,每发送一个报文,序列号+1,接收者通过序列号检测报文丢失情况,重新排序报文,恢复数据。

TimeStamp:时间戳,32位,记录了包中数据的第一个字节的采样时刻,即使没有没有信号发送时,时间戳的数值也会不断增加,时间戳主要作用是计算延迟和延迟抖动,进行同步控制这些。

SSRC:同步源标识符,32位,指RTP包的来源,同一个会话不会有两个一样的,MD5算法生成。

CSRC:特约信源,每一个占32位,可以有0~15个,标识了包含在RTP报文有效载荷中的所有有贡献的源。

#ifndef _rtp_header_h_
#define _rtp_header_h_

#include <stdint.h>

/*
 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        |
|                               ....                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/

#define RTP_VERSION 2 // RTP version field must equal 2 (p66)

typedef struct _rtp_header_t
{
	uint32_t v:2;		/* protocol version */
	uint32_t p:1;		/* padding flag */
	uint32_t x:1;		/* header extension flag */
	uint32_t cc:4;		/* CSRC count */
	uint32_t m:1;		/* marker bit */
	uint32_t pt:7;		/* payload type */
	uint32_t seq:16;	/* sequence number */
	uint32_t timestamp; /* timestamp */
	uint32_t ssrc;		/* synchronization source */
} rtp_header_t;

#define RTP_V(v)	((v >> 30) & 0x03) /* protocol version */
#define RTP_P(v)	((v >> 29) & 0x01) /* padding flag */
#define RTP_X(v)	((v >> 28) & 0x01) /* header extension flag */
#define RTP_CC(v)	((v >> 24) & 0x0F) /* CSRC count */
#define RTP_M(v)	((v >> 23) & 0x01) /* marker bit */
#define RTP_PT(v)	((v >> 16) & 0x7F) /* payload type */
#define RTP_SEQ(v)	((v >> 00) & 0xFFFF) /* sequence number */

#endif /* !_rtp_header_h_ */

H264

        H264是一种由国际电信联盟和国际话组织联合开发的视频压缩标准,它旨在通过高效的压缩算法实现高质量视频的传输和存储,同时减低所诉的带宽和存储空间。

H264有两种组织格式

        1. AVCC格式,MPEG-4格式,字节对齐,主要用于mp4/flv/mkv等封装中,AVCC格式使用NALU长度进行分割,在封装或者流的头部包含extradata信息,exteadata中含有NALU长度的字节数以及SPS和PPS信息。

        2. Annex-B格式,MPEG-2 transport stream format格式,ts流中常用这种格式,本文也主要介绍这一种格式,Annex-B格式使用start code进行分割,start code有两种,一种为0x00 00 01,另一种0x00 00 00 01。

        接收到SPS+PPS+SEI后表示这一帧为IDR帧。视频由frame组成,frame分为IDR帧、I帧、B帧、P帧,在推流H264视频时首先发送的就是一帧IDR帧,因为接收到IDR帧就得到了PPS和SPS,就可以知道视频的信息知道怎么解码,后面可以全是P帧,可以有B帧,可以有I帧,直播一般只有IDR帧、I帧和P帧。

        NALU组成: [start code] [NAL头] [NAL payload]

        看一下NAL头部的定义:

F : 1比特,一般为0。

NRI:2比特,指示NALU单元的重要性,一般不太关心。

TYPE:5比特,表示这个NALU单元的类型。

RTP三种封包模式

        IP协议中MTU最大长度为1500字节:IP报头:20字节,UDP报头:8字节,RTP头12字节,NALU的长度不可以超过1460字节(RTP负载的NALU长度)。如果用TCP的话TCP报头20字节,自己算,就是一共不可以超过1500字节。

        1.  单一封包模式:NALU可以放入一个RTP中不超过1500字节的可以使用这种模式,打包时除去start code即可,把其他的数据放入RTP包中即可。

        2.  组合封包模式:当NALU长度很小,可以把几个NALU放入一个RTP包中且不超过1500字节的可以使用这种模式。常用的是STAP-A模式,这种模式同样去掉start code,然后在第一个NAL payload前加入 STAP-A头(1字节)紧接着是第一个NAL payload长度(2字节)然后紧接 NAL payload 。

RTP header + STAP-A头 + 第一个NAL payload长度 + 第二个NAL payload + 第二个NAL payload长度 + 第二个NAL payload ....

        3. 分片封包模式:当NALU的长度超过了MTU时,使用分片的模式。在封装时需要使用FU indicator + FU header 替换NALU原来的头部。这种方式称为Fragmentation Units(FUs)。

FU indicator + FU header + FU payload ....

FU indicator:

F、NRI与NAL头相同含义,TYPE固定28。

FU Header

S:S = 1 表示分片打包的第一个包。

E:E = 1 表示分片打包的最后一个包。

TYPE:如果是H264的话就是NALU的TYPE。

FU payload 为去掉起始码和头部的NAL的NAL payload

RTP封装H264解析

RTP封装常用的就是单一封包和分片封包模式,组合基本不用。

RTP序号每发送一个包就 + 1 ,同一个NALU的分片的RTP包时间戳不变。

H264类型:

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

解析时按照每一位去解析即可,最简单的解析方式使用wireshark去抓包一个字节一个去解析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值