使用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