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;i m_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; }