协议回顾
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)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓