1)我对Live555进行了一次封装,但是Live555 是单线程的,里面定义的全局变量太多,我封装好dll库后,在客户端调用,因为多个对话框中要使用码流,我就定义了多个对象从设备端接收码流,建立多个连接,但是当一路码流退出,然后在退出另外的一路码流时,库里面出现问题,原因是Live555 里面的全局变量被破坏了!
针对上面问题:我目前的解决办法是将全局的信息隔离:
定义一个结构:
#define CLIENT_STREAM_NUM 4
class ourRTSPClient;
typedef struct _RtspGlobal
{
ourRTSPClient *pRtspClient;
NetSdk *pNetSdk;
}RtspGlobal;
//
RtspGlobal struRtspGlobal[CLIENT_STREAM_NUM];
这样每一路码流对应数组中的一项,就做成多线程的了,在全局的回调函数中,根据RTSPClient*rtspClient的指针和struRtspGloball数组中的指针进行比较,如果相同,就知道是哪个流对应的连接了,比如在continueAfterSETUP函数里面建立sink时,我们可以如下判断:
for (int i=0;i
if (struRtspGlobal[i].pNetSdk!=NULL)
{
if (struRtspGlobal[i].pRtspClient==rtspClient)
{
scs.subsession->sink = CRtpMediaSink::createNew(env, *scs.subsession,
(RtpMediaSinkCallback)struRtspGlobal[i].pNetSdk->rtspDataCallback,
(void *)&struRtspGlobal[i],RTPMEDAA_SINK_RECEIVE_BUFFER_SIZE, rtspClient->url());
break;
}
}
}
这样使得testRtspClient例子支持到多线程了。
2)Live555 的断网重连问题
1)重连死锁
1.1)重连时如果将解码回调线程放在NetSdk里面,使用两个Event,当接受线程结束时,发送接受线程结束的信号,然后在解码线程里面判断接收线程信号 ,如果有信号,就发送一个退出解码线程,发送一个解码结束的信号;
1.2)当超时重连时,首先Stop码流,然后Restart码流;停止码流时,将eventLoopWatchVariable=1;让数据接收线程顺利退出;同时在stop函数里面等待解码线程结束,
WaitForThreadExit(m_DecodeExitEvent);
这时会造成死锁;因为Live555是单线程的,在超时函数中需要等待本线程的结束,造成死锁;
解决办法:
1)使用单独的心跳线程来实现重连功能或者在回调数据给客户端的的解码线程里面实现重连功能;
2)网络断开判断方法 使用延迟队列来判断,初始化时候调用noteLiveness,然后每次收到Sink的一帧数据时,再次调用noteLiveness,这样如果网络断开,超时后,就能判断出来;在数据接收线程的doEventLoop后面将重连标记置位:
m_bReConnect=true;
3)断网重连的工作不能放在livenessTimeoutTask这个函数里面,不然会造成重连死锁,因为live555是单线程的;只能放在其它的线程里面实现重连;我是放在回调给客户端的解码线程里面实现重连;
void NetSdk::noteLiveness(void* clientData,UsageEnvironment& env)
{
if (m_ReconnectTime> 0)
{
env.taskScheduler().rescheduleDelayedTask(fLivenessCheckTask,m_ReconnectTime*1000000,(TaskFunc*)livenessTimeoutTask, clientData);
}
}
void NetSdk::livenessTimeoutTask(void* clientData) {
TRACE("livenessTimeoutTask run\n");
RtspGlobal *pRtspGlobal=(RtspGlobal *)clientData;
pRtspGlobal->pNetSdk->fLivenessCheckTask= NULL;
UsageEnvironment& env = pRtspGlobal->pRtspClient->envir(); // alias
pRtspGlobal->pNetSdk->RestopVideo();
}
重连线程如下:
void NetSdk::DecodeThread(void *arg)
{
NetSdk *pThis=(NetSdk*)arg;
while (!pThis->m_bQuit)
{
if (pThis->m_bReConnect)
{
//
pThis->RestartVideo();
pThis->m_bReConnect=false;
}else
{
pThis->ImageDecodeAndShow();
}
}
SetEvent(pThis->m_DecodeExitEvent);
}
哪位有更好的办法,不妨告诉我!