141 lines
3.1 KiB
C++
141 lines
3.1 KiB
C++
#include "rtp-over-rtsp.h"
|
|
#include "rtp-header.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
#define VMIN(x, y) ((x) < (y) ? (x) : (y))
|
|
|
|
enum rtp_over_tcp_state_t
|
|
{
|
|
rtp_start = 0,
|
|
rtp_channel,
|
|
rtp_length_1,
|
|
rtp_length_2,
|
|
rtp_data,
|
|
};
|
|
|
|
static int rtp_alloc(struct rtp_over_rtsp_t *rtp)
|
|
{
|
|
void* p;
|
|
if (rtp->capacity < rtp->length)
|
|
{
|
|
p = realloc(rtp->data, rtp->length);
|
|
if (!p)
|
|
return -1;
|
|
rtp->data = (uint8_t*)p;
|
|
rtp->capacity = rtp->length;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#if defined(RTP_OVER_RTSP_TRY_TO_FIND_NEXT_PACKET)
|
|
// skip missing data, find next start
|
|
static const uint8_t* rtp_over_rtsp_try_to_find_next_packet(struct rtp_over_rtsp_t* rtp, const uint8_t* data, const uint8_t* end)
|
|
{
|
|
const uint8_t* p;
|
|
p = (const uint8_t*)memchr(data, '$', end - data);
|
|
if (!p)
|
|
return end; // not found
|
|
|
|
rtp->check = 1;
|
|
return p;
|
|
}
|
|
#endif
|
|
|
|
// 10.12 Embedded (Interleaved) Binary Data
|
|
// Stream data such as RTP packets is encapsulated by an ASCII dollar sign(24 hexadecimal),
|
|
// followed by a one-byte channel identifier,
|
|
// followed by the length of the encapsulated binary data as a binary two-byte integer in network byte order.
|
|
const uint8_t* rtp_over_rtsp(struct rtp_over_rtsp_t *rtp, const uint8_t* data, const uint8_t* end)
|
|
{
|
|
int n;
|
|
|
|
for (n = 0; data < end; data++)
|
|
{
|
|
switch (rtp->state)
|
|
{
|
|
case rtp_start:
|
|
if (*data != '$') {
|
|
#if defined(RTP_OVER_RTSP_TRY_TO_FIND_NEXT_PACKET)
|
|
return rtp_over_rtsp_try_to_find_next_packet(rtp, data, end);
|
|
#else
|
|
return end;
|
|
#endif
|
|
}
|
|
rtp->bytes = 0;
|
|
rtp->state = rtp_channel;
|
|
break;
|
|
|
|
case rtp_channel:
|
|
// The channel identifier is defined in the Transport header with
|
|
// the interleaved parameter(Section 12.39).
|
|
rtp->channel = *data;
|
|
rtp->state = rtp_length_1;
|
|
break;
|
|
|
|
case rtp_length_1:
|
|
rtp->length = *data << 8;
|
|
rtp->state = rtp_length_2;
|
|
break;
|
|
|
|
case rtp_length_2:
|
|
rtp->length |= *data;
|
|
rtp->state = rtp_data;
|
|
break;
|
|
|
|
case rtp_data:
|
|
if (0 == rtp->bytes && 0 != rtp_alloc(rtp))
|
|
return end;
|
|
n = (int)(end - data);
|
|
n = VMIN(rtp->length - rtp->bytes, n);
|
|
memcpy(rtp->data + rtp->bytes, data, n);
|
|
rtp->bytes += (uint16_t)n;
|
|
|
|
#if defined(RTP_OVER_RTSP_TRY_TO_FIND_NEXT_PACKET)
|
|
if (rtp->bytes >= 12)
|
|
{
|
|
uint32_t ssrc;
|
|
ssrc = *(uint32_t*)(rtp->data + 8);
|
|
|
|
if (rtp->check)
|
|
{
|
|
if (rtp->channel >= sizeof(rtp->ssrc) / sizeof(rtp->ssrc[0])
|
|
|| ssrc != rtp->ssrc[rtp->channel]
|
|
|| RTP_VERSION != (*rtp->data >> 6))
|
|
{
|
|
rtp->state = rtp_start;
|
|
return rtp_over_rtsp_try_to_find_next_packet(rtp, data, end);
|
|
}
|
|
|
|
rtp->check = 0;
|
|
}
|
|
else if(rtp->channel < sizeof(rtp->ssrc) / sizeof(rtp->ssrc[0]) && 0 == rtp->ssrc[rtp->channel])
|
|
{
|
|
assert(RTP_VERSION == (*rtp->data >> 6));
|
|
//assert(0 == rtp->ssrc[rtp->channel] || ssrc == rtp->ssrc[rtp->channel]);
|
|
rtp->ssrc[rtp->channel] = ssrc;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
data += n;
|
|
|
|
if (rtp->bytes == rtp->length)
|
|
{
|
|
rtp->state = rtp_start;
|
|
if(rtp->onrtp)
|
|
rtp->onrtp(rtp->param, rtp->channel, rtp->data, rtp->length);
|
|
return data;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
assert(0);
|
|
return end;
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|