www.pudn.com > rtsp_linker.rar > rtspLinker.cpp


//--------------------------------------------------------------------------- 
 
#include  
 
#include "rtspLinker.h" 
 
//--------------------------------------------------------------------------- 
 
int GetHostByNameFuc(char *pcDDNS, char *pcIP); 
//--------------------------------------------------------------------------- 
 
const unsigned long RECV_BUF_SIZE = 204800; 
const unsigned long UNIT_TIMEOUT_MSEC = 100; 
 
rtspLinker::rtspLinker() 
           :m_sRtspSkt(INVALID_SOCKET), m_sVideoSkt(INVALID_SOCKET), m_sAudioSkt(INVALID_SOCKET), 
            m_ulPort(0), m_ulVideoPort(0), m_ulAudioPort(0), 
            m_eProtoType(ptTCP), m_bAudioEnabled(true), 
            m_ulTimeOut(3000), m_ulReconnectInter(5000), m_ulFrameBufSize(10), 
            m_usSeqNum(0), m_bStartup(true), m_bTerminate(false), 
            m_hProcHandle(NULL), m_hAudioProcHandle(NULL) 
{ 
    m_hHeap = GetProcessHeap(); 
 
    *m_pcIP = '\0'; 
    *m_pcUrlPath = '\0'; 
    *m_pcSession = '\0'; 
    *m_pcVideoTrack = '\0'; 
    *m_pcAudioTrack = '\0'; 
 
    InitializeCriticalSection(&m_csVideoListLock); 
    InitializeCriticalSection(&m_csAudioListLock); 
    InitializeCriticalSection(&m_csBufferPoolLock); 
 
    WSADATA wsaData; 
    if(WSAStartup(MAKEWORD(2,2), &wsaData) != NO_ERROR) 
        MessageBox(NULL, "WSAStartup() failed !", "rtspLinker::Error", MB_OK); 
 
	GetHostByNameFuc("ddns.camddns.com", m_pcSelfDDNSServerIP); 
	GetHostByNameFuc("ddns2.ydsdvr.com", m_pcSelfDDNSServerIP2); 
} 
 
rtspLinker::~rtspLinker() 
{ 
  	WSACleanup(); 
 
    DeleteCriticalSection(&m_csVideoListLock); 
    DeleteCriticalSection(&m_csAudioListLock); 
    DeleteCriticalSection(&m_csBufferPoolLock); 
}              
 
void rtspLinker::SetLinker(char *pcIP, unsigned long ulPort) 
{ 
    strcpy(m_pcIP, pcIP); 
    m_ulPort = ulPort; 
 
    char pcRealIP[64]; 
    if(GetHostByNameFuc(m_pcIP, pcRealIP) == NO_ANY_ERROR) 
    {     
        //若是公司的 DDNS,要用網頁的方式,取得 IP 及 port 值 
        if(strcmp(pcRealIP, m_pcSelfDDNSServerIP) == 0 || strcmp(pcRealIP, m_pcSelfDDNSServerIP2) == 0) 
        { 
            SOCKET sSocket = socket(AF_INET,SOCK_STREAM,0); 
        	if(sSocket != INVALID_SOCKET) 
            { 
        	    struct sockaddr_in siServerSockaddr; 
        	    memset(&siServerSockaddr,0,sizeof(sockaddr_in)); 
        	    siServerSockaddr.sin_family      = AF_INET; 
        	    siServerSockaddr.sin_addr.s_addr = inet_addr(pcRealIP); 
        	    siServerSockaddr.sin_port        = htons(m_ulPort); 
 
	        	if(connect(sSocket, (const struct sockaddr *)&siServerSockaddr, sizeof(sockaddr_in)) == 0) 
                { 
                    char pcCmd[1024]; 
                    sprintf(pcCmd, "GET / HTTP/1.1\r\nHost:%s\r\n\r\n", m_pcIP); 
                    if( send(sSocket, pcCmd, strlen(pcCmd), 0) > 0 ) 
                    { 
                        memset(pcCmd, 0, 1024); 
                        if( recv(sSocket, pcCmd, 1024, 0) > 0 ) 
                        { 
                            //檢查是否已取得真實的 IP,是則離開 
                            char *pcFind = strstr(pcCmd, "Location: http://"); 
                            if(pcFind != NULL) 
                            { 
                                char *pcFindEnd = strstr(pcFind, "/\r\n"); 
                                if(pcFindEnd != NULL) 
                                { 
                                    memcpy(pcIP, pcFind+17, pcFindEnd-pcFind-17); 
                                    *(m_pcIP+(pcFindEnd-pcFind-17)) = '\0'; 
 
                                    pcFindEnd = strstr(m_pcIP, ":"); 
                                    if(pcFindEnd != NULL) 
                                    { 
                                        m_ulPort = atoi(pcFindEnd+1); 
                                        *pcFindEnd = '\0'; 
                                    } 
                                } 
                            } 
                        } 
                    } 
                    CloseSocket(&sSocket); 
                } 
            } 
        } 
        else 
        { 
            strcpy(m_pcIP, pcRealIP); 
        } 
    } 
} 
 
void rtspLinker::SetProtocol(enum PROTOCOL_TYPE eType) 
{ 
    m_eProtoType = eType; 
} 
 
void rtspLinker::SetUrlPath(char *pcUrl) 
{ 
    sprintf(m_pcUrlPath, "%s%s", (*pcUrl=='/')?"":"/", pcUrl); 
} 
 
void rtspLinker::SetAudioEnabled(bool bEnabled) 
{ 
    m_bAudioEnabled = bEnabled; 
} 
 
void rtspLinker::SetTimeOut(unsigned long ulTimeOut) 
{ 
    m_ulTimeOut = ulTimeOut; 
} 
 
void rtspLinker::SetReconnectInterval(unsigned long ulInterval) 
{ 
    m_ulReconnectInter = ulInterval; 
} 
 
void rtspLinker::SetFrameBufferSize(unsigned long ulSize) 
{ 
    m_ulFrameBufSize = ulSize; 
} 
 
void rtspLinker::Connect() 
{ 
    if(m_hProcHandle || m_hAudioProcHandle) 
    { 
        Disconnect(); 
    } 
 
    m_bStartup = true; 
    m_bTerminate = false; 
    *m_pcSession = '\0';    
    *m_pcVideoTrack = '\0'; 
    *m_pcAudioTrack = '\0'; 
    m_DataQueue.Resize(0); 
    m_usSeqNum = 0; 
 
    m_hProcHandle = CreateThread(NULL, 0, MainProc, this, 0, NULL); 
    if(m_bAudioEnabled && m_eProtoType == ptUDP) 
        m_hAudioProcHandle = CreateThread(NULL, 0, AudioProc, this, 0, NULL); 
} 
 
void rtspLinker::Disconnect() 
{ 
    m_bTerminate = true; 
 
    if(m_sRtspSkt != INVALID_SOCKET) 
    { 
        char pcCmd[1024]; 
        memset(pcCmd, 0, 1024); 
        sprintf(pcCmd, "TEARDOWN rtsp://%s%s RTSP/1.0\r\nSession: %s\r\nCSeq: %d\r\n\r\n", 
                m_pcIP, m_pcUrlPath, m_pcSession, m_usSeqNum++); 
        send(m_sRtspSkt,pcCmd,strlen(pcCmd),0); 
        memset(pcCmd, 0, 1024); 
        RecvResponse(m_sRtspSkt, (unsigned char *)pcCmd, 1024, m_ulTimeOut); 
    } 
 
    CloseSocket(&m_sRtspSkt);   
    CloseSocket(&m_sVideoSkt); 
    CloseSocket(&m_sAudioSkt); 
 
    if(m_hProcHandle) 
    { 
        DWORD dwRetValue = 0; 
        do 
        { 
           Sleep(3); 
           GetExitCodeThread(m_hProcHandle, &dwRetValue); 
        }while(dwRetValue != ERR_TERMINATED); 
        CloseHandle(m_hProcHandle); 
        m_hProcHandle = NULL; 
    } 
 
    if(m_hAudioProcHandle) 
    { 
        DWORD dwRetValue = 0; 
        do 
        { 
           Sleep(3); 
           GetExitCodeThread(m_hAudioProcHandle, &dwRetValue); 
        }while(dwRetValue != ERR_TERMINATED); 
        CloseHandle(m_hAudioProcHandle); 
        m_hAudioProcHandle = NULL; 
    } 
 
    EnterCriticalSection(&m_csVideoListLock); 
    while(!m_VideoList.empty()) 
    { 
        ReturnFrame(&m_VideoList.front()->m_pBufPtr); 
        m_VideoList.pop_front(); 
    } 
    LeaveCriticalSection(&m_csVideoListLock); 
 
    EnterCriticalSection(&m_csAudioListLock); 
    while(!m_AudioList.empty()) 
    { 
        ReturnFrame(&m_AudioList.front()->m_pBufPtr); 
        m_AudioList.pop_front(); 
    } 
    LeaveCriticalSection(&m_csAudioListLock); 
 
    std::set::iterator itPos; 
    EnterCriticalSection(&m_csBufferPoolLock); 
    bool bEmpty = m_BufferPool.empty(); 
    LeaveCriticalSection(&m_csBufferPoolLock); 
    while(!bEmpty) 
    { 
        EnterCriticalSection(&m_csBufferPoolLock); 
        void *pVoid = *m_BufferPool.begin(); 
        LeaveCriticalSection(&m_csBufferPoolLock); 
        ReturnFrame(&pVoid); 
        EnterCriticalSection(&m_csBufferPoolLock); 
        bEmpty = m_BufferPool.empty(); 
        LeaveCriticalSection(&m_csBufferPoolLock); 
    } 
} 
 
bool rtspLinker::RecvVideoFrame(enum FRAME_TYPE &eType, void **ppBuf, unsigned long &ulLen) 
{ 
    EnterCriticalSection(&m_csVideoListLock); 
    if(!m_VideoList.empty()) 
    { 
        FrameInfo *pInfo = m_VideoList.front(); 
        eType  = pInfo->m_eType; 
        *ppBuf = pInfo->m_pBufPtr; 
        ulLen  = pInfo->m_ulLen; 
        m_VideoList.pop_front(); 
        LeaveCriticalSection(&m_csVideoListLock); 
        return true; 
    } 
    LeaveCriticalSection(&m_csVideoListLock); 
    return false; 
} 
 
bool rtspLinker::RecvAudioFrame(enum FRAME_TYPE &eType, void **ppBuf, unsigned long &ulLen) 
{ 
    EnterCriticalSection(&m_csAudioListLock); 
    if(!m_AudioList.empty()) 
    { 
        FrameInfo *pInfo = m_AudioList.front(); 
        eType  = pInfo->m_eType; 
        *ppBuf = pInfo->m_pBufPtr; 
        ulLen  = pInfo->m_ulLen; 
        m_AudioList.pop_front(); 
        LeaveCriticalSection(&m_csAudioListLock); 
        return true; 
    } 
    LeaveCriticalSection(&m_csAudioListLock); 
    return false; 
} 
 
void rtspLinker::ReturnFrame(void **ppBuf) 
{                                 
    std::set::iterator itPos; 
    EnterCriticalSection(&m_csBufferPoolLock); 
    itPos = m_BufferPool.find(*ppBuf); 
    if(itPos != m_BufferPool.end()) 
        m_BufferPool.erase(itPos); 
    LeaveCriticalSection(&m_csBufferPoolLock); 
 
    HeapFree(m_hHeap, 0, *ppBuf); 
    *ppBuf = NULL; 
} 
//--------------------------------------------------------------------------------------------- 
//--------------------------------------------------------------------------------------------- 
//--------------------------------------------------------------------------------------------- 
                                                                                                     
int GetHostByNameFuc(char *pcDDNS, char *pcIP) 
{ 
    if(inet_addr(pcDDNS) == INADDR_NONE) 
    { 
        struct hostent *hp = gethostbyname(pcDDNS); 
        if(!hp) 
            return ERR_INIT_DDNSCONVERT; 
 
        struct sockaddr_in local_addr; 
        memcpy(&local_addr.sin_addr.s_addr,hp->h_addr,4); 
 
        struct in_addr in; 
        in.s_addr = local_addr.sin_addr.s_addr; 
        strcpy(pcIP, inet_ntoa(in)); 
    } 
    else 
    { 
        strcpy(pcIP, pcDDNS); 
    } 
    return NO_ANY_ERROR; 
} 
//--------------------------------------------------------------------------------------------- 
//--------------------------------------------------------------------------------------------- 
//--------------------------------------------------------------------------------------------- 
 
int rtspLinker::CreateSocketConnect(SOCKET *pSocket, const char *pcIP, const unsigned long ulPort) 
{ 
    if(*pSocket != INVALID_SOCKET) 
        CloseSocket(pSocket); 
 
    *pSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if(*pSocket == INVALID_SOCKET) 
        return INVALID_SOCKET; 
 
    sockaddr_in sSockaddr; 
    sSockaddr.sin_family = AF_INET; 
    sSockaddr.sin_addr.s_addr = inet_addr(pcIP); 
    sSockaddr.sin_port = htons(ulPort); 
 
    setsockopt(*pSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&m_ulTimeOut, sizeof(m_ulTimeOut)); 
    setsockopt(*pSocket, SOL_SOCKET, SO_SNDTIMEO, (char *)&m_ulTimeOut, sizeof(m_ulTimeOut)); 
     
    return connect( *pSocket, (SOCKADDR*)&sSockaddr, sizeof(sSockaddr) ); 
} 
 
int rtspLinker::CreateBindSocket(SOCKET *pSocket, unsigned long *pulPort) 
{ 
    CloseSocket(pSocket); 
     
    int iRetValue = NO_ANY_ERROR; 
 
    //建立 UDP socket 
    *pSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 
 
    if(*pSocket == INVALID_SOCKET) 
        return ERR_CONNECT_SOCKET; 
 
    struct sockaddr_in addr; 
    ZeroMemory(&addr, sizeof(addr)); 
    addr.sin_family = AF_INET; 
    addr.sin_addr.s_addr = ADDR_ANY; 
 
    //做 bind 去獲得一個 port 
    if(bind(*pSocket, (struct sockaddr *)&addr, sizeof(addr)) != 0) 
    { 
        CloseSocket(pSocket); 
        iRetValue = ERR_CONNECT_BIND; 
    } 
    else 
    { 
        //從剛建立並 bind 的 socket 去取得分配到的 port 
        if(pulPort) 
        { 
            int iLen = sizeof(addr); 
            ZeroMemory(&addr, sizeof(addr)); 
            if(getsockname(*pSocket, (struct sockaddr *)&addr, &iLen) != 0) 
            { 
                CloseSocket(pSocket); 
                iRetValue = ERR_CONNECT_GETSOCKNAME; 
            } 
            else 
                *pulPort = ntohs(addr.sin_port); 
        } 
    } 
 
    return iRetValue; 
} 
 
void rtspLinker::CloseSocket(SOCKET *pSocket) 
{ 
    if(*pSocket != INVALID_SOCKET) 
    { 
        shutdown(*pSocket, SD_BOTH); 
        closesocket(*pSocket); 
        *pSocket = INVALID_SOCKET; 
    } 
} 
 
int rtspLinker::RecvResponse(SOCKET sSocket, unsigned char *pcBuf, unsigned int uiRecvSize, unsigned long ulTimeout) 
{ 
    if(sSocket == INVALID_SOCKET)   return -1; 
    if(pcBuf == NULL)               return -1; 
    if(uiRecvSize == 0)             return 0; 
 
    unsigned int recvSize_temp = 0;  
    int iRecvSize = 0; 
 
    fd_set sReadSet; 
    timeval tTimeout; 
    tTimeout.tv_sec = 0; 
    tTimeout.tv_usec = UNIT_TIMEOUT_MSEC * 1000; 
    int iTimeoutLimit = ulTimeout / UNIT_TIMEOUT_MSEC + 1; 
    int iTimeoutCount = 0; 
 
    while(recvSize_temp < uiRecvSize) 
    { 
        iTimeoutCount = 0; 
        do 
        { 
            if(++iTimeoutCount > iTimeoutLimit) 
                return SOCKET_ERROR; 
 
            FD_ZERO(&sReadSet); 
            FD_SET(sSocket, &sReadSet); 
 
            int iRes = select(1, &sReadSet, NULL, NULL, &tTimeout ); 
            if( iRes > 0 ) 
                break; 
            else if( iRes == 0 ) 
                continue; 
            else if( iRes == SOCKET_ERROR ) 
                return SOCKET_ERROR; 
        }while(TRUE); 
 
        //一次接收一個 byte,避免收到後面的影像資料 
        iRecvSize = recv(sSocket,(char *)(pcBuf+recvSize_temp), 1, 0);  
        if(iRecvSize == 0) 
            return 0; 
        else if(iRecvSize == SOCKET_ERROR) 
            return SOCKET_ERROR; 
             
        recvSize_temp += iRecvSize; 
 
        //檢查是否收到這個 response 的結尾 "\r\n\r\n" 
        if(recvSize_temp >= 4) 
        { 
            if(pcBuf[recvSize_temp-4] == 0x0D && pcBuf[recvSize_temp-3] == 0x0A && pcBuf[recvSize_temp-2] == 0x0D && pcBuf[recvSize_temp-1] == 0x0A) 
                break; 
        } 
    } 
    return recvSize_temp; 
} 
 
int rtspLinker::RecvBufFunc(SOCKET sSocket, unsigned char *pcBuf, unsigned int uiRecvSize, unsigned long ulTimeout) 
{ 
    if(sSocket == INVALID_SOCKET)   return -1; 
    if(pcBuf == NULL)               return -1; 
    if(uiRecvSize == 0)             return 0; 
 
    unsigned int recvSize_temp = 0; 
    int iRecvSize = 0; 
 
    fd_set sReadSet, sErrorSet; 
    timeval tTimeout; 
    tTimeout.tv_sec = 0; 
    tTimeout.tv_usec = UNIT_TIMEOUT_MSEC * 1000; 
    int iTimeoutLimit = ulTimeout / UNIT_TIMEOUT_MSEC + 1; 
    int iTimeoutCount = 0; 
    int iRes = 0; 
 
    while(recvSize_temp < uiRecvSize) 
    { 
        iTimeoutCount = 0; 
        do 
        { 
            if(++iTimeoutCount > iTimeoutLimit) 
                return iRes; 
 
            FD_ZERO(&sReadSet);     FD_SET(sSocket, &sReadSet); 
            FD_ZERO(&sErrorSet);    FD_SET(sSocket, &sErrorSet); 
 
            iRes = select(1, &sReadSet, NULL, &sErrorSet, &tTimeout ); 
            if(FD_ISSET(sSocket, &sErrorSet)) 
                return SOCKET_ERROR; 
 
            if( iRes > 0 ) 
                break; 
            else if( iRes == 0 ) 
                continue; 
            else if( iRes == SOCKET_ERROR ) 
                return SOCKET_ERROR; 
        }while(TRUE); 
 
        iRecvSize = recv(sSocket,(char *)(pcBuf+recvSize_temp), uiRecvSize-recvSize_temp, 0); 
        if(iRecvSize == 0) 
            return 0; 
        else if(iRecvSize == SOCKET_ERROR) 
            return SOCKET_ERROR; 
 
        recvSize_temp += iRecvSize; 
    } 
 
    return recvSize_temp; 
}         
 
int rtspLinker::RecvOnceFunc(SOCKET sSocket, unsigned char *pcBuf, unsigned int uiRecvSize, unsigned long ulTimeout) 
{ 
    if(sSocket == INVALID_SOCKET)   return -1; 
    if(pcBuf == NULL)               return -1; 
    if(uiRecvSize == 0)             return 0; 
 
    fd_set sReadSet, sErrorSet; 
    timeval tTimeout; 
    tTimeout.tv_sec = 0; 
    tTimeout.tv_usec = UNIT_TIMEOUT_MSEC * 1000; 
    int iTimeoutLimit = ulTimeout / UNIT_TIMEOUT_MSEC + 1; 
    int iRes = 0; 
    int iTimeoutCount = 0; 
 
    do 
    { 
        if(++iTimeoutCount > iTimeoutLimit) 
            return iRes; 
 
        FD_ZERO(&sReadSet);     FD_SET(sSocket, &sReadSet); 
        FD_ZERO(&sErrorSet);    FD_SET(sSocket, &sErrorSet); 
 
        iRes = select(1, &sReadSet, NULL, &sErrorSet, &tTimeout ); 
        if(FD_ISSET(sSocket, &sErrorSet)) 
            return SOCKET_ERROR; 
 
        if( iRes > 0 ) 
            break; 
        else if( iRes == 0 ) 
            continue; 
        else if( iRes == SOCKET_ERROR ) 
            return SOCKET_ERROR; 
    }while(TRUE); 
 
    return recv(sSocket, (char *)pcBuf, uiRecvSize, 0); 
} 
 
DWORD WINAPI rtspLinker::MainProc(LPVOID lpParam) 
{ 
    rtspLinker *pSelf = (rtspLinker *)lpParam; 
    int iStatus = ERR_TERMINATED; 
    do 
    { 
        if(iStatus == NO_ANY_ERROR) 
            iStatus = pSelf->RecvDataFunc(); 
        else 
            iStatus = pSelf->ConnectFunc(); 
 
        if(iStatus != NO_ANY_ERROR) 
        { 
            if(pSelf->m_sRtspSkt != INVALID_SOCKET) 
            { 
                char pcCmd[1024]; 
                memset(pcCmd, 0, 1024); 
                sprintf(pcCmd, "TEARDOWN rtsp://%s%s RTSP/1.0\r\nSession: %s\r\nCSeq: %d\r\n\r\n", 
                        pSelf->m_pcIP, pSelf->m_pcUrlPath, pSelf->m_pcSession, pSelf->m_usSeqNum++); 
                send(pSelf->m_sRtspSkt,pcCmd,strlen(pcCmd),0); 
                memset(pcCmd, 0, 1024); 
                pSelf->RecvResponse(pSelf->m_sRtspSkt, (unsigned char *)pcCmd, 1024, pSelf->m_ulTimeOut); 
            } 
 
            pSelf->m_bStartup = true; 
            *pSelf->m_pcSession = '\0'; 
            *pSelf->m_pcVideoTrack = '\0'; 
            *pSelf->m_pcAudioTrack = '\0'; 
            pSelf->m_DataQueue.Resize(0); 
            pSelf->m_usSeqNum = 0; 
            pSelf->CloseSocket(&pSelf->m_sRtspSkt);   
            pSelf->CloseSocket(&pSelf->m_sVideoSkt); 
            pSelf->CloseSocket(&pSelf->m_sAudioSkt); 
 
            int iCount = 0, iCountLimit = pSelf->m_ulReconnectInter / UNIT_TIMEOUT_MSEC; 
            while(!pSelf->m_bTerminate && iCount++ < iCountLimit) 
            { 
                Sleep(UNIT_TIMEOUT_MSEC); 
            } 
        } 
    }while(!pSelf->m_bTerminate); 
    return ERR_TERMINATED; 
} 
 
DWORD WINAPI rtspLinker::AudioProc(LPVOID lpParam) 
{ 
    rtspLinker *pSelf = (rtspLinker *)lpParam; 
    //int iStatus = ERR_TERMINATED; 
    do 
    { 
        if(pSelf->m_sAudioSkt != INVALID_SOCKET && pSelf->m_bStartup == false) 
        { 
            pSelf->RecvAudioFunc(); 
        } 
        Sleep(1); 
    }while(!pSelf->m_bTerminate); 
    return ERR_TERMINATED; 
} 
 
int rtspLinker::ConnectFunc() 
{ 
    const unsigned long MAX_BUF_SIZE = 1024; 
 
    int  iByte; 
    char pcSendBuf[MAX_BUF_SIZE]; 
    char pcRecvBef[MAX_BUF_SIZE]; 
     
    //建立連線 
    if(m_bTerminate == true) 
        return ERR_TERMINATED; 
    if(CreateSocketConnect(&m_sRtspSkt, m_pcIP, m_ulPort) == INVALID_SOCKET) 
        return ERR_CONNECT_CONNECT; 
 
    //執行 DESCRIBE 
    sprintf(pcSendBuf, "DESCRIBE rtsp://%s%s RTSP/1.0\r\nCSeq: %d\r\n\r\n", m_pcIP, m_pcUrlPath, m_usSeqNum++); 
    iByte = send(m_sRtspSkt, pcSendBuf, strlen(pcSendBuf), 0); 
    if(iByte <= 0) 
        return ERR_CONNECT_SEND; 
 
    memset(pcRecvBef, 0, MAX_BUF_SIZE); 
    RecvResponse(m_sRtspSkt, (unsigned char *)pcRecvBef, MAX_BUF_SIZE, m_ulTimeOut); 
    if(strstr((char *)pcRecvBef, " 200 ") == NULL) 
        return ERR_CONNECT_RECV; 
    else 
    { 
        //接收 Content-Length 大小的 Content 
        char *pcContentLen = strstr((char *)pcRecvBef,"Content-Length: "); 
        if(pcContentLen != NULL) 
        { 
            unsigned long ulContentLen = atoi(pcContentLen+16); 
            memset(pcRecvBef, 0, MAX_BUF_SIZE); 
            RecvResponse(m_sRtspSkt, (unsigned char *)pcRecvBef, ulContentLen, m_ulTimeOut); 
 
            char *pcKeyword, *pcTrack; 
            pcKeyword = strstr(pcRecvBef, "m=video"); 
            pcTrack   = strstr(pcKeyword, "a=control:"); 
            if(sscanf(pcTrack, "a=control:%[^\r]", m_pcVideoTrack) != 1) 
                return ERR_CONNECT_NOVIDEOTRACK; 
 
            pcKeyword = strstr(pcRecvBef, "m=audio"); 
            pcTrack   = strstr(pcKeyword, "a=control:");     
            if(sscanf(pcTrack, "a=control:%[^\r]", m_pcAudioTrack) != 1) 
                *m_pcAudioTrack = '\0'; 
        } 
    } 
 
    //執行 SETUP -> Video track 
    if(m_bTerminate == true) 
        return ERR_TERMINATED; 
 
    if(m_eProtoType == ptTCP) 
    { 
        sprintf(pcSendBuf, "SETUP rtsp://%s%s/%s RTSP/1.0\r\nCSeq: %d\r\nTransport: RTP/AVP/TCP;unicast;interleaved=0\r\n\r\n", 
                m_pcIP, m_pcUrlPath, m_pcVideoTrack, m_usSeqNum++); 
    } 
    else 
    { 
        unsigned long ulAssignedPort = 0; 
        int iRetValue = CreateBindSocket(&m_sVideoSkt, &ulAssignedPort); 
        if(iRetValue == NO_ANY_ERROR) 
            sprintf(pcSendBuf, "SETUP rtsp://%s%s/%s RTSP/1.0\r\nCSeq: %d\r\nTransport: RTP/AVP;unicast;client_port=%d\r\n\r\n", 
                    m_pcIP, m_pcUrlPath, m_pcVideoTrack, m_usSeqNum++, ulAssignedPort/*, ulAssignedPort+1*/); 
        else 
            return iRetValue; 
    } 
    iByte = send(m_sRtspSkt, pcSendBuf, strlen(pcSendBuf), 0); 
    if(iByte <= 0) 
        return ERR_CONNECT_SEND; 
 
    memset(pcRecvBef, 0, MAX_BUF_SIZE); 
    RecvResponse(m_sRtspSkt, (unsigned char *)pcRecvBef, MAX_BUF_SIZE, m_ulTimeOut); 
    if(strstr(pcRecvBef, " 200 ") == NULL) 
        return ERR_CONNECT_RECV; 
    else 
    { 
        //取得 Session 
        char *pcSession = strstr(pcRecvBef, "Session: "); 
        if(sscanf(pcSession, "Session: %[^;\r]", m_pcSession) != 1) 
            return ERR_CONNECT_NOSESSION; 
 
        if(m_eProtoType == ptUDP) 
        { 
            char *pcServerPort = strstr(pcRecvBef, "server_port="); 
            if(pcServerPort == NULL) 
                return ERR_CONNECT_NOSERVERPORT; 
            m_ulVideoPort = atoi(pcServerPort+12); 
        } 
    } 
 
    //執行 SETUP -> Audio track 
    if(m_bAudioEnabled && m_pcAudioTrack != '\0') 
    { 
        if(m_bTerminate == true) 
            return ERR_TERMINATED; 
             
        if(m_eProtoType == ptTCP) 
        { 
            sprintf(pcSendBuf, "SETUP rtsp://%s%s/%s RTSP/1.0\r\nSession: %s\r\nCSeq: %d\r\nTransport: RTP/AVP/TCP;unicast;interleaved=2\r\n\r\n", 
                    m_pcIP, m_pcUrlPath, m_pcAudioTrack, m_pcSession, m_usSeqNum++); 
        } 
        else 
        { 
            unsigned long ulAssignedPort = 0; 
            int iRetValue = CreateBindSocket(&m_sAudioSkt, &ulAssignedPort); 
            if(iRetValue != NO_ANY_ERROR) 
                return iRetValue; 
            sprintf(pcSendBuf, "SETUP rtsp://%s%s/%s RTSP/1.0\r\nCSeq: %d\r\nSession: %s\r\nTransport: RTP/AVP;unicast;client_port=%d\r\n\r\n", 
                    m_pcIP, m_pcUrlPath, m_pcAudioTrack, m_usSeqNum++, m_pcSession, ulAssignedPort/*, ulAssignedPort+1*/); 
        } 
        iByte = send(m_sRtspSkt,pcSendBuf,strlen(pcSendBuf),0); 
        if(iByte <= 0) 
            return ERR_CONNECT_SEND; 
 
        memset(pcRecvBef, 0, MAX_BUF_SIZE); 
        RecvResponse(m_sRtspSkt, (unsigned char *)pcRecvBef, MAX_BUF_SIZE, m_ulTimeOut); 
        if(strstr(pcRecvBef, " 200 ") == NULL) 
            return ERR_CONNECT_RECV; 
        else if(m_eProtoType == ptUDP) 
        { 
            char *pcServerPort = strstr(pcRecvBef,"server_port="); 
            if(pcServerPort == NULL) 
                return ERR_CONNECT_NOSERVERPORT; 
            m_ulAudioPort = atoi(pcServerPort+12); 
        } 
    } 
 
    //執行 PLAY 
    if(m_bTerminate == true) 
        return ERR_TERMINATED; 
    sprintf(pcSendBuf, "PLAY rtsp://%s%s RTSP/1.0\r\nCSeq: %d\r\nSession: %s\r\n\r\n", m_pcIP, m_pcUrlPath, m_usSeqNum++, m_pcSession); 
    iByte = send(m_sRtspSkt, pcSendBuf, strlen(pcSendBuf), 0); 
    if(iByte <= 0) 
        return ERR_CONNECT_SEND; 
 
    memset(pcRecvBef, 0, MAX_BUF_SIZE); 
    RecvResponse(m_sRtspSkt, (unsigned char *)pcRecvBef, MAX_BUF_SIZE, m_ulTimeOut); 
    if(strstr(pcRecvBef, " 200 ") == NULL) 
        return ERR_CONNECT_RECV; 
 
    if(m_eProtoType == ptUDP) 
    { 
        //連線到 rtsp server 
        struct sockaddr_in addr; 
        ZeroMemory(&addr, sizeof(addr)); 
        addr.sin_family = AF_INET; 
        addr.sin_port = htons(m_ulVideoPort); 
        addr.sin_addr.s_addr = inet_addr(m_pcIP); 
        if(connect(m_sVideoSkt, (struct sockaddr *)&addr, sizeof(addr)) != 0) 
            return ERR_CONNECT_CONNECT; 
 
        if(m_bAudioEnabled) 
        { 
            ZeroMemory(&addr, sizeof(addr)); 
            addr.sin_family = AF_INET; 
            addr.sin_port = htons(m_ulAudioPort); 
            addr.sin_addr.s_addr = inet_addr(m_pcIP); 
            if(connect(m_sAudioSkt, (struct sockaddr *)&addr, sizeof(addr)) != 0) 
                return ERR_CONNECT_CONNECT; 
        } 
    } 
 
    return NO_ANY_ERROR; 
} 
 
int rtspLinker::RecvDataFunc() 
{ 
    if(m_eProtoType == ptTCP) 
    { 
        unsigned char buf[RECV_BUF_SIZE]; 
        unsigned char header[64]; 
 
        int iRecvByte = RecvBufFunc(m_sRtspSkt,header,16,m_ulTimeOut); 
 
        //若接收失敗或第一個 byte 不為 0x24,則重連 
        if(iRecvByte == 16 && header[0] == 0x24) 
        { 
            int iInterleaved = header[1]; 
            unsigned short usSeq_Number = header[6]*256 + header[7]; 
            if(m_RtspCheckMap.find(iInterleaved) == m_RtspCheckMap.end()) 
            { 
                m_RtspCheckMap[iInterleaved].ID = iInterleaved; 
                memcpy(m_RtspCheckMap[iInterleaved].SSRC, header+12, 4); 
                m_RtspCheckMap[iInterleaved].usSeq_Number = usSeq_Number; 
            } 
 
            if(!m_DataQueue.IsLiving()) 
                m_DataQueue.Resize(RECV_BUF_SIZE); 
 
            //計算是否帶有 CSRC 資料,有則接收掉不做處理 
            unsigned char ucCSRC_Num = header[4]&0x0F; 
            if(ucCSRC_Num != 0) 
            { 
                if(RecvBufFunc(m_sRtspSkt,buf+16,ucCSRC_Num*4,m_ulTimeOut) != ucCSRC_Num*4) 
                    return ERR_RECV_CHECKCSRC; 
            } 
 
            //計算此封包的長度 (接收長度 = 實際封包長度 - 已接收 header - CSRC 所佔長度) 
            unsigned short usPacketLen = (header[2]*256 + header[3]) - 12 - ucCSRC_Num*4; 
            //若 CircleQueue 的剩餘容量小於欲接收的封包大小,則將 Queue 清空 (表示整個 Queue 都切不出一張 frame) 
            if(m_DataQueue.FreeSize() < (unsigned long)usPacketLen) 
                m_DataQueue.Erase(m_DataQueue.Size()); 
            //開始接收此封包 
            if(RecvBufFunc(m_sRtspSkt,buf,usPacketLen,m_ulTimeOut) != usPacketLen) 
                return ERR_RECV_NODATA; 
 
            //檢查 Sequence Number,若中間有 lost 封包,則要從 I frame 開始送 
            if(m_RtspCheckMap[iInterleaved].usSeq_Number != usSeq_Number) 
            { 
                m_RtspCheckMap[iInterleaved].usSeq_Number = usSeq_Number; 
                m_bStartup = true; 
            } 
            ++m_RtspCheckMap[iInterleaved].usSeq_Number; 
 
            if(iInterleaved == 0 || iInterleaved == 1) 
            { 
                //將此封包存入 Circle Queue 
                m_DataQueue.Write(buf, usPacketLen); 
            } 
            else 
            { 
                //iInterleaved == 2 || 3 -> Audio frame 
                if(m_bStartup == false) 
                { 
                    EnterCriticalSection(&m_csAudioListLock); 
                    if(m_AudioList.size() < m_ulFrameBufSize) 
                    { 
                        FrameInfo *pFrameInfo = new FrameInfo(ftAudio, HeapAlloc(m_hHeap, 0, usPacketLen), usPacketLen); 
                        memcpy(pFrameInfo->m_pBufPtr, buf, usPacketLen); 
                        m_AudioList.push_back(pFrameInfo);    
 
                        EnterCriticalSection(&m_csBufferPoolLock); 
                        m_BufferPool.insert(pFrameInfo->m_pBufPtr); 
                        LeaveCriticalSection(&m_csBufferPoolLock); 
                    } 
                    LeaveCriticalSection(&m_csAudioListLock); 
                } 
                return NO_ANY_ERROR; 
            } 
        } 
        else 
        { 
            return ERR_RECV_NODATA; 
        } 
    } 
    else 
    {        
        unsigned char buf[RECV_BUF_SIZE]; 
        unsigned char *header; 
 
        if(!m_DataQueue.IsLiving()) 
            m_DataQueue.Resize(RECV_BUF_SIZE); 
 
        if(m_DataQueue.FreeSize() < 12) 
            m_DataQueue.Erase(m_DataQueue.Size()); 
 
        int iRecvByte = RecvOnceFunc(m_sVideoSkt,buf,m_DataQueue.FreeSize(),m_ulTimeOut); 
 
        //若接收失敗或第一個 byte 不為 0x24,則重連 
        if(iRecvByte > 12) 
        { 
            header = buf; 
            int iInterleaved = 0; 
            unsigned short usSeq_Number = header[2]*256 + header[3]; 
            if(m_RtspCheckMap.find(iInterleaved) == m_RtspCheckMap.end()) 
            { 
                m_RtspCheckMap[iInterleaved].ID = iInterleaved; 
                memcpy(m_RtspCheckMap[iInterleaved].SSRC, header+8, 4); 
                m_RtspCheckMap[iInterleaved].usSeq_Number = usSeq_Number; 
            }                                                           
 
            //計算此封包的長度 (接收長度 = 實際封包長度 - 已接收 header - CSRC 所佔長度) 
            unsigned short usHeaderLen = 12 + (header[0]&0x0F)*4; 
            unsigned short usPacketLen = iRecvByte - usHeaderLen; 
 
            //檢查 Sequence Number,若中間有 lost 封包,則要從 I frame 開始送 
            if(m_RtspCheckMap[iInterleaved].usSeq_Number != usSeq_Number) 
            { 
                m_RtspCheckMap[iInterleaved].usSeq_Number = usSeq_Number; 
                m_bStartup = true; 
            } 
            ++m_RtspCheckMap[iInterleaved].usSeq_Number; 
 
            m_DataQueue.Write(buf+usHeaderLen, usPacketLen); 
        } 
        else 
        { 
            return ERR_RECV_NODATA; 
        } 
    } 
 
    if(m_bTerminate == true) 
        return ERR_TERMINATED; 
 
    bool bGetFrame = false; 
    do 
    { 
        enum FRAME_TYPE eFrameType = ftNone; 
        bool bFindIFrameData = false; 
        bool bFindZero = false; 
        unsigned long ulFindOffset = 0; 
        unsigned long ulFrameLen   = 0; 
 
        bGetFrame = false; 
        do 
        { 
            //尋找 00 00 01 開頭的資料 
            bFindZero = false; 
            unsigned long ulQueueSize = m_DataQueue.Size(); 
            for(unsigned int i=ulFindOffset;im_pBufPtr, ulFrameLen); 
                    m_VideoList.push_back(pFrameInfo); 
 
                    EnterCriticalSection(&m_csBufferPoolLock); 
                    m_BufferPool.insert(pFrameInfo->m_pBufPtr); 
                    LeaveCriticalSection(&m_csBufferPoolLock); 
                } 
                LeaveCriticalSection(&m_csVideoListLock); 
            } 
            else 
            {   /* 
                EnterCriticalSection(&m_csVideoListLock); 
                if(m_VideoList.size() < m_ulFrameBufSize) 
                { 
                    unsigned long ulLen = ulFrameLen + m_ulIFrameHeaderLen; 
                    FrameInfo *pFrameInfo = new FrameInfo(ftMotion, HeapAlloc(m_hHeap, 0, ulLen), ulLen); 
                    memcpy(pFrameInfo->m_pBufPtr, buf, ulLen); 
                    //m_DataQueue.Read(pframe->m_acData + m_ulIFrameHeaderLen, ulFrameLen); 
                    m_VideoList.push_back(pFrameInfo); 
                } 
                LeaveCriticalSection(&m_csVideoListLock); 
                */ 
            } 
        } 
 
        if(m_bTerminate == true) 
            return ERR_TERMINATED; 
 
    }while(bGetFrame); 
 
    return NO_ANY_ERROR; 
} 
 
int rtspLinker::RecvAudioFunc() 
{ 
    unsigned char buf[RECV_BUF_SIZE]; 
    unsigned char *header; 
 
    int iRecvByte = RecvOnceFunc(m_sAudioSkt,buf,RECV_BUF_SIZE,m_ulTimeOut); 
    header = buf; 
 
    //若接收失敗則重連 
    if(iRecvByte > 12) 
    { 
        int iInterleaved = 2; 
        unsigned short usSeq_Number = header[2]*256 + header[3]; 
        if(m_RtspCheckMap.find(iInterleaved) == m_RtspCheckMap.end()) 
        { 
            m_RtspCheckMap[iInterleaved].ID = iInterleaved; 
            memcpy(m_RtspCheckMap[iInterleaved].SSRC, header+8, 4); 
            m_RtspCheckMap[iInterleaved].usSeq_Number = usSeq_Number; 
        } 
 
        //計算此封包的長度 (接收長度 = 實際封包長度 - 已接收 header - CSRC 所佔長度) 
        unsigned short usHeaderLen = 12 + (header[0]&0x0F)*4; 
        unsigned short usPacketLen = iRecvByte - usHeaderLen; 
 
        //檢查 Sequence Number,若中間有 lost 封包,則要從 I frame 開始送 
        if(m_RtspCheckMap[iInterleaved].usSeq_Number != usSeq_Number) 
        { 
            m_RtspCheckMap[iInterleaved].usSeq_Number = usSeq_Number; 
        } 
        else 
        { 
            if(m_bStartup == false) 
            { 
                EnterCriticalSection(&m_csAudioListLock); 
                if(m_AudioList.size() < m_ulFrameBufSize) 
                { 
                    FrameInfo *pFrameInfo = new FrameInfo(ftAudio, HeapAlloc(m_hHeap, 0, usPacketLen), usPacketLen); 
                    memcpy(pFrameInfo->m_pBufPtr, buf+usHeaderLen, usPacketLen); 
                    m_AudioList.push_back(pFrameInfo); 
 
                    EnterCriticalSection(&m_csBufferPoolLock); 
                    m_BufferPool.insert(pFrameInfo->m_pBufPtr); 
                    LeaveCriticalSection(&m_csBufferPoolLock); 
                } 
                LeaveCriticalSection(&m_csAudioListLock); 
            } 
        } 
        ++m_RtspCheckMap[iInterleaved].usSeq_Number; 
        return NO_ANY_ERROR; 
    } 
 
    return ERR_RECV_NODATA; 
}