有时候需要切换 tcp 接收码流,于是做了这个。使用TCP传输RTP包,GB28181-2016和GB28181-2022 都是按IETF RFC4571来的。使用TCP发送RTP包,前面加个16位无符号长度字段就好(网络字节序)。具体定义格式如下:
![GB28181 RTP over TCP](https://www.nxrte.com/wp-content/themes/justnews/themer/assets/images/lazy.png)
SDP也要做相应调整.
媒体行为定义如下(m=):
"m=" media SP port ["/" integer] SP proto 1*(SP fmt) CRLF
其中<proto>值为:"TCP/RTP/AVP"
rtp-dump.h
#ifndef _rtp_dump_h_
#define _rtp_dump_h_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
struct rtpdump_t;
typedef void (*rtpdump_callback)(void* param, const void* data, size_t bytes);
struct rtpdump_t* rtpdump_create(rtpdump_callback cb, intptr_t context);
int rtpdump_close(struct rtpdump_t* dump);
int rtpdump_write(struct rtpdump_t* dump, const void* data, size_t bytes);
int rtpdump_read(struct rtpdump_t* dump);
#ifdef __cplusplus
}
#endif
#endif /* !_rtp_dump_h_ */
rtp-dump.c
#include "rtp-dump.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
struct rtpdump_t
{
uint8_t* ptr;
uint32_t capacity;
uint32_t datalen;
uint32_t rtplen;
rtpdump_callback cb;
intptr_t context;
};
static int packet_check_and_alloc(struct rtpdump_t* dump, size_t bytes)
{
if (dump->capacity - dump->datalen < bytes)
{
void* p = realloc(dump->ptr, bytes + dump->datalen);
if (p == NULL)
return -1;
dump->ptr = (uint8_t*)p;
dump->capacity = bytes + dump->datalen;
}
return 0;
}
struct rtpdump_t* rtpdump_create(rtpdump_callback cb, intptr_t context)
{
struct rtpdump_t* dump = (struct rtpdump_t*)calloc(1, sizeof(struct rtpdump_t));
if (dump == NULL)
{
return NULL; // Memory allocation failed
}
dump->cb = cb;
dump->context = context;
return dump;
}
int rtpdump_close(struct rtpdump_t* dump)
{
if (dump == NULL)
return -1; // Invalid input
if (dump->ptr != NULL)
{
free(dump->ptr);
dump->ptr = NULL;
}
free(dump);
return 0;
}
// Write data to the RTP dump object
int rtpdump_write(struct rtpdump_t* dump, const void* data, size_t bytes) {
if (dump == NULL || data == NULL || bytes == 0) {
return -1; // Invalid input
}
size_t data_offset = 0;
// Process incoming data in chunks
while (data_offset < bytes) {
// If there's no RTP length known and enough data is available, read the length
if (dump->rtplen == 0 && dump->datalen >= 2) {
dump->rtplen = (dump->ptr[0] << 8) | dump->ptr[1];
}
if (dump->rtplen > 0) {
// Calculate the necessary bytes to complete the RTP packet
size_t bytes_needed = dump->rtplen + 2 - dump->datalen;
size_t bytes_to_copy = (bytes - data_offset) < bytes_needed ? (bytes - data_offset) : bytes_needed;
// Ensure there is enough memory
if (packet_check_and_alloc(dump, bytes_to_copy) != 0) {
return -1; // Memory reallocation failed
}
// Copy data
memcpy(dump->ptr + dump->datalen, (const uint8_t*)data + data_offset, bytes_to_copy);
dump->datalen += bytes_to_copy;
data_offset += bytes_to_copy;
// If the whole RTP packet is now received
if (dump->datalen == dump->rtplen + 2) {
// Callback for the RTP packet, skip the TCP header (2 bytes)
if (dump->cb) {
dump->cb(dump->context, dump->ptr + 2, dump->rtplen);
}
// Reset buffer for the next packet
dump->datalen = 0;
dump->rtplen = 0;
}
}
else {
// Not enough data for RTP length yet, handle partial header
size_t header_bytes = (bytes - data_offset) > (2 - dump->datalen) ? (2 - dump->datalen) : (bytes - data_offset);
// Ensure there is enough memory
if (packet_check_and_alloc(dump, header_bytes) != 0) {
return -1; // Memory reallocation failed
}
// Copy header data
memcpy(dump->ptr + dump->datalen, (const uint8_t*)data + data_offset, header_bytes);
dump->datalen += header_bytes;
data_offset += header_bytes;
// Read the RTP length if header is complete
if (dump->datalen >= 2) {
dump->rtplen = (dump->ptr[0] << 8) | dump->ptr[1];
}
}
}
return 0;
}
static int ice_onrecv(void* ptr, int code, const void* data, size_t bytes) {
struct i_transport_t* avt = (struct i_transport_t*)ptr;
if (avt->dump)
rtpdump_write(avt->dump, data, bytes);
return 0;
}
srs的tcp发送
// 一次性发送一帧的rtp数据,提高网络io性能
if (tuple->getSock()->sockType() == SockNum::Sock_TCP) {
// 增加tcp两字节头
auto len = buf->size();
char tcp_len[2] = { 0 };
tcp_len[0] = (len >> 8) & 0xff;
tcp_len[1] = len & 0xff;
tuple->SockSender::send(tcp_len, 2);
}
作者: Aliveyun
版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。