live555的rtsp代理ProxyServerMediaSession改进
live555中的ProxyServerMediaSession是一个为后端的网络摄像头或其他设备做rtsp代理的类
实际应用中有几个地方需要注意
1 代理过程中,从第一次客户端连接,proxy就会开始从后端rtsp服务器拉数据,在所有客户端断开连接后,proxy发送rtsp的pause(而不是teardown)命令给后端rtsp服务器,从而继续从后端获取数据,一直占用带宽。
2 live555使用中,需要根据实际情况修改一些值,预防数据包被人为的网络切断(truncation)而发生花屏问题,
例如默认值对中低码率的视频也许正常,遇到1080p的时候就出现问题。
2.1 OutPacketBuffer::maxSize (过小时live555会在运行时有警告提示,帧数据丢失)
2.2 接收和发送的socket 缓冲区大小,可以通过调用 increaseReceiveBufferTo和increaseSendBufferTo接口修改
这里说一下参考的解决方法:
1 解决无客户端连接时不从后端接收流媒体数据:
在ProxyRtspClient添加代码
TaskToken fProxyResetCommandTask; //所有客户端断开后执行 static void ProxyRTSPClient::proxyReset(void* clientData){ ((ProxyRTSPClient*)clientData)->handleProxyReset(); } void ProxyRTSPClient::handleProxyReset(){ continueAfterLivenessCommand(-1,False); envir().taskScheduler().unscheduleDelayedTask(fProxyResetCommandTask); fProxyResetCommandTask = NULL; }
//在proxyRtspClient 构造函数中初始化fProxyResetCommandTask
fProxyResetCommandTask = NULL;
修改ProxyServerMediaSubsession::closeStreamSource(FramedSource* inputSource)函数
void ProxyServerMediaSubsession::closeStreamSource(FramedSource* inputSource) { if (verbosityLevel() > 0) { envir() << *this << "::closeStreamSource()\n"; } // Because there's only one input source for this 'subsession' (regardless of how many downstream clients are proxying it), // we don't close the input source here. (Instead, we wait until *this* object gets deleted.) // However, because (as evidenced by this function having been called) we no longer have any clients accessing the stream, // then we "PAUSE" the downstream proxied stream, until a new client arrives: if (fHaveSetupStream) { ProxyServerMediaSession* const sms = (ProxyServerMediaSession*)fParentSession; ProxyRTSPClient* const proxyRTSPClient = sms->fProxyRTSPClient; if (proxyRTSPClient->fLastCommandWasPLAY) { // so that we send only one "PAUSE"; not one for each subsession //proxyRTSPClient->sendPauseCommand(fClientMediaSubsession.parentSession(), NULL, proxyRTSPClient->auth()); proxyRTSPClient->sendTeardownCommand(fClientMediaSubsession.parentSession(), NULL, proxyRTSPClient->auth()); proxyRTSPClient->fProxyResetCommandTask = envir().taskScheduler().scheduleDelayedTask(0,ProxyRTSPClient::proxyReset,proxyRTSPClient); proxyRTSPClient->fLastCommandWasPLAY = False; } fHaveSetupStream = False; } }
2 设置缓冲大小
2.1 OutPacketBuffer::maxSize 是个静态变量,程序开始便可以设置。(这个就不用多说了吧,大家水平都这么高了)
比如OutPacketBuffer::maxSize = 2000000; 就行
2.2 接收时的socket 缓冲设置,修改ProxyServerMediaSubsession::createNewStreamSource函数,加上蓝色部分
FramedSource* ProxyServerMediaSubsession::createNewStreamSource(unsigned clientSessionId, unsigned& estBitrate) { ProxyServerMediaSession* const sms = (ProxyServerMediaSession*)fParentSession; if (verbosityLevel() > 0) { envir() << *this << "::createNewStreamSource(session id " << clientSessionId << ")\n"; } // If we haven't yet created a data source from our 'media subsession' object, initiate() it to do so: if (fClientMediaSubsession.readSource() == NULL) { fClientMediaSubsession.receiveRawMP3ADUs(); // hack for MPA-ROBUST streams fClientMediaSubsession.receiveRawJPEGFrames(); // hack for proxying JPEG/RTP streams. (Don't do this if we're transcoding.) fClientMediaSubsession.initiate(); <span style="color:#330099;">if(!strcmp(fClientMediaSubsession.mediumName(),"video")) increaseReceiveBufferTo(envir(),fClientMediaSubsession.rtpSource()->RTPgs()->socketNum(),2000000);</span> if (verbosityLevel() > 0) {
void OnDemandServerMediaSubsession ::getStreamParameters(unsigned clientSessionId, netAddressBits clientAddress, Port const& clientRTPPort, Port const& clientRTCPPort, int tcpSocketNum, unsigned char rtpChannelId, unsigned char rtcpChannelId, netAddressBits& destinationAddress, u_int8_t& /*destinationTTL*/, Boolean& isMulticast, Port& serverRTPPort, Port& serverRTCPPort, void*& streamToken) { ... if (rtpGroupsock != NULL) { // Try to use a big send buffer for RTP - at least 0.1 second of // specified bandwidth and at least 50 KB unsigned rtpBufSize = streamBitrate * 25 / 2; // 1 kbps * 0.1 s = 12.5 bytes <span style="color:#000099;">if (rtpBufSize < 50 * 1024) rtpBufSize = 2000 * 1024; //50 * 1024;</span> increaseSendBufferTo(envir(), rtpGroupsock->socketNum(), rtpBufSize); } ... }