RTSP over TCP RTP数据接收和RTSP命令响应数据接收混乱问题求救!

randommmm 2014-01-25 02:55:51
各位大神好:
我在做RTSP over TCP 时,RTP/AVP/TCP;unicast;interleaved=0-1
接收RTP和RTCP数据的时候结构体
strucr InterLeaved
{
BYTE flag;
BYTE type;
unsigned char len;
}

InterLeaved.flag == 0x24 && InterLeaved.type == 0 ----RTP
InterLeaved.flag == 0x24 && InterLeaved.type == 1 ----RTCP

RTSP over TCP 所有数据和命令都是通过一个 socket 来发送和接收的。那如果我现在需要发送一个 RTSP 命令,服务端响应该命令返回的数据应该怎么接收?
我现在遇到的问题是收到的 InterLeaved.flag == 0x24 是正确的,但是InterLeaved.type就五花八门了,而且InterLeaved.len也不对,这个要怎么解决?求大神指教,万分感谢!
...全文
1420 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
jyh420124 2014-09-25
  • 打赏
  • 举报
回复
void CRtspClient::OnRtpOnTcpAV( int nErrorCode ) { char *rbuf = new char[MAX_RECV_LEN]; int rpos = 0; memset(rbuf,0,MAX_RECV_LEN); char* m_pbody=0; int m_nbody=0; UINT lasttime=GetTickCount(); UINT timecnt=0; while(m_hSocket != INVALID_SOCKET) try { timecnt++; if((timecnt%5)==0) { int diff = GetTickCount()-lasttime; if (diff > (MAX_RTP_TIMEOUT*1000)) { onRtpRecvTimeOutErr(); } if (diff > (25*1000)) //55 s timeout { sendoutKEEPLIVE(); } } if(rpos >= MAX_RECV_LEN) { TRACE("缓冲满\n"); Close(); onRecvBufOver(); goto EXIT_CLEAN; break; } struct timeval tv; tv.tv_sec=1; tv.tv_usec=0; fd_set set; FD_ZERO(&set); FD_SET(m_hSocket,&set); //TRACE("等待接收\n"); int aret = select((int)m_hSocket+1,&set,NULL,NULL,&tv); if(aret < 1){Sleep(1);continue;} if(!FD_ISSET(m_hSocket,&set)){Sleep(1);continue;} #if 1 //TRACE("有数据\n"); int rn = this->Receive(rbuf+rpos,MAX_RECV_LEN-rpos); if(rn<=0){ int err = WSAGetLastError(); TRACE(">>> net err = %d, rn = %d\n", err,rn); Close(); if(rn==0)onPeerClose(); else onRecvErr(); goto EXIT_CLEAN; break; } lasttime=GetTickCount(); rpos += rn; if(rpos<MAX_RECV_LEN) rbuf[rpos]='\0'; else rbuf[MAX_RECV_LEN-1]='\0'; NEXT_RECV_AV: if(memcmp(rbuf,"RTSP/1.",7)==0) //rtsp response : PLAY PAUSE TEARDOWN { TRACE("信令\n"); char *ptr = strstr(rbuf,"\r\n\r\n"); if(!ptr)continue; ptr += 4; CString m_header; char t0 = *ptr; *ptr = '\0'; m_header = rbuf; *ptr = t0; int bodylen = getBodyLen(m_header); if(rpos < (bodylen+(ptr-rbuf))) continue; if(bodylen>0) { if(m_pbody)delete[] m_pbody; m_pbody=NULL; try { m_pbody = new char[bodylen+4]; } catch(...){ } if(m_pbody) { memset(m_pbody,0,bodylen+4); memcpy(m_pbody,ptr,bodylen); m_nbody=bodylen; } } int k = (bodylen+(ptr-rbuf)); memmove(rbuf,rbuf+k,rpos-k); rpos -= k; rbuf[rpos]='\0'; //显示输出接收到的信息 try { if(m_bWLog) { OutLogText((LPCTSTR)m_header); if(bodylen>0)OutLogText(m_pbody); } #ifdef _DEBUG TRACE("\n%s\n", (LPCTSTR)m_header); if(bodylen>0) { int i, bn = bodylen/500; //TRACE限制显示的string不超过512-1 int bm = bodylen%500; char tmp[512]={0}; for (i=0; i<bn; i++) { memcpy(tmp, m_pbody+i*500, 500); tmp[500]='\0'; TRACE("%s\n", (LPCTSTR)tmp); } if(bm>0) { memcpy(tmp, m_pbody+bn*500, bm); tmp[bm]='\0'; TRACE("%s\n", (LPCTSTR)tmp); } } #endif //_DEBUG } catch(...) {} goto NEXT_RECV_AV; } else if((rbuf[0]==0x24) && (((BYTE)(rbuf[4])&0xc0)==0x80)) //rtp on tcp { //TRACE("%d RTP ON TCP\n",rpos); int chan = (BYTE)rbuf[1]; int num = ((BYTE)rbuf[2]<<8)|(BYTE)rbuf[3]; if(rpos < (4+num))continue; if (num > 0) m_recvRtpSize += num; BYTE* rtp = (BYTE*)rbuf+4; if(rtp[0]==0x80) { workstate=1; if((rtp[1]&0x7f)==vcode) //0x60) { this->tv.put(rtp,num,300); //onRtpDataVideo(rtp,num); } else if((rtp[1]&0x7f)==acode) //0x60) { onRtpDataAudio(rtp,num); } } int tpos = 4+num; if(rpos>tpos)memmove(rbuf,rbuf+tpos,rpos-tpos); rpos -= tpos; rbuf[rpos] = '\0'; goto NEXT_RECV_AV; } else //find sync rtp header { //TRACE("%d SYNC\n",rpos); int tpos = -1; for (int i=0; i<rpos-5; i++) { if((rbuf[i]==0x24) && (((BYTE)(rbuf[i+4])&0xc0)==0x80)) //rtp on tcp { tpos=i; break; } } if(tpos != -1) { if(rpos>tpos)memmove(rbuf,rbuf+tpos,rpos-tpos); rpos -= tpos; rbuf[rpos] = '\0'; goto NEXT_RECV_AV; } continue; } #else BYTE h[4]={0,0,0,0}; int r = this->ForceReceive(h,4); if(r!=4)return; if(h[0]!=0x24) return; //if(h[1]!=0)return; int n = (h[2]<<8)|h[3]; BYTE buf[4096]; r = this->ForceReceive(buf,n); if(r != n)return; if(buf[0]==0x80) if((buf[1]&0x7f)==vcode) //0x60) { this->tv.put(buf,n,300); //onRtpDataVideo(buf,n); } #endif } catch(...){} EXIT_CLEAN: if(rbuf)delete[] rbuf; rbuf=0; rpos=0; if(m_pbody)delete[] m_pbody; m_pbody=0; m_nbody=0; }
jyh420124 2014-09-25
  • 打赏
  • 举报
回复
大多答非所问。在接收的数据中找$,找到就按RTP/RTCP处理;又找“RTSP/1.”,如找到就再找\r\n\r\n; 如果数据乱了失去同步,就找下一个$
randommmm 2014-02-24
  • 打赏
  • 举报
回复
感谢各位大侠的回复,特别感谢 lyuan1314
钱国正 2014-02-12
  • 打赏
  • 举报
回复
引用 9 楼 randong1988 的回复:
[quote=引用 8 楼 qianguozheng 的回复:] [quote=引用 7 楼 randong1988 的回复:] [quote=引用 6 楼 qianguozheng 的回复:] [quote=引用 5 楼 Worcy_kiddy 的回复:] 这个有什么干扰吗?RTSP协议是一个应用层交互协议,端口号是554或8554,比如Client发送Setup,服务端会回复RTSP/1.0 200 OK。而RTP是流媒体传输协议,RTCP是控制协议,这两个协议的端口号本就不一样!
我想楼主是RTP over RTSP over TCP, 其中RTP和RTSP共用同一个连接,即同一个端口,传输RTSP数据和RTP数据,同时想保持同步RTSP keep alive,楼主我理解的可正确否?[/quote] 对,就是这个意思,RTP和RTSP共用同一个连接,现在这个链接已经在开始传输RTP数据了,现在我又想通过这个链接连来发送OPTION,发送倒是没问题,但是server给我响应的 200 OK 会与RTP数据造成混乱,不知道各位大神是怎么处理的,指点一下小弟,非常感谢![/quote] RTP数据会和 200 OK 混乱? 你有抓包嘛?可以发过来看看,这个东西我们camera里支持这种方式,你需要care 回复干嘛?[/quote] 大侠您好! 抓包应该看不出什么问题,我的代码是这样的,要不您帮忙看看? InterleavedFrame定义: struct InterleavedFrame { BYTE flag; BYTE type; unsigned short len; }; SETUP 的时候设置: sprintf(m_szVideoTrancePort, "RTP/AVP/TCP;unicast;interleaved=%d-%d", m_nVideoDatachannel, m_nVideoCtrolchannel); sprintf(m_szAudioTrancePort, "RTP/AVP/TCP;unicast;interleaved=%d-%d", m_nAudioDatachannel, m_nAudioCtrolchannel); 接收数据: int nNeedRecvLen = 0; nNeedRecvLen = m_nInterleavLen;//先收4个字节的RTP_TCP_HEADER nRecvedLen = TcpRecvData((char*)&m_sInterleavedFrame, nNeedRecvLen); if (nRecvedLen < nNeedRecvLen || m_sInterleavedFrame.flag != 0x24)//cheack head { //recv error! return -1; } nNeedRecvLen = ntohs(m_sInterleavedFrame.len); if (m_nVideoDatachannel == m_sInterleavedFrame.type || m_nAudioDatachannel == m_sInterleavedFrame.type)//rtp data { nRecvedLen = TcpRecvData(recvBuf, nNeedRecvLen); if (nRecvedLen < nNeedRecvLen) { //recv error! return -1; } } else if (m_nVideoCtrolchannel == m_sInterleavedFrame.type || m_nAudioCtrolchannel == m_sInterleavedFrame.type)//rtcp data { nNeedRecvLen = ntohs(m_sInterleavedFrame.len); nRecvedLen = TcpRecvData(rtcpBuf, nNeedRecvLen); if (nRecvedLen < nNeedRecvLen) { //recv error! return -1; } } else { //error data return -1; } 首先说明一下,我RTSP OVER TCP 时只有一个socket,连接服务器554,发送RTSP命令,接收RTSP命令响应,还有接收RTP都是这一个socket。RTSP命令请求完成后就开始接收RTP数据,只有TcpRecvData这里在从服务端收数据,那么在接收RTP数据过程中如果我发了RTSP命令,返回的 “200 OK” 肯定也是从TcpRecvData这里收过来的,RTP也是从这里收的,所以产生了混乱。现在我遇到的情况是如果我发了RTSP命令那么收到的m_sInterleavedFrame.type。m_sInterleavedFrame.flag != 0x24 这个是对的,但是m_sInterleavedFrame.type不对,出现很多种值,ntohs(m_sInterleavedFrame.len);也很大。如果我不发RTSP命令就正常。[/quote] 针对你这种情况我想问问,服务器是怎么接收你客户端的RTSP命令的,可以参照其代码搞搞啊
EagleAIGC 2014-02-10
  • 打赏
  • 举报
回复
如果不是$开头的,那就是RTSP命令的Response,直接接收就行了。一般接收RTSP命令的Response是一个字节一个字节接收的。根据RTSP的消息格式来判断什么时候结束,“\r\n”。
randommmm 2014-02-10
  • 打赏
  • 举报
回复
引用 11 楼 lyuan1314 的回复:
如果第一个字节是$,就是RTP或者RTCP的数据。然后根据第二个字节来判断是RTP还是RTCP,这个字节与分配的socket有关。 所以,需要对接收到的数据作判断。 至于是音频数据还是视频数据,那就需要解析RTP包了。
大侠,您好! 您说的这个我都没问题的,我能正确解析出RTP包和RTCP包,问题是在接收数据过程中如果我向服务端发送 RTSP 命令,然后服务端给我返回的 200 OK,这个数据要怎么收,怎么解析?您说的 rfc2326 10.12我也看了的,只说了RTP 和 RTCP 交叉的问题啊,没说明RTSP命令的交叉问题额。不知道您能明白我的意思不?
EagleAIGC 2014-02-10
  • 打赏
  • 举报
回复
如果第一个字节是$,就是RTP或者RTCP的数据。然后根据第二个字节来判断是RTP还是RTCP,这个字节与分配的socket有关。 所以,需要对接收到的数据作判断。 至于是音频数据还是视频数据,那就需要解析RTP包了。
EagleAIGC 2014-02-10
  • 打赏
  • 举报
回复
你可以参看一下RFC2326的10.12那一节,Embedded (Interleaved) Binary Data。 使用TCP传输数据,RTSP、RTP和RTCP都使用同一个端口。媒体数据作为RTSP的Response传输到Client。 希望能帮到你。
randommmm 2014-02-09
  • 打赏
  • 举报
回复
引用 8 楼 qianguozheng 的回复:
[quote=引用 7 楼 randong1988 的回复:] [quote=引用 6 楼 qianguozheng 的回复:] [quote=引用 5 楼 Worcy_kiddy 的回复:] 这个有什么干扰吗?RTSP协议是一个应用层交互协议,端口号是554或8554,比如Client发送Setup,服务端会回复RTSP/1.0 200 OK。而RTP是流媒体传输协议,RTCP是控制协议,这两个协议的端口号本就不一样!
我想楼主是RTP over RTSP over TCP, 其中RTP和RTSP共用同一个连接,即同一个端口,传输RTSP数据和RTP数据,同时想保持同步RTSP keep alive,楼主我理解的可正确否?[/quote] 对,就是这个意思,RTP和RTSP共用同一个连接,现在这个链接已经在开始传输RTP数据了,现在我又想通过这个链接连来发送OPTION,发送倒是没问题,但是server给我响应的 200 OK 会与RTP数据造成混乱,不知道各位大神是怎么处理的,指点一下小弟,非常感谢![/quote] RTP数据会和 200 OK 混乱? 你有抓包嘛?可以发过来看看,这个东西我们camera里支持这种方式,你需要care 回复干嘛?[/quote] 大侠您好! 抓包应该看不出什么问题,我的代码是这样的,要不您帮忙看看? InterleavedFrame定义: struct InterleavedFrame { BYTE flag; BYTE type; unsigned short len; }; SETUP 的时候设置: sprintf(m_szVideoTrancePort, "RTP/AVP/TCP;unicast;interleaved=%d-%d", m_nVideoDatachannel, m_nVideoCtrolchannel); sprintf(m_szAudioTrancePort, "RTP/AVP/TCP;unicast;interleaved=%d-%d", m_nAudioDatachannel, m_nAudioCtrolchannel); 接收数据: int nNeedRecvLen = 0; nNeedRecvLen = m_nInterleavLen;//先收4个字节的RTP_TCP_HEADER nRecvedLen = TcpRecvData((char*)&m_sInterleavedFrame, nNeedRecvLen); if (nRecvedLen < nNeedRecvLen || m_sInterleavedFrame.flag != 0x24)//cheack head { //recv error! return -1; } nNeedRecvLen = ntohs(m_sInterleavedFrame.len); if (m_nVideoDatachannel == m_sInterleavedFrame.type || m_nAudioDatachannel == m_sInterleavedFrame.type)//rtp data { nRecvedLen = TcpRecvData(recvBuf, nNeedRecvLen); if (nRecvedLen < nNeedRecvLen) { //recv error! return -1; } } else if (m_nVideoCtrolchannel == m_sInterleavedFrame.type || m_nAudioCtrolchannel == m_sInterleavedFrame.type)//rtcp data { nNeedRecvLen = ntohs(m_sInterleavedFrame.len); nRecvedLen = TcpRecvData(rtcpBuf, nNeedRecvLen); if (nRecvedLen < nNeedRecvLen) { //recv error! return -1; } } else { //error data return -1; } 首先说明一下,我RTSP OVER TCP 时只有一个socket,连接服务器554,发送RTSP命令,接收RTSP命令响应,还有接收RTP都是这一个socket。RTSP命令请求完成后就开始接收RTP数据,只有TcpRecvData这里在从服务端收数据,那么在接收RTP数据过程中如果我发了RTSP命令,返回的 “200 OK” 肯定也是从TcpRecvData这里收过来的,RTP也是从这里收的,所以产生了混乱。现在我遇到的情况是如果我发了RTSP命令那么收到的m_sInterleavedFrame.type。m_sInterleavedFrame.flag != 0x24 这个是对的,但是m_sInterleavedFrame.type不对,出现很多种值,ntohs(m_sInterleavedFrame.len);也很大。如果我不发RTSP命令就正常。
钱国正 2014-02-08
  • 打赏
  • 举报
回复
引用 7 楼 randong1988 的回复:
[quote=引用 6 楼 qianguozheng 的回复:] [quote=引用 5 楼 Worcy_kiddy 的回复:] 这个有什么干扰吗?RTSP协议是一个应用层交互协议,端口号是554或8554,比如Client发送Setup,服务端会回复RTSP/1.0 200 OK。而RTP是流媒体传输协议,RTCP是控制协议,这两个协议的端口号本就不一样!
我想楼主是RTP over RTSP over TCP, 其中RTP和RTSP共用同一个连接,即同一个端口,传输RTSP数据和RTP数据,同时想保持同步RTSP keep alive,楼主我理解的可正确否?[/quote] 对,就是这个意思,RTP和RTSP共用同一个连接,现在这个链接已经在开始传输RTP数据了,现在我又想通过这个链接连来发送OPTION,发送倒是没问题,但是server给我响应的 200 OK 会与RTP数据造成混乱,不知道各位大神是怎么处理的,指点一下小弟,非常感谢![/quote] RTP数据会和 200 OK 混乱? 你有抓包嘛?可以发过来看看,这个东西我们camera里支持这种方式,你需要care 回复干嘛?
randommmm 2014-02-08
  • 打赏
  • 举报
回复
引用 6 楼 qianguozheng 的回复:
[quote=引用 5 楼 Worcy_kiddy 的回复:] 这个有什么干扰吗?RTSP协议是一个应用层交互协议,端口号是554或8554,比如Client发送Setup,服务端会回复RTSP/1.0 200 OK。而RTP是流媒体传输协议,RTCP是控制协议,这两个协议的端口号本就不一样!
我想楼主是RTP over RTSP over TCP, 其中RTP和RTSP共用同一个连接,即同一个端口,传输RTSP数据和RTP数据,同时想保持同步RTSP keep alive,楼主我理解的可正确否?[/quote] 对,就是这个意思,RTP和RTSP共用同一个连接,现在这个链接已经在开始传输RTP数据了,现在我又想通过这个链接连来发送OPTION,发送倒是没问题,但是server给我响应的 200 OK 会与RTP数据造成混乱,不知道各位大神是怎么处理的,指点一下小弟,非常感谢!
钱国正 2014-02-07
  • 打赏
  • 举报
回复
引用 5 楼 Worcy_kiddy 的回复:
这个有什么干扰吗?RTSP协议是一个应用层交互协议,端口号是554或8554,比如Client发送Setup,服务端会回复RTSP/1.0 200 OK。而RTP是流媒体传输协议,RTCP是控制协议,这两个协议的端口号本就不一样!
我想楼主是RTP over RTSP over TCP, 其中RTP和RTSP共用同一个连接,即同一个端口,传输RTSP数据和RTP数据,同时想保持同步RTSP keep alive,楼主我理解的可正确否?
黑泡泡选手 2014-01-27
  • 打赏
  • 举报
回复
这个有什么干扰吗?RTSP协议是一个应用层交互协议,端口号是554或8554,比如Client发送Setup,服务端会回复RTSP/1.0 200 OK。而RTP是流媒体传输协议,RTCP是控制协议,这两个协议的端口号本就不一样!
CyberLogix 2014-01-26
  • 打赏
  • 举报
回复
引用 2 楼 randong1988 的回复:
您好!我在接收RTP和RTCP数据都没有问题,视频也能正常播放,问题是我在RTCP和RTP数据接收过程中,如何同时接收 RTSP 命令的响应包,就是 RTSP/1.0 200 OK 这个东西,谢谢!
协议中石油相关命令来标示的啊,RTSP命令的格式是已经定义的,具体请参考RTSP协议规范
randommmm 2014-01-25
  • 打赏
  • 举报
回复
您好!我在接收RTP和RTCP数据都没有问题,视频也能正常播放,问题是我在RTCP和RTP数据接收过程中,如何同时接收 RTSP 命令的响应包,就是 RTSP/1.0 200 OK 这个东西,谢谢!
rightorwrong 2014-01-25
  • 打赏
  • 举报
回复
可以看live555 tcp时是﹩(1字节)+2字节+长度(2字节)+rtp数据 依稀记得是这样

2,547

社区成员

发帖
与我相关
我的任务
社区描述
专题开发/技术/项目 多媒体/流媒体开发
社区管理员
  • 多媒体/流媒体开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧