使用live555客户端源码拉rtsp流遇到两个问题,正常测试拉取海康摄像头没问题;

1.拉有些厂商的rtsp流会间隔一段时间断开连接;

2.与大华摄像头建立连接时,发送DESCRIBE命令后很长时间服务器端才返回;

问题一:

问题描述:rtsp流间隔一段时间后总是中断,因为有断开重连机制,所以画面一直是卡住,然后正常播放一段时间,这样循环。

原因描述:由于没有与服务器端建立心跳导致;有些服务器会检测心跳,有的不会,当检测心跳时长时间超过一定值后,服务器端会断开连接; 

解决方法:定期发送心跳GET_PARAMETER;

代码:

TaskToken	m_HeartBeatCommandTask;
Boolean bsupportGetParamter = False;

RTSPClient * XXXX::StartRTSPClient(char const * rtspURL)
{
	RTSPClient * pRtspClient = NULL;

	pRtspClient = myRTSPClient::createNew(*env, rtspURL, 1, NULL);

	if (pRtspClient)
	{
		pRtspClient->sendOptionsCommand(continueAfterOption);
	}

	return pRtspClient;
}

int XXXX::StopRTSPClient(RTSPClient * rtspClient)
{
	bsupportGetParamter = False;
	env->taskScheduler().unscheduleDelayedTask(m_HeartBeatCommandTask);
	m_HeartBeatCommandTask = NULL;

	return 0;
}

void XXXX::continueAfterOption()
{
	/*...............*/

	bsupportGetParamter = RTSPOptionIsSupported("GET_PARAMETER", "");
	sendDescribeCommand(continueAfterDESCRIBE);

	/*...............*/
}

void XXXX::continueAfterDESCRIBE(RTSPClient* rtspClient)
{
	/*...............*/

	setupNextSubsession(rtspClient);

	/*...............*/
}

void XXXX::setupNextSubsession(RTSPClient* rtspClient)
{

	/*...............*/
	
	//对ServerMediaSubsession发送SETUP命令,收到回复后回调continueAfterSETUP函数
	rtspClient->sendSetupCommand(*scs.subsession, continueAfterSETUP, False, True);

	/*...............*/
		
	// 成功与所有的ServerMediaSubsession建立了连接,现在发送PLAY命令
	rtspClient->sendPlayCommand(*scs.session, continueAfterPLAY, scs.session->absStartTime(), scs.session->absEndTime());
	
	/*...............*/
}

void XXXX::continueAfterSETUP(RTSPClient* rtspClient, )
{
	/*...............*/

	//调用setupNextSubsession函数与下一个ServerMediaSubsession建立连接,
	//在setupNextSubsession函数中,会检查是否与所有的ServerMediaSubsession都建立了连接,
	//全部建立连接之后则发送PLAY命令请求开始传送数据,收到回复则调用continueAfterPLAY函数
	setupNextSubsession(rtspClient);
}

void XXXX::continueAfterPLAY(RTSPClient* rtspClient, int resultCode, char* resultString) {
   
	/*...............*/

	//发送play命令之后,设置定时发送心跳
	scheduleHeartBeatCommand(rtspClient);
}

void XXXX::continueAfterHeartBeatOption(RTSPClient* rtspClient)
{
	scheduleHeartBeatCommand(rtspClient);
}

void XXXX::scheduleHeartBeatCommand(RTSPClient* rtspClient)
{
	// 获取超时时间,设置超时一半的时间发送心跳
	unsigned delayMax = rtspClient->sessionTimeoutParameter();

	int64_t uSecondsToDelay = delayMax;
	uSecondsToDelay = uSecondsToDelay * 500000;
	m_HeartBeatCommandTask = env->taskScheduler().scheduleDelayedTask(uSecondsToDelay, sendHeartBeatCommand, rtspClient);
}

void XXXX::sendHeartBeatCommand(void* clientData)
{
	// 支持GET_PARAMETER参数的话就发送GET_PARAMETER,不支持发送option
	// 发送成功之后在通过回调continueAfterHeartBeatOption重新设置定时,这样就进入了循环,一直在发送心跳
	if (bsupportGetParamter)
	{
		sendGetParameterCommand((*rtspClient->scs.session), continueAfterHeartBeatOption, NULL);
	}
	else
	{
		sendOptionsCommand(continueAfterHeartBeatOption);
	}
}

问题二:

问题描述:发送option后收到回应,再次发送DESCRIBE后隔10s左右收到回应,建立连接时间较长;

 原因描述:使用live555 接收 有鉴权功能的IPC中的RTSP服务时 RTSP play 之前会有很长时间的延时 大概10秒左右;原因是我们的rtsp的url 可能是 这种形式的rtsp:\\usr:password@192.xxx.xxx.xxx\streamname;也就是说rtsp的url 是包含用户名和密码的。

借鉴连接:

解决方法:RTSPClient 实例使用时sendDescribeCommand 使用

sendDescribeCommand(describecallback,Authenticator*);

修改之前代码:

// 假设rtspURL的格式rtsp:\\usr:password@192.xxx.xxx.xxx\streamname
RTSPClient * pRtspClient = NULL;

pRtspClient = ourRTSPClient::createNew(*env, rtspURL, 1, NULL);

if (pRtspClient)
{
	pRtspClient->sendOptionsCommand(continueAfterOption);
}

修改之后:

// 先将rtsp:\\usr:password@192.xxx.xxx.xxx\streamname解析一下,
// pUnauthorizedPath 的格式为rtsp:\\192.xxx.xxx.xxx\streamname
char* pUsername = NULL; 
char* pPassword = NULL;
char* pUnauthorizedPath = NULL;
ParseRTSPURL(rtspURL, pUsername, pPassword, pUnauthorizedPath);

if (pUsername != NULL && pPassword != NULL)
	pRtspClient = ourRTSPClient::createNew(*env, pUnauthorizedPath, 1, NULL);
else
	pRtspClient = ourRTSPClient::createNew(*env, rtspURL, 1, NULL);

if (pRtspClient)
{
	if (pUsername != NULL && pPassword != NULL)
	{
		Authenticator authenticator(pUsername, pPassword, False);
		pRtspClient->sendOptionsCommand(continueAfterOption, &authenticator);
	}
	else
	{
		pRtspClient->sendOptionsCommand(continueAfterOption);
	}	
}