GB28181 RTP over TCP

有时候需要切换 tcp 接收码流,于是做了这个。使用TCP传输RTP包,GB28181-2016和GB28181-2022 都是按IETF RFC4571来的。使用TCP发送RTP包,前面加个16位无符号长度字段就好(网络字节序)。具体定义格式如下:

GB28181 RTP over TCP

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 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论