使用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);
}
}
.