RTSP服务器:RTP over TCP

协议回顾

RTP协议负责实际数据的传输。通常使用UDP来传送数据,但RTP也可以在TCP或ATM等其他协议之上工作。

基于UDP的RTP和基于TCP的RTP各有千秋。如果需要低延时,可容忍部分数据丢失,选用UDP;如果需要可靠性高,对实时性要求不高,选用TCP。这里只简单地说明两者的优缺点,在具体项目中需要考虑的细节可能远不止上面几点。

RTP/AVP & RTP/AVP/TCP

RTSP流(传输RTP包)的传输方式有两种:RTP/AVP/UDP(即RTP/AVP)和 RTP/AVP/TCP。

1)采用那种方式传输是由客户端决定的

VLC客户端中设置RTP over TCP:

工具->偏好设置->输入/编解码器->RTP over RTSP(TCP)

2)客户端在RTSP的SETUP命令中需要明确使用TCP传输还是使用UDP传输

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

① RTP/AVP

---------------C->S--------------
SETUP rtsp://192.168.1.168:1935/live/track1 RTSP/1.0
CSeq: 5
Transport: RTP/AVP;unicast;client_port=51950-51951
Session: 00148940

---------------S->C--------------
RTSP/1.0 200 OK
CSeq: 5
Transport: RTP/AVP;unicast;client_port=51950-51951;server_port=12344-12345
Session: 00148940

② RTP/AVP/TCP

---------------C->S--------------178
SETUP rtsp://192.168.174.3:1935/live/track0 RTSP/1.0
CSeq: 4
User-Agent: LibVLC/3.0.14 (LIVE555 Streaming Media v2016.11.28)
Transport: RTP/AVP/TCP;unicast;interleaved=0-1

---------------S->C--------------
RTSP/1.0 200 OK
CSeq: 4
Transport: RTP/AVP/TCP;unicast;interleaved=0-1
Session: 66334873

3)RTP over TCP,不需要额外的RTP端口和RTCP端口,直接使用原先RTSP与VLC连接的TCP socket传输数据。

因为RTSP、RTP、RTCP都使用同一个socket通道,所以我们需要对不同协议的封包进行区分。在RTP层上添加一层,叫做rtsp interleaved frame层。

struct rtp_packet {
    uint8_t interleaved[4]; 	// interleaved层     
    struct rtp_header header;   // 12 Bytes
    uint8_t payload[0];         // 柔性数组
};

interleaved层(4字节)

第一个字节为'$',用于区分RTP/RTCP包和RTSP包;

第二个字节为channel,用于区分RTP包和RTCP包

interleaved=rtp_channel-rtcp_channel

interleaved=0-1,表示视频流;

interleaved=2-3,表示音频流;

rtp_channel一般为偶数,rtcp_channel一般为奇数。

第三字节和第四字节表示RTP层(rtp_header+rtp_payload)的长度。

完整代码就不贴出来了,大概展示几点与RTP/AVP不同的地方。

① rtp_send_packet

int rtp_send_packet(int sockfd, uint8_t rtpchannel, struct rtp_packet *packet, int datalen) {
    packet->prev[0] = '$';  // 与rtsp区分
    packet->prev[1] = rtpchannel;    // 区分rtp和rtcp。0-1
    packet->prev[2] = ((datalen+RTP_HEADER_SIZE) & 0xff00)>>8;
    packet->prev[3] = (datalen+RTP_HEADER_SIZE) & 0xff;

    packet->header.seq = htons(packet->header.seq); 
    packet->header.timestamp = htonl(packet->header.timestamp);
    packet->header.ssrc = htonl(packet->header.ssrc);
    
    int ret = send(sockfd, (void *)packet, 4+RTP_HEADER_SIZE+datalen, 0);

    packet->header.seq = ntohs(packet->header.seq); 
    packet->header.timestamp = ntohl(packet->header.timestamp);
    packet->header.ssrc = ntohl(packet->header.ssrc);
    return ret;
}

②解析SETUP请求

if (!strcmp(method, "SETUP")) {
	while(1) {
		bufPtr = getLineFromBuf(bufPtr, line);
		if (!strncmp(line, "Transport:", strlen("Transport:"))) {
			sscanf(line, "Transport: RTP/AVP/TCP;unicast;interleaved:%hhu-%hhu\r\n",
					&rtp_channel, &rtcp_channel);
			break;
		}
	}
}

③ rtp_play_h264

/* 
 * @func : RTP打包传输H264码流
 * @param: 
 *      sockfd --- TCP socket 
 *      path   --- H264 file 
 */
int rtp_play_h264(int sockfd, uint8_t rtpchannel, const char *path);

如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论! 

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

猜你喜欢

转载自blog.csdn.net/m0_60259116/article/details/127447449
今日推荐