RTP文档规范
文档查阅网址
https://www.rfc-editor.org/rfc/rfc3550
https://www.rfc-editor.org/rfc/rfc5285
对比说明
在RFC3550头扩展包含一个16位的defined by profile字段和16位长度的字段表征扩展头长度,此处的长度是扩展头32位的个数,比如,扩展头长度是8字节,则length=2。但这个扩展头方法最多存在两个缺陷:首先,在每个rtp包中最多只允许一个扩展头;其次,该规范没有提供关于如何分配16位头扩展标识符defined by profile以避免冲突的方案。
在RFC5285中针对以上两个缺陷做出了修改,针对第一个,新协议在单个RTP包中可以有多个扩展头,通过定义URI命名的扩展元素;定义在IETF规范中定义的扩展元素的IANA注册表,以及用于在命名URI和RTP数据包中携带的标识符值之间映射的会话描述协议(SDP)方法,从而消除了第二个缺陷。数据包中的每个扩展元素都具有一个本地标识符(ID)和一个长度。流中存在的本地标识符必须在带外进行协商或定义,每个不同的扩展都必须有一个唯一的ID。值0保留用于填充,不能用作本地标识符。
有两种类型的扩展头:one-byte 和two-byte扩展头。
RFC3550扩展头英文说明
5.3.1 RTP Header Extension
An extension mechanism is provided to allow individual
implementations to experiment with new payload-format-independent
functions that require additional information to be carried in the
RTP data packet header. This mechanism is designed so that the
header extension may be ignored by other interoperating
implementations that have not been extended.
Schulzrinne, et al. Standards Track [Page 18]
RFC 3550 RTP July 2003
Note that this header extension is intended only for limited use.
Most potential uses of this mechanism would be better done another
way, using the methods described in the previous section. For
example, a profile-specific extension to the fixed header is less
expensive to process because it is not conditional nor in a variable
location. Additional information required for a particular payload
format SHOULD NOT use this header extension, but SHOULD be carried in
the payload section of the packet.
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| defined by profile | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| header extension |
| .... |
If the X bit in the RTP header is one, a variable-length header
extension MUST be appended to the RTP header, following the CSRC list
if present. The header extension contains a 16-bit length field that
counts the number of 32-bit words in the extension, excluding the
four-octet extension header (therefore zero is a valid length). Only
a single extension can be appended to the RTP data header. To allow
multiple interoperating implementations to each experiment
independently with different header extensions, or to allow a
particular implementation to experiment with more than one type of
header extension, the first 16 bits of the header extension are left
open for distinguishing identifiers or parameters. The format of
these 16 bits is to be defined by the profile specification under
which the implementations are operating. This RTP specification does
not define any header extensions itself.
JRTPLIB暂时只支持RFC3550扩展头识别
RTP头定义
12个字节的报头
struct RTPHeader
{
#ifdef RTP_BIG_ENDIAN
uint8_t version:2;
uint8_t padding:1;
uint8_t extension:1;
uint8_t csrccount:4;
uint8_t marker:1;
uint8_t payloadtype:7;
#else // little endian
uint8_t csrccount:4;
uint8_t extension:1;
uint8_t padding:1;
uint8_t version:2;
uint8_t payloadtype:7;
uint8_t marker:1;
#endif // RTP_BIG_ENDIAN
uint16_t sequencenumber;
uint32_t timestamp;
uint32_t ssrc;
};
RTP扩展头定义
struct RTPExtensionHeader
{
uint16_t extid;
uint16_t length;
};
RTP解析
int RTPPacket::ParseRawPacket(RTPRawPacket &rawpack)
{
uint8_t *packetbytes;
size_t packetlen;
uint8_t payloadtype;
RTPHeader *rtpheader;
bool marker;
int csrccount;
bool hasextension;
int payloadoffset,payloadlength;
int numpadbytes;
RTPExtensionHeader *rtpextheader;
if (!rawpack.IsRTP()) // If we didn't receive it on the RTP port, we'll ignore it
return ERR_RTP_PACKET_INVALIDPACKET;
// The length should be at least the size of the RTP header
packetlen = rawpack.GetDataLength();
if (packetlen < sizeof(RTPHeader))
return ERR_RTP_PACKET_INVALIDPACKET;
packetbytes = (uint8_t *)rawpack.GetData();
rtpheader = (RTPHeader *)packetbytes;
// The version number should be correct
if (rtpheader->version != RTP_VERSION)
return ERR_RTP_PACKET_INVALIDPACKET;
// We'll check if this is possibly a RTCP packet. For this to be possible
// the marker bit and payload type combined should be either an SR or RR
// identifier
//marker为1标志这是分包的最后一个包
marker = (rtpheader->marker == 0)?false:true;
payloadtype = rtpheader->payloadtype;
if (marker)
{
if (payloadtype == (RTP_RTCPTYPE_SR & 127)) // don't check high bit (this was the marker!!)
return ERR_RTP_PACKET_INVALIDPACKET;
if (payloadtype == (RTP_RTCPTYPE_RR & 127))
return ERR_RTP_PACKET_INVALIDPACKET;
}
csrccount = rtpheader->csrccount;
payloadoffset = sizeof(RTPHeader)+(int)(csrccount*sizeof(uint32_t));
if (rtpheader->padding) // adjust payload length to take padding into account
{
numpadbytes = (int)packetbytes[packetlen-1]; // last byte contains number of padding bytes
if (numpadbytes <= 0)
return ERR_RTP_PACKET_INVALIDPACKET;
}
else
numpadbytes = 0;
//判断是否有RTP扩展头
hasextension = (rtpheader->extension == 0)?false:true;
if (hasextension) // got header extension
{
//跳到RTP扩展头指针位置
rtpextheader = (RTPExtensionHeader *)(packetbytes+payloadoffset);
payloadoffset += sizeof(RTPExtensionHeader);
//跳过扩展头的结构体位置偏移,共4个字节
//获取扩展头的长度,实际上就是有多少个32位整型的长度
uint16_t exthdrlen = ntohs(rtpextheader->length);
payloadoffset += ((int)exthdrlen)*sizeof(uint32_t);
}
else
{
rtpextheader = 0;
}
payloadlength = packetlen-numpadbytes-payloadoffset;
if (payloadlength < 0)
return ERR_RTP_PACKET_INVALIDPACKET;
// Now, we've got a valid packet, so we can create a new instance of RTPPacket
// and fill in the members
RTPPacket::hasextension = hasextension;
if (hasextension)
{
RTPPacket::extid = ntohs(rtpextheader->extid);
RTPPacket::extensionlength = ((int)ntohs(rtpextheader->length))*sizeof(uint32_t);
RTPPacket::extension = ((uint8_t *)rtpextheader)+sizeof(RTPExtensionHeader);
}
RTPPacket::hasmarker = marker;
RTPPacket::numcsrcs = csrccount;
RTPPacket::payloadtype = payloadtype;
// Note: we don't fill in the EXTENDED sequence number here, since we
// don't have information about the source here. We just fill in the low
// 16 bits
RTPPacket::extseqnr = (uint32_t)ntohs(rtpheader->sequencenumber);
RTPPacket::timestamp = ntohl(rtpheader->timestamp);
RTPPacket::ssrc = ntohl(rtpheader->ssrc);
RTPPacket::packet = packetbytes;
RTPPacket::payload = packetbytes+payloadoffset;
RTPPacket::packetlength = packetlen;
RTPPacket::payloadlength = payloadlength;
// We'll zero the data of the raw packet, since we're using it here now!
rawpack.ZeroData();
return 0;
}
如下是来自华为NVR的RTP数据包抓包
标签:JRTPLIB,extension,扩展,uint8,header,RTP,RTPPacket,解析 From: https://blog.51cto.com/fengyuzaitu/6004555