使用live555客戶端源碼遇到的問題及解決方法

使用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:[email protected]\streamname;也就是說rtsp的url 是包含用戶名和密碼的。

借鑑連接:https://blog.csdn.net/u013008311/article/details/81585827

解決方法:RTSPClient 實例使用時sendDescribeCommand 使用

sendDescribeCommand(describecallback,Authenticator*);

修改之前代碼:

// 假設rtspURL的格式rtsp:\\usr:[email protected]\streamname
RTSPClient * pRtspClient = NULL;

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

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

修改之後:

// 先將rtsp:\\usr:[email protected]\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);
	}	
}

ParseRTSPURL()函數鏈接:https://blog.csdn.net/m0_37684310/article/details/89713900

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章