我對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<CLIENT_STREAM_NUM;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();
}
}