stream-deploy/ZLM/3rdpart/media-server/librtp/source/rtp-packet.c

151 lines
3.8 KiB
C++

#include "rtp-packet.h"
#include "rtp-util.h"
#include <string.h>
#include <assert.h>
// RFC3550 RTP: A Transport Protocol for Real-Time Applications
// 5.1 RTP Fixed Header Fields (p12)
/*
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 |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
int rtp_packet_deserialize(struct rtp_packet_t *pkt, const void* data, int bytes)
{
uint32_t i, v;
int hdrlen;
const uint8_t *ptr;
if (bytes < RTP_FIXED_HEADER) // RFC3550 5.1 RTP Fixed Header Fields(p12)
return -1;
ptr = (const unsigned char *)data;
memset(pkt, 0, sizeof(struct rtp_packet_t));
// pkt header
v = nbo_r32(ptr);
pkt->rtp.v = RTP_V(v);
pkt->rtp.p = RTP_P(v);
pkt->rtp.x = RTP_X(v);
pkt->rtp.cc = RTP_CC(v);
pkt->rtp.m = RTP_M(v);
pkt->rtp.pt = RTP_PT(v);
pkt->rtp.seq = RTP_SEQ(v);
pkt->rtp.timestamp = nbo_r32(ptr + 4);
pkt->rtp.ssrc = nbo_r32(ptr + 8);
assert(RTP_VERSION == pkt->rtp.v);
hdrlen = RTP_FIXED_HEADER + pkt->rtp.cc * 4;
if (RTP_VERSION != pkt->rtp.v || bytes < hdrlen + (pkt->rtp.x ? 4 : 0) + (pkt->rtp.p ? 1 : 0))
return -1;
// pkt contributing source
for (i = 0; i < pkt->rtp.cc; i++)
{
pkt->csrc[i] = nbo_r32(ptr + 12 + i * 4);
}
assert(bytes >= hdrlen);
pkt->payload = (uint8_t*)ptr + hdrlen;
pkt->payloadlen = bytes - hdrlen;
// pkt header extension
if (1 == pkt->rtp.x)
{
const uint8_t *rtpext = ptr + hdrlen;
assert(pkt->payloadlen >= 4);
pkt->extension = rtpext + 4;
pkt->extprofile = nbo_r16(rtpext);
pkt->extlen = nbo_r16(rtpext + 2) * 4;
if (pkt->extlen + 4 > pkt->payloadlen)
{
assert(0);
return -1;
}
else
{
pkt->payload = rtpext + pkt->extlen + 4;
pkt->payloadlen -= pkt->extlen + 4;
}
}
// padding
if (1 == pkt->rtp.p)
{
uint8_t padding = ptr[bytes - 1];
if (pkt->payloadlen < padding)
{
assert(0);
return -1;
}
else
{
pkt->payloadlen -= padding;
}
}
return 0;
}
int rtp_packet_serialize_header(const struct rtp_packet_t *pkt, void* data, int bytes)
{
int hdrlen;
uint32_t i;
uint8_t* ptr;
if (RTP_VERSION != pkt->rtp.v || 0 != (pkt->extlen % 4))
{
assert(0); // RTP version field must equal 2 (p66)
return -1;
}
// RFC3550 5.1 RTP Fixed Header Fields(p12)
hdrlen = RTP_FIXED_HEADER + pkt->rtp.cc * 4 + (pkt->rtp.x ? 4 : 0);
if (bytes < hdrlen + pkt->extlen)
return -1;
ptr = (uint8_t *)data;
nbo_write_rtp_header(ptr, &pkt->rtp);
ptr += RTP_FIXED_HEADER;
// pkt contributing source
for (i = 0; i < pkt->rtp.cc; i++, ptr += 4)
{
nbo_w32(ptr, pkt->csrc[i]);
}
// pkt header extension
if (1 == pkt->rtp.x)
{
// 5.3.1 RTP Header Extension
assert(0 == (pkt->extlen % 4));
nbo_w16(ptr, pkt->extprofile);
nbo_w16(ptr + 2, pkt->extlen / 4);
memcpy(ptr + 4, pkt->extension, pkt->extlen);
ptr += pkt->extlen + 4;
}
return hdrlen + pkt->extlen;
}
int rtp_packet_serialize(const struct rtp_packet_t *pkt, void* data, int bytes)
{
int hdrlen;
hdrlen = rtp_packet_serialize_header(pkt, data, bytes);
if (hdrlen < RTP_FIXED_HEADER || hdrlen + pkt->payloadlen > bytes)
return -1;
memcpy(((uint8_t*)data) + hdrlen, pkt->payload, pkt->payloadlen);
return hdrlen + pkt->payloadlen;
}