#include "receiver.h" CReceiver::CReceiver(void):m_exit(false),m_HasInit(false), m_nVideoTimeDiff(0),m_nAudioTimeDiff(0),m_bFirst(true) { m_hVideoRecvThread = NULL; m_hAudioRecvThread = NULL; m_VideoQueue = NULL; m_AudioQueue = NULL; } CReceiver::~CReceiver(void) { Uninit(); } bool CReceiver::Start(const char *url) { if(!Init()) { Uninit(); return false; } if(!Connect(url)) { m_rtsp.ReInit(); return false; } return true; } bool CReceiver::Init() { //-------Rtsp Init------// if(!m_HasInit) { WSADATA wsaData; if(WSAStartup(MAKEWORD(2,0), &wsaData) != 0) return false; m_VideoQueue = new CRtpQueue(100); if(m_VideoQueue == NULL) return false; m_AudioQueue = new CRtpQueue(100); if(m_AudioQueue == NULL) return false; if(!m_rtsp.Init()) return false; //Init video streaming data socket(udp) if(!m_video_rtp.Create(SocketUDP)) return false; if(!m_video_rtp.Bind(VIDEO_RTP_PORT)) return false; //Init video streaming data socket(udp) if(!m_audio_rtp.Create(SocketUDP)) return false; if(!m_audio_rtp.Bind(AUDIO_RTP_PORT)) return false; unsigned int nVideoThreadId,nAudioThreadId; m_hVideoRecvThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ProcessVideoRtp,(LPVOID)this,0,(LPDWORD)&nVideoThreadId); if(m_hVideoRecvThread == NULL) { //ExitThread(m_nVideoThreadId); return false; } m_hAudioRecvThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ProcessAudioRtp,(LPVOID)this,0,(LPDWORD)&nAudioThreadId); if(m_hAudioRecvThread == NULL) { //ExitThread(nThreadId2); return false; } m_HasInit = true; } return true; } void CReceiver::Uninit() { if(m_HasInit) { m_exit = true; if(m_hVideoRecvThread) { WaitForSingleObject(m_hVideoRecvThread, INFINITE); CloseHandle(m_hVideoRecvThread); m_hVideoRecvThread = NULL; } if(m_hAudioRecvThread) { WaitForSingleObject(m_hAudioRecvThread, INFINITE); CloseHandle(m_hAudioRecvThread); m_hAudioRecvThread = NULL; } m_rtsp.Uninit(); m_video_rtp.Close(); m_audio_rtp.Close(); if(m_VideoQueue != NULL) { delete m_VideoQueue; m_VideoQueue = NULL; } if(m_AudioQueue != NULL) { delete m_AudioQueue; m_AudioQueue = NULL; } WSACleanup(); m_HasInit = false; } } // void *CReceiver::ProcessVideoRtp(void *arg) { CReceiver *pPtr = (CReceiver *)arg; pPtr->ProcessVideo(); return NULL; } void *CReceiver::ProcessAudioRtp(void *arg) { CReceiver *pPtr = (CReceiver *)arg; pPtr->ProcessAudio(); return NULL; } // void CReceiver::ProcessVideo() { char buff[UDP_RECV_SIZE] = {0}; //recv_buff[32]; unsigned int len = 0; //readsocks, ret; bool bFirst = true; unsigned short nFirtSeq = 0; //First sequence number unsigned short nLastSeq = 0; unsigned short nLastDiff = 0; //Sequence num 段间差值 unsigned short diff = 0; unsigned short seqnum = 0; unsigned int nLastTimeStamp = 0; fd_set fdRead; SOCKET socket = m_video_rtp.GetSocket(); struct timeval time_out; time_out.tv_sec = 1; time_out.tv_usec = 0; while(!m_exit) { FD_ZERO(&fdRead); FD_SET(socket, &fdRead); ::select(socket+1, &fdRead, NULL, NULL, &time_out); if(FD_ISSET(socket, &fdRead)) //network ok { memset(buff,0,sizeof(buff)); len = m_video_rtp.ReceiveFrom(buff,sizeof(buff)); if(len <= 0) continue; } else continue; //------Sequence number of rtp----------// seqnum = (buff[2] << 8) | buff[3]; if(nFirtSeq == 0) { nFirtSeq = seqnum; //bFirst = false; } if(nLastSeq > 0 && (65536 + seqnum - nLastSeq) % 65536 > 20) //出现了段,计算差值 nLastDiff += (65536 + seqnum - nLastSeq - 1) % 65536; diff = (65536 + seqnum - nLastDiff - nFirtSeq) % 65536; //增量 nLastSeq = seqnum; // //Calculate difference value timestamp of rtp if(m_nVideoTimeDiff == 0) { unsigned int nTime = ntohl(*((unsigned int*)(buff + 4))); //unsigned int nTime = (buff[4] << 24) | (buff[5] << 16) | (buff[6] << 8) | buff[7]; if(nTime == 0) { continue; } if(nLastTimeStamp == 0) nLastTimeStamp = nTime; if(nLastTimeStamp != 0 && nTime > nLastTimeStamp) { m_nVideoTimeDiff = nTime - nLastTimeStamp; m_nVideoTimeDiff = (m_nVideoTimeDiff * 10000000) / 90000; } } bool ret = m_VideoQueue->PushPacket((unsigned char*)buff,len,diff); while(!ret && !m_exit) //Queue is full { Sleep(200); ret = m_VideoQueue->PushPacket((unsigned char*)buff,len,diff); } } } void CReceiver::ProcessAudio() { char buff[UDP_RECV_SIZE] = {0}; //recv_buff[32]; unsigned int len = 0; //readsocks, ret; bool bFirst = true; unsigned short nFirtSeq = 0; //First sequence number unsigned short nLastSeq = 0; unsigned short nLastDiff = 0; //Sequence num 段间差值 unsigned int nLastTimeStamp = 0; unsigned short diff = 0; unsigned short seqnum = 0; fd_set fdRead; SOCKET socket = m_audio_rtp.GetSocket(); struct timeval time_out; time_out.tv_sec = 1; time_out.tv_usec = 0; while(!m_exit) { FD_ZERO(&fdRead); FD_SET(socket, &fdRead); ::select(socket+1, &fdRead, NULL, NULL, &time_out); if(FD_ISSET(socket, &fdRead)) //network ok { memset(buff,0,sizeof(buff)); len = m_audio_rtp.ReceiveFrom(buff,sizeof(buff)); if(len <= 0) continue; } else continue; //------Sequence number of rtp----------// seqnum = (buff[2] << 8) | buff[3]; if(nFirtSeq == 0) { nFirtSeq = seqnum; } if(nLastSeq > 0 && (65536 + seqnum - nLastSeq) % 65536 > 20) //出现了段,计算差值 nLastDiff += (65536 + seqnum - nLastSeq - 1) % 65536; diff = (65536 + seqnum - nLastDiff - nFirtSeq) % 65536; //增量 nLastSeq = seqnum; // //Calculate difference value timestamp of rtp if(m_nAudioTimeDiff == 0) { //unsigned int nTime = (buff[4] << 24) | (buff[5] << 16) | (buff[6] << 8) | buff[7]; unsigned int nTime = ntohl(*((unsigned int*)(buff + 4))); if(nTime == 0) { continue; } if(nLastTimeStamp == 0) nLastTimeStamp = nTime; if(nLastTimeStamp != 0 && nTime > nLastTimeStamp) { m_nAudioTimeDiff = nTime - nLastTimeStamp; m_nAudioTimeDiff = (m_nAudioTimeDiff * 10000000) / 12000; } } bool ret = m_AudioQueue->PushPacket((unsigned char*)buff,len,diff); while(!ret && !m_exit) //Queue is full { Sleep(200); ret = m_AudioQueue->PushPacket((unsigned char*)buff,len,diff); } } } // int CReceiver::GetVideoFrame(unsigned char *pFrame,unsigned int nDataLen,unsigned int *nTimeStamp) { unsigned int nOffSet = 0; //offset of buffer int nCount = 0; if(m_nVideoTimeDiff == 0 || GetStatus() == STOPPED || GetStatus() == PAUSED) { return 0; } //Build a vop CRtpPacket *packet = NULL; *nTimeStamp = 0; while(1) { packet = m_VideoQueue->GetReadPacket(); if(packet == NULL) { Sleep(50); packet = m_VideoQueue->GetNextPacket(); if(packet == NULL) { if(GetStatus() == STOPPED) break; else continue; } } //parse rtp packet packet->ParseRawData(); //时间戳与上一个不同,则认为是另一个VOP if(*nTimeStamp != 0 && *nTimeStamp != packet->m_TimeStamp) { //重置包位置 m_VideoQueue->ReSetReadPacket(); break; } *nTimeStamp = packet->m_TimeStamp; if(m_bFirst) { memcpy(pFrame + nOffSet,packet->m_payload,packet->m_PayloadLength); nOffSet += packet->m_PayloadLength; m_bFirst = false; } else { memcpy(pFrame + nOffSet,packet->m_payload,packet->m_PayloadLength); nOffSet += packet->m_PayloadLength; } //标志位为1:这是VOP的最后一个(或仅有一个)RTP包 if(packet->m_HasMarker) break; } return nOffSet; } int CReceiver::GetAudioFrame(unsigned char *pFrame,unsigned int nDataLen,unsigned int *nTimeStamp) { unsigned int nOffSet = 0; //offset of buffer int nCount = 0; if(m_nAudioTimeDiff == 0 || GetStatus() == STOPPED || GetStatus() == PAUSED) { return 0; } //Build a audio frame CRtpPacket *packet = NULL; *nTimeStamp = 0; while(1) { packet = m_AudioQueue->GetReadPacket(); if(packet == NULL) { Sleep(50); packet = m_AudioQueue->GetNextPacket(); if(packet == NULL) { if(GetStatus() == STOPPED) break; else continue; } } //parse rtp packet packet->ParseRawData(); //时间戳与上一个不同,则认为是另一个 if(*nTimeStamp != 0 && *nTimeStamp != packet->m_TimeStamp) { //重置包位置 m_VideoQueue->ReSetReadPacket(); break; } *nTimeStamp = packet->m_TimeStamp; memcpy(pFrame + nOffSet,packet->m_payload+1,packet->m_PayloadLength-1); nOffSet += packet->m_PayloadLength; //标志位为1:这是最后一个(或仅有一个)RTP包 if(packet->m_HasMarker) break; } return nOffSet; } //Start to play a program bool CReceiver::Connect(const char *url) { if(m_rtsp.GetStatus() == PLAYING || m_rtsp.GetStatus() == PAUSE) return true; int ret = -1; //m_VideoQueue->QueueFlush(); //------send describe to server---------// m_rtsp.m_ssclient.cmd = DESCRIBE; m_rtsp.m_ssclient.multiple = 1; m_rtsp.m_ssclient.rtspmsg_seqno = 1; strncpy(m_rtsp.m_ssclient.url, url,sizeof(m_rtsp.m_ssclient.url) - 1); ret = sscanf(m_rtsp.m_ssclient.url, "rtsp://%[^:]:%d/", m_rtsp.m_ssclient.server_ip, &(m_rtsp.m_ssclient.server_port)); if (ret != 2) return false; RTSPMSG msg; memset(&msg,0,sizeof(RTSPMSG)); //build describe rtsp message if((ret = m_rtsp.BuildRtspMsg(&msg)) != 0) return false; //send describe request to server if(!m_rtsp.SendRequest(&msg)) return false; //process response if((ret = m_rtsp.ProcessResponse()) < 0) { /*switch(ret) { case: }*/ return false; } return true; } //Start to play a program bool CReceiver::Play() { int ret = -1; if(m_rtsp.GetStatus() == STOPPED) { m_VideoQueue->QueueFlush(); //------send describe to server---------// m_rtsp.m_ssclient.cmd = PLAY; m_rtsp.m_ssclient.multiple = 1; } else if(m_rtsp.GetStatus() == PAUSED) { m_rtsp.m_ssclient.cmd = PLAY; } else return true; RTSPMSG msg; memset(&msg,0,sizeof(RTSPMSG)); //build video setup rtsp message if((ret = m_rtsp.BuildRtspMsg(&msg)) != 0) return false; //send setup request to server if(!m_rtsp.SendRequest(&msg)) return false; //process response if((ret = m_rtsp.ProcessResponse()) < 0) { /*switch(ret) { case: }*/ return false; } return true; } // bool CReceiver::Pause() { if(m_rtsp.GetStatus() != PLAYING) return true; int ret = -1; m_rtsp.m_ssclient.cmd = PAUSE; RTSPMSG msg; if((ret = m_rtsp.BuildRtspMsg(&msg)) != 0) return false; //send pause request to server if(!m_rtsp.SendRequest(&msg)) return false; //process response if((ret = m_rtsp.ProcessResponse()) < 0) { /*switch(ret) { case: }*/ return false; } return true; } // bool CReceiver::ConPlay() // { // int ret = -1; // m_rtsp.m_ssclient.cmd = PLAY; // // RTSPMSG msg; // if((ret = m_rtsp.BuildRtspMsg(&msg)) != 0) // return false; // // //send play request to server // if(!m_rtsp.SendRequest(&msg)) // return false; // // //process response // if((ret = m_rtsp.ProcessResponse()) != 0) // { // /*switch(ret) // { // case: // }*/ // return false; // } // // return true; // } bool CReceiver::Stop() { if(m_rtsp.GetStatus() == STOPPED) return true; int ret = -1; m_rtsp.m_ssclient.cmd = TEARDOWN; RTSPMSG msg; if((ret = m_rtsp.BuildRtspMsg(&msg)) != 0) return false; //send teardown request to server if(!m_rtsp.SendRequest(&msg)) return false; //process response if((ret = m_rtsp.ProcessResponse()) < 0) { /*switch(ret) { case: }*/ return false; } return true; } // void CReceiver::Exit() { Uninit(); } void CReceiver::GetCodeType(char *VideoType,unsigned short VideoLen,char *AudioType,unsigned short AudioLen) { if(VideoType == NULL || AudioType == NULL) return; memcpy(VideoType,m_rtsp.m_ssclient.video_type,VideoLen-1); memcpy(AudioType,m_rtsp.m_ssclient.audio_type,AudioLen-1); return; } void CReceiver::GetFrameSize(int *width,int *height) { *width = m_rtsp.m_ssclient.video_width; *height = m_rtsp.m_ssclient.video_height; } #ifndef _Receiver_H #define _Receiver_H #include "rtsp.h" #include "Queue.h" // class CReceiver { public: CReceiver(void); virtual ~CReceiver(void); static void* ProcessVideoRtp(void *arg); static void* ProcessAudioRtp(void *arg); //Function public: bool Start(const char *url); bool Play(); bool Pause(); //bool ConPlay(); bool Stop(); void Exit(); SSC_STATE GetStatus(){ return m_rtsp.GetStatus();} void GetCodeType(char *VideoType,unsigned short VideoLen,char *AudioType,unsigned short AudioLen); void GetFrameSize(int *width,int *height); int GetVideoFrame(unsigned char *pFrame,unsigned int nDataLen,unsigned int *nTimeStamp); int GetAudioFrame(unsigned char *pFrame,unsigned int nDataLen,unsigned int *nTimeStamp); private: bool Init(); void Uninit(); bool Connect(const char *url); void ProcessVideo(); void ProcessAudio(); //Data public: CRtsp m_rtsp; //rstp object CMessageSocket m_video_rtp; //rtp socket for video streaming data CMessageSocket m_audio_rtp; //rtp socket for audio streaming data CRtpQueue *m_VideoQueue; CRtpQueue *m_AudioQueue; HANDLE m_hVideoRecvThread; HANDLE m_hAudioRecvThread; bool m_exit; bool m_HasInit; unsigned __int64 m_nVideoTimeDiff; //视频帧间隔时间 unsigned __int64 m_nAudioTimeDiff; // unsigned int m_nTimeStamp; bool m_bFirst; }; #endif #include "rtsp.h" // CRtsp::CRtsp(void) { } CRtsp::~CRtsp(void) { } bool CRtsp::Init() { memset(&m_ssclient,0,sizeof(SSC)); m_ssclient.state = STOPPED; m_ssclient.rtspmsg_seqno = 0; //Init rtsp socket(tcp) if(!m_socket.Create(SocketTCP)) { printf("-----Create rtsp socket failed!-------/n"); return false; } // if(!m_socket.Bind(LOCAL_RTSP_PORT)) // return false; if(!GetHostIP(&(m_ssclient.local_nip))) return false; return true; } // void CRtsp::Uninit() { //close rtsp socket(tcp) m_socket.Close(); } // void CRtsp::ReInit() { //close rtsp socket(tcp) m_socket.Close(); Init(); } // bool CRtsp::SendRequest(RTSPMSG *msg) { char buf[SEND_LEN] = {0}; int ret, len; if(m_ssclient.ppStr[0] == '/0') strcpy(m_ssclient.ppStr,"test"); memset(buf, 0, sizeof(buf)); len = m_RtspEncode.sv_rtsp_encode(msg,buf,sizeof(buf),m_ssclient.ppStr); if(len > 0) { ret = m_socket.Send(buf, len); if(ret > 0) { //LOG("[OK] tcp send %s:%d:/n%s/n",inet_ntoa(fd_struct->dest.sin_addr), / //ntohs(fd_struct->dest.sin_port), buf); } else return false; } else { printf("encode error/n"); return false; } return true; } int CRtsp::ProcessResponse() { char psRecvBuff[RECE_LEN] = {0}; int ret = -1; fd_set fdRead; SOCKET socket = m_socket.GetSocket(); struct timeval time_out; time_out.tv_sec = 5; time_out.tv_usec = 0; while(1) { FD_ZERO(&fdRead); FD_SET(socket, &fdRead); ret = ::select(socket+1, &fdRead, NULL, NULL, &time_out); if(ret <= 0) //network error { //printf("........Can't receive rtsp response message......./n"); return -1; } else if(FD_ISSET(socket, &fdRead)) //network ok { int len = 0; memset(psRecvBuff,0,sizeof(psRecvBuff)); if((len = m_socket.Receive(psRecvBuff,RECE_LEN)) <= 0) { //printf("........Can't receive rtsp response message......./n"); return -1; } } ret = ParseRtspMsg(psRecvBuff); if(ret != 1) return ret; else continue; } return 0; } // // int CRtsp::BuildDescribeMsg(RTSPMSG *msg) { int ret = -1; int nCount = 0; //connect the server //ret = m_socket.Connect(m_ssclient.server_ip, m_ssclient.server_port); while(ret != 0) { ret = m_socket.Connect(m_ssclient.server_ip, m_ssclient.server_port); if(ret == 0) break; if(++nCount > 5) return -1; else Sleep(1); } if(!m_socket.SetNonBlock()) return -1; //---build rtsp msg----// msg->msg_id = RTSP_DESCRIBE; strncpy(msg->url,m_ssclient.url,sizeof(msg->url)-1); msg->seqno = m_ssclient.rtspmsg_seqno; m_ssclient.last_msg_id = msg->msg_id; return 0; } // int CRtsp::BuildOptionMsg(RTSPMSG *msg) { int ret = 0; //connect the server ret = m_socket.Connect(m_ssclient.server_ip, m_ssclient.server_port); if(ret != 0) { return CONNECT_SS_FAIL; } //---build rtsp msg----// msg->msg_id = RTSP_OPTIONS; strncpy(msg->url,m_ssclient.url,sizeof(msg->url)-1); msg->seqno = m_ssclient.rtspmsg_seqno; m_ssclient.last_msg_id = msg->msg_id; return 0; } // void CRtsp::BuildVideoSetupMsg(RTSPMSG *msg) { int ret = 0; //---build rtsp msg----// msg->msg_id = RTSP_VIDEO_SETUP; strncpy(msg->url,m_ssclient.url,sizeof(msg->url)-1); msg->setup.id = m_ssclient.video_track; msg->setup.transport.prot = PROT_RTP; msg->setup.transport.multicast = 0; msg->setup.transport.dest_valid = 0; msg->setup.transport.dest.sin_family = AF_INET; msg->setup.transport.dest.sin_addr.s_addr = m_ssclient.local_nip; msg->setup.transport.dest.sin_port = htons(VIDEO_RTP_PORT); msg->seqno = (++m_ssclient.rtspmsg_seqno); m_ssclient.last_msg_id = msg->msg_id; } // void CRtsp::BuildAudioSetupMsg(RTSPMSG *msg) { int ret = 0; //---build rtsp msg----// msg->msg_id = RTSP_AUDIO_SETUP; msg->session_id = m_ssclient.session_id; strncpy(msg->url,m_ssclient.url,sizeof(msg->url)-1); msg->setup.id = m_ssclient.audio_track; msg->setup.transport.prot = PROT_RTP; msg->setup.transport.multicast = 0; msg->setup.transport.dest_valid = 0; msg->setup.transport.dest.sin_family = AF_INET; msg->setup.transport.dest.sin_addr.s_addr = m_ssclient.local_nip; msg->setup.transport.dest.sin_port = htons(AUDIO_RTP_PORT); msg->seqno = (++m_ssclient.rtspmsg_seqno); m_ssclient.last_msg_id = msg->msg_id; } // void CRtsp::BuildPlayMsg(RTSPMSG *msg) { msg->msg_id = RTSP_PLAY; strncpy(msg->url,m_ssclient.url,sizeof(msg->url)-1); msg->play.range_valid = 1; msg->session_id = m_ssclient.session_id; msg->seqno = (++m_ssclient.rtspmsg_seqno); m_ssclient.last_msg_id = msg->msg_id; } //Build Rtsp message int CRtsp::BuildRtspMsg(RTSPMSG *msg) { if(msg == NULL) return -1; int ret; if(m_ssclient.cmd == DESCRIBE && m_ssclient.multiple == 1 && m_ssclient.state == STOPPED) { //DESCRIBE ret = BuildDescribeMsg(msg); return ret; } else if(m_ssclient.cmd == PLAY && m_ssclient.multiple == 1 && m_ssclient.state == STOPPED) { //Setup if(m_ssclient.video_track > 0) { BuildVideoSetupMsg(msg); } else if(m_ssclient.audio_track > 0) { BuildAudioSetupMsg(msg); } } else if(m_ssclient.cmd == PLAY && m_ssclient.multiple == 1 && / (m_ssclient.state == TRICKING || m_ssclient.state == PAUSED)) { //Continue PLAY msg->msg_id = RTSP_PLAY; strncpy(msg->url,m_ssclient.url,sizeof(msg->url)-1); msg->play.range_valid = 0; msg->session_id = m_ssclient.session_id; msg->seqno = (++m_ssclient.rtspmsg_seqno); } else if(m_ssclient.cmd == TRICK && m_ssclient.multiple != 1 && m_ssclient.state != STOPPED) { //Trick msg->msg_id = RTSP_PLAY; strncpy(msg->url,m_ssclient.url,sizeof(msg->url)-1); msg->session_id = m_ssclient.session_id; msg->play.scale = 1024*(m_ssclient.multiple); msg->seqno = (++m_ssclient.rtspmsg_seqno); } else if((m_ssclient.cmd == PAUSE || m_ssclient.cmd == TEARDOWN) /*&& m_ssclient.state != STOPPED*/) { //PUASE or TEARDOWN (m_ssclient.cmd == PAUSE)?(msg->msg_id = RTSP_PAUSE):(msg->msg_id = RTSP_TEARDOWN); strncpy(msg->url,m_ssclient.url,sizeof(msg->url)-1); msg->session_id = m_ssclient.session_id; msg->seqno = (++m_ssclient.rtspmsg_seqno); } m_ssclient.last_msg_id = msg->msg_id; return 0; } bool CRtsp::GetHostIP(unsigned int *nip) { char name[155] = {0}; PHOSTENT hostinfo; if(::gethostname(name,sizeof(name)) == 0) { if((hostinfo = ::gethostbyname(name)) != NULL) { //获得IP char *ip = NULL; ip = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list); printf("%s/n",ip); *nip = *(unsigned int *)*hostinfo->h_addr_list; } } return true; } // int CRtsp::ParseRtspMsg(char *buff) { if(buff == NULL) return -1; int ret = 0; RTSPMSG resp; RTSPMSG reqmsg; //解析RTSP回应消息 if(m_RtspDecode.sv_rtsp_decode_response(buff,&resp) != 0) { return CONTENT_OVER; } //printf("---TCP recv:/n%s/n",buff); ret = resp.response.retcode; //响应码 if (resp.msg_id == RTSP_EX_RESPONSE && m_ssclient.rtspmsg_seqno == resp.seqno / && m_ssclient.last_msg_id == RTSP_OPTIONS) { switch (ret) { case RTSPR_OK: memset(&reqmsg, 0, sizeof(reqmsg)); //------send describe rtsp msg to server-------// BuildDescribeMsg(&reqmsg); if(!SendRequest(&reqmsg)) return -1; return 1; break; case RTSPR_CONTINUE: return 1; break; default: return ret; break; } } if (resp.msg_id == RTSP_EX_RESPONSE && m_ssclient.rtspmsg_seqno == resp.seqno / && m_ssclient.last_msg_id == RTSP_DESCRIBE) { switch (ret) { case RTSPR_OK: memset(&reqmsg, 0, sizeof(reqmsg)); m_RtspDecode.sv_rtsp_decode_sdp(buff,&reqmsg.response.sdp); //Codec type memcpy(m_ssclient.video_type,reqmsg.response.sdp.video_type,sizeof(m_ssclient.video_type) -1); memcpy(m_ssclient.audio_type,reqmsg.response.sdp.audio_type,sizeof(m_ssclient.audio_type) -1); //Track m_ssclient.video_track = reqmsg.response.sdp.video_track; m_ssclient.audio_track = reqmsg.response.sdp.audio_track; //Size m_ssclient.video_width = reqmsg.response.sdp.video_width; m_ssclient.video_height = reqmsg.response.sdp.video_height; return 0; break; case RTSPR_CONTINUE: return 1; break; default: return ret; break; } } else if (resp.msg_id == RTSP_EX_RESPONSE && m_ssclient.rtspmsg_seqno == resp.seqno / && m_ssclient.last_msg_id == RTSP_VIDEO_SETUP) { switch (ret) { case RTSPR_OK: m_ssclient.session_id = resp.session_id; m_ssclient.server_rtp_port = ntohs(resp.response.transport.src.sin_port); //------send audio setup rtsp msg to server-------// memset(&reqmsg, 0, sizeof(reqmsg)); if(m_ssclient.audio_track > 0) { BuildAudioSetupMsg(&reqmsg); if(!SendRequest(&reqmsg)) return -1; } else { BuildPlayMsg(&reqmsg); if(SendRequest(&reqmsg)) return -1; } return 1; break; case RTSPR_TEMP_MOVE: //重定向到SH,default 5554 端口 ret = sscanf (resp.url, "rtsp://%[^:]:%d", m_ssclient.server_ip, &m_ssclient.server_port); if (ret != 2) { printf("got REDIRECT, but url /"%s/" is wrong!/n", resp.url); return -2; } //if (g_ss_rtsp != NULL) sock_close(g_ss_rtsp); /*g_ss_rtsp = sock_init(SOCK_TCP, 0, m_ssclient.ss_ip, m_ssclient.ss_msg_port); ssclient_assert(g_ss_rtsp != NULL); memset(&reqmsg, 0, sizeof(reqmsg)); build_setup_rtspmsg(&reqmsg); ret = send_to_ss(g_ss_rtsp, &reqmsg);*/ return 1; break; case RTSPR_CONTINUE: return 1; break; default: return ret; break; } } else if (resp.msg_id == RTSP_EX_RESPONSE && m_ssclient.rtspmsg_seqno == resp.seqno / && m_ssclient.last_msg_id == RTSP_AUDIO_SETUP) { switch (ret) { case RTSPR_OK: //------send play rtsp msg to server-------// m_ssclient.session_id = resp.session_id; memset(&reqmsg, 0, sizeof(reqmsg)); BuildPlayMsg(&reqmsg); SendRequest(&reqmsg); return 1; case RTSPR_TEMP_MOVE: //重定向到SH,default 5554 端口 ret = sscanf (resp.url, "rtsp://%[^:]:%d", m_ssclient.server_ip, &m_ssclient.server_port); if (ret != 2) { printf("got REDIRECT, but url /"%s/" is wrong!/n", resp.url); return -2; } //if (g_ss_rtsp != NULL) sock_close(g_ss_rtsp); /*g_ss_rtsp = sock_init(SOCK_TCP, 0, m_ssclient.ss_ip, m_ssclient.ss_msg_port); ssclient_assert(g_ss_rtsp != NULL); memset(&reqmsg, 0, sizeof(reqmsg)); build_setup_rtspmsg(&reqmsg); ret = send_to_ss(g_ss_rtsp, &reqmsg);*/ return 1; break; case RTSPR_CONTINUE: return 1; break; default: return ret; break; } } else if (resp.msg_id == RTSP_EX_RESPONSE && m_ssclient.rtspmsg_seqno == resp.seqno && ret == RTSPR_OK) { if(m_ssclient.last_msg_id == RTSP_PLAY) { if (m_ssclient.multiple == 1) { m_ssclient.state = PLAYING; } else { m_ssclient.state = TRICKING; } } else if (m_ssclient.last_msg_id == RTSP_PAUSE) { m_ssclient.state = PAUSED; } else if (m_ssclient.last_msg_id == RTSP_TEARDOWN) { m_ssclient.state = STOPPED; } return 0; } else if (resp.msg_id == RTSP_ANNOUNCE) { ///TODO: notify player END return 2; } else if (resp.msg_id == RTSP_EX_RESPONSE && m_ssclient.rtspmsg_seqno == resp.seqno / && ret != RTSPR_OK && ret != RTSPR_CONTINUE) { return -1; } else { return -1; } return 0; } #ifndef _RTSP_H #define _RTSP_H #include "datatype.h" #include "MessageSocket.h" #include "RtspDecode.h" #include "RtspEncode.h" #define RECE_LEN 2048 #define SEND_LEN 1024 // class CRtsp { public: CRtsp(void); virtual ~CRtsp(void); bool Init(); void Uninit(); void ReInit(); //Function public: bool SendRequest(RTSPMSG *msg); int ProcessResponse(); int BuildRtspMsg(RTSPMSG *msg); SSC_STATE GetStatus(){ return m_ssclient.state;} SOCKET GetSocket() { return m_socket.GetSocket();} private: int BuildOptionMsg(RTSPMSG *msg); int BuildDescribeMsg(RTSPMSG *msg); void BuildVideoSetupMsg(RTSPMSG *msg); void BuildAudioSetupMsg(RTSPMSG *msg); void BuildPlayMsg(RTSPMSG *msg); int ParseRtspMsg(char *buff); bool GetHostIP(unsigned int *nip); //Data public: CMessageSocket m_socket; SSC m_ssclient; CRtspDecode m_RtspDecode; CRtspEncode m_RtspEncode; }; #endif // RtspClientFilter.cpp : 定义 DLL 应用程序的入口点。 // #include "RtspClientFilter.h" #include <initguid.h> #include "FilterGuid.h" #include <olectl.h> #pragma warning(disable:4710) // 'function': function not inlined (optimzation) const AMOVIESETUP_MEDIATYPE m_sudType[] = { { &MEDIATYPE_Video, &MEDIASUBTYPE_NULL // wild card }, { &MEDIATYPE_Audio, &MEDIASUBTYPE_NULL }, }; const AMOVIESETUP_PIN m_sudPin[] = { { L"Video", // pin name FALSE, // is rendered? TRUE, // is output? FALSE, // zero instances allowed? FALSE, // many instances allowed? &CLSID_NULL, // connects to filter (for bridge pins) NULL, // connects to pin (for bridge pins) 1, // count of registered media types &m_sudType[0] // list of registered media types }, { L"Audio", // pin name FALSE, // is rendered? TRUE, // is output? FALSE, // zero instances allowed? FALSE, // many instances allowed? &CLSID_NULL, // connects to filter (for bridge pins) NULL, // connects to pin (for bridge pins) 1, // count of registered media types &m_sudType[1] // list of registered media types } }; const AMOVIESETUP_FILTER m_sudFilter = { &CLSID_RtspFilter, // filter clsid L"Headware Rtsp Filter", // filter name MERIT_DO_NOT_USE, // Filter merit 2, // count of registered pins m_sudPin // list of pins to register }; CFactoryTemplate g_Templates[] = { { L"Headware Rtsp Filter", &CLSID_RtspFilter, CRtspFilter::CreateInstance, NULL, &m_sudFilter } }; int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); // STDAPI DllRegisterServer() { HRESULT hr = AMovieDllRegisterServer2(true); return hr; } STDAPI DllUnregisterServer() { HRESULT hr = AMovieDllRegisterServer2(false); return hr; } // // DllEntryPoint extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID); BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) { return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved); } ///CRtspFilter/ // CreateInstance CUnknown * WINAPI CRtspFilter::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr) { ASSERT(phr); CUnknown *punk = new CRtspFilter(lpunk, phr); if(punk == NULL) { if(phr) *phr = E_OUTOFMEMORY; } return punk; } CRtspFilter::CRtspFilter(LPUNKNOWN lpunk, HRESULT *phr) : CSource(NAME("Headware Rtsp Filter"), lpunk, CLSID_RtspFilter) { ASSERT(phr); CAutoLock cAutoLock(&m_cStateLock); m_paStreams = (CSourceStream **) new CFilterOutputPin*[2]; if(m_paStreams == NULL) { if(phr) *phr = E_OUTOFMEMORY; return; } m_paStreams[0] = new CFilterOutputPin(phr, this, L"Video"); if(m_paStreams[0] == NULL) { if(phr) *phr = E_OUTOFMEMORY; return; } m_paStreams[1] = new CFilterOutputPin(phr, this, L"Audio"); if(m_paStreams[1] == NULL) { if(phr) *phr = E_OUTOFMEMORY; return; } // HRESULT hr = Start("rtsp://192.168.0.42:5554/txzp_64_mp4_aac.3gp"); // if(SUCCEEDED(hr)) // return; // else // return; } CRtspFilter::~CRtspFilter() { StopStream(); m_recv.Exit(); } //Basic COM - used here to reveal our own interfaces STDMETHODIMP CRtspFilter::NonDelegatingQueryInterface(REFIID riid, void ** ppv) { CheckPointer(ppv, E_POINTER); if (riid == IID_IRtspReceiver) { return GetInterface((IRtspReceiver *) this, ppv); } else { return CSource::NonDelegatingQueryInterface(riid, ppv); } } // int CRtspFilter::GetVideoFrame(unsigned char *pFrame,unsigned int nDataLen,unsigned int *nTimeStamp) { if(pFrame == NULL) return 0; return m_recv.GetVideoFrame(pFrame,nDataLen,nTimeStamp); } int CRtspFilter::GetAudioFrame(unsigned char *pFrame,unsigned int nDataLen,unsigned int *nTimeStamp) { if(pFrame == NULL) return 0; return m_recv.GetAudioFrame(pFrame,nDataLen,nTimeStamp); } STDMETHODIMP CRtspFilter::Run(REFERENCE_TIME tStart) { CAutoLock lck(&m_cStateLock); HRESULT hr = Play(); //Play return CSource::Run(tStart); } STDMETHODIMP CRtspFilter::Pause() { CAutoLock lck(&m_cStateLock); HRESULT hr = NOERROR; if (m_State == State_Paused) { // (This space left deliberately blank) } else { if (m_State == State_Stopped) { hr = Play(); //Play // wfd = NULL; // wfd = fopen("./TransFormer_video.es", "wb"); // if(wfd == NULL) // printf("fopen error"); // else // printf("fopen ok"); } else if (m_State == State_Running) { hr = PauseStream(); //Pause } if (SUCCEEDED(hr)) { hr = CSource::Pause(); } } return hr; } STDMETHODIMP CRtspFilter::Stop() { CAutoLock lck1(&m_cStateLock); StopStream(); //Stop receive stream HRESULT hr = CSource::Stop(); return hr; } // HRESULT CRtspFilter::StartStream(const char *url) { if(m_recv.Start(url)) { //Set codec type char sVideoType[20] = {0}; char sAudioType[20] = {0}; int x,y; m_recv.GetCodeType(sVideoType,sizeof(sVideoType),sAudioType,sizeof(sAudioType)); m_recv.GetFrameSize(&x,&y); //Video Pin CFilterOutputPin *OutPin = (CFilterOutputPin*)m_paStreams[0]; if(OutPin) { OutPin->m_pType.SetCodeType(sVideoType); OutPin->m_pType.SetFrameSize(x,y); } //Audio Pin OutPin = (CFilterOutputPin*)m_paStreams[1]; if(OutPin) OutPin->m_pType.SetCodeType(sAudioType); //m_bCanConnect = true; return NOERROR; } else return E_FAIL; } HRESULT CRtspFilter::PauseStream() { if(m_recv.Pause()) return NOERROR; else return E_FAIL; } HRESULT CRtspFilter::PlayStream() { if(m_recv.Play()) return NOERROR; else return E_FAIL; } HRESULT CRtspFilter::StopStream() { if(m_recv.Stop()) { //m_bCanConnect = false; return NOERROR; } else return E_FAIL; } //---------INetReceiver methods----------// // STDMETHODIMP CRtspFilter::Start(const char *url) { return StartStream(url); } STDMETHODIMP CRtspFilter::Exit(void) { m_recv.Exit(); return NOERROR; } STDMETHODIMP CRtspFilter::Play() { return PlayStream(); } //CFilterOutputPin/// // Constructor CFilterOutputPin::CFilterOutputPin(HRESULT *phr, CRtspFilter *pParent, LPCWSTR pPinName) : CSourceStream(NAME("Output Pin"),phr, pParent, pPinName), m_rtSampleTime(0),m_first(true) { ASSERT(phr); ASSERT(pParent); CAutoLock cAutoLock(&m_cSharedState); m_pParentFilter = pParent; } // Destructor CFilterOutputPin::~CFilterOutputPin() { //CAutoLock cAutoLock(&m_cSharedState); m_pParentFilter = NULL; } // HRESULT CFilterOutputPin::SetType(const char *psType) { CheckPointer(psType,E_POINTER); m_pType.SetCodeType(psType); return NOERROR; } // HRESULT CFilterOutputPin::SetFrameSize(unsigned short nWidth,unsigned short nHeight) { m_pType.SetFrameSize(nWidth,nHeight); return NOERROR; } // FillBuffer HRESULT CFilterOutputPin::FillBuffer(IMediaSample *pms) { CheckPointer(pms,E_POINTER); //ASSERT(m_Ball); BYTE *pData = NULL; long lDataLen = 0; long lActualDataSize = 0; pms->GetPointer(&pData); lDataLen = pms->GetSize(); ZeroMemory(pData, lDataLen); CAutoLock cAutoLockShared(&m_cSharedState); if(m_pParentFilter) { unsigned int nTimeStamp = 0; if(m_pType.IsVideo()) lActualDataSize = m_pParentFilter->GetVideoFrame(pData,lDataLen,&nTimeStamp); else lActualDataSize = m_pParentFilter->GetAudioFrame(pData,lDataLen,&nTimeStamp); if(lActualDataSize > 0) { //fwrite(pData, 1, lActualDataSize, m_pParentFilter->wfd); //fwrite("/n/n/n/n", 1, 4, m_pParentFilter->wfd); pms->SetActualDataLength(lActualDataSize); REFERENCE_TIME tSampleStart = m_rtSampleTime; //if (tSampleStart < 0) //pms->SetPreroll(true); REFERENCE_TIME tSampleEnd = 0; if(m_pType.IsVideo()) tSampleEnd = tSampleStart + m_pParentFilter->m_recv.m_nVideoTimeDiff;//(m_pParentFilter->m_recv.m_nVideoTimeDiff * UNITS)/90000; else tSampleEnd = tSampleStart + m_pParentFilter->m_recv.m_nAudioTimeDiff; m_rtSampleTime = tSampleEnd; pms->SetTime(&tSampleStart, &tSampleEnd); } else Sleep(200); } return NOERROR; } // Notify : STDMETHODIMP CFilterOutputPin::Notify(IBaseFilter * pSender, Quality q) { UNREFERENCED_PARAMETER(pSender); CAutoLock lock(&m_cSharedState); m_tLate = q.Late; return S_OK; } // GetMediaType HRESULT CFilterOutputPin::GetMediaType(int iPosition, CMediaType *pmt) { CheckPointer(pmt,E_POINTER); if (m_pType.GetType(pmt, iPosition)) return S_OK; return VFW_S_NO_MORE_ITEMS; } // CheckMediaType HRESULT CFilterOutputPin::CheckMediaType(const CMediaType *pMediaType) { CheckPointer(pMediaType,E_POINTER); CMediaType mtTrack; int idx = 0; while(m_pType.GetType(&mtTrack, idx++)) { if (*pMediaType == mtTrack) return S_OK; } return S_FALSE; } // DecideBufferSize HRESULT CFilterOutputPin::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProperties) { CheckPointer(pAlloc,E_POINTER); CheckPointer(pProperties,E_POINTER); CAutoLock cAutoLock(m_pFilter->pStateLock()); if(m_pType.IsVideo()) { pProperties->cbBuffer = 1500 * 5; pProperties->cBuffers = 30; } else { pProperties->cbBuffer = 1500; pProperties->cBuffers = 30; } ALLOCATOR_PROPERTIES propActual; return pAlloc->SetProperties(pProperties, &propActual); } // SetMediaType HRESULT CFilterOutputPin::SetMediaType(const CMediaType *pMediaType) { //CAutoLock cAutoLock(m_pFilter->pStateLock()); HRESULT hr = CSourceStream::SetMediaType(pMediaType); if (SUCCEEDED(hr)) { if (!m_pType.SetType(pMediaType)) hr = VFW_E_TYPE_NOT_ACCEPTED; return NOERROR; } return hr; } // OnThreadCreate // As we go active reset the stream time to zero HRESULT CFilterOutputPin::OnThreadCreate() { CAutoLock cAutoLockShared(&m_cSharedState); m_rtSampleTime = 0; // if(m_first) // { // m_pParentFilter->Play(); // m_first = false; // } // we need to also reset the repeat time in case the system // clock is turned off after m_iRepeatTime gets very big return NOERROR; } #ifndef _RtspFilter_H #define _RtspFilter_H #include "ElemType.h" #include "receiver.h" #include "IRtspReceiver.h" // class CRtspFilter : public CSource,public IRtspReceiver { private: // It is only allowed to to create these objects with CreateInstance CRtspFilter(LPUNKNOWN lpunk, HRESULT *phr); ~CRtspFilter(); DECLARE_IUNKNOWN; public: // The only allowed way to create Bouncing balls! static CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr); int GetVideoFrame(unsigned char *pFrame,unsigned int nDataLen,unsigned int *nTimeStamp); int GetAudioFrame(unsigned char *pFrame,unsigned int nDataLen,unsigned int *nTimeStamp); protected: HRESULT StartStream(const char *url); HRESULT PauseStream(void); HRESULT PlayStream(void); HRESULT StopStream(void); public: // Basic COM - used here to reveal our own interfaces STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); STDMETHODIMP Run(REFERENCE_TIME tStart); STDMETHODIMP Pause(); STDMETHODIMP Stop(); //----INetReceiver methods----// STDMETHODIMP Start(const char *url); STDMETHODIMP Exit(void); STDMETHODIMP Play(void); public: CReceiver m_recv; //bool m_bCanConnect; FILE *wfd; }; // class CFilterOutputPin : public CSourceStream { public: CFilterOutputPin(HRESULT *phr, CRtspFilter *pParent, LPCWSTR pPinName); ~CFilterOutputPin(); // HRESULT SetType(const char *psType); HRESULT SetFrameSize(unsigned short nWidth,unsigned short nHeight); // video frame HRESULT FillBuffer(IMediaSample *pms); // Ask for buffers of the size appropriate to the agreed media type HRESULT DecideBufferSize(IMemAllocator *pIMemAlloc, ALLOCATOR_PROPERTIES *pProperties); // Set the agreed media type HRESULT SetMediaType(const CMediaType *pMediaType); HRESULT CheckMediaType(const CMediaType *pMediaType); HRESULT GetMediaType(int iPosition, CMediaType *pmt); // Resets the stream time to zero HRESULT OnThreadCreate(void); // Quality control notifications sent to us STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); public: CCritSec m_cSharedState; // REFERENCE_TIME m_rtSampleTime; // The time stamp for each sample ElementaryType m_pType; REFERENCE_TIME m_tLate; private: CRtspFilter *m_pParentFilter; bool m_first; }; #endif #ifndef __H_DATATYPE__ #define __H_DATATYPE__ #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <stdarg.h> #include <string.h> #include "io.h" #include "sv_rtsp.h" /************************************************************************************ MACRO define ************************************************************************************/ #define VIDEO_RTP_PORT 4320 //local video rtp port #define AUDIO_RTP_PORT 4322 //local audio rtp port #define LOCAL_RTSP_PORT 1234 //local rtsp port #define UDP_RECV_SIZE 1500 /*UDP received stream data buffer size*/ /************************************************************************************ enum define ************************************************************************************/ typedef enum { OPTIONS = 0, DESCRIBE, PLAY, PAUSE, TRICK, TEARDOWN }SSC_CMD; typedef enum { STOPPED = 0, PLAYING, PAUSED, TRICKING }SSC_STATE; /******************************************************************************************************** error code ********************************************************************************************************/ enum { PROGRAM_NOT_EXIT = -2 , WRONG_XML_MSG = 1000, CONNECT_SS_FAIL, BUILD_RTSPMSG_FAIL, CONTENT_OVER, PEER_CLOSE_SOCK, RECEIVE_SS_ERROR, GET_PASSPORT_ERROR, PP_XML_CODE_WRONG, RICH_MEDIA }; enum { NORMALLY_PLAY_METHOD = 0 , DOWNLOAD_PLAY_METHOD } ; // typedef struct _RTSP_INFO { SSC_STATE state; /*ss_client in state*/ /*play relative*/ char url[256]; char server_ip[16]; //server ip int server_port; //server rtsp port unsigned int local_nip; int rtspmsg_seqno; int multiple; SSC_CMD cmd; char ppStr[SV_MAX_PASSPORT_LEN]; __int64 session_id; int last_msg_id; /*SETUP/PLAY/PAUSE/TEARDOWN*/ int play_type ; unsigned short server_rtp_port; //server rtp port //char setup_range[128]; char video_type[20]; char audio_type[20]; int video_track; //video track id int audio_track; //audio track id int video_width; int video_height; }SSC; /RTP/// #define RTP_VERSION 2 #define RTP_MAXCSRCS 15 #define ERR_RTP_INVALIDPACKET -2 struct RTPHeader { #ifdef RTP_BIG_ENDIAN unsigned char version:2; unsigned char padding:1; unsigned char extension:1; unsigned char csrccount:4; unsigned char marker:1; unsigned char payloadtype:7; #else // little endian unsigned char csrccount:4; unsigned char extension:1; unsigned char padding:1; unsigned char version:2; unsigned char payloadtype:7; unsigned char marker:1; #endif // RTP_BIG_ENDIAN unsigned short sequencenumber; unsigned int timestamp; unsigned int ssrc; }; struct RTPExtensionHeader { unsigned short extid; unsigned short length; }; #endif // #include "RtpPacket.h" CRtpPacket::CRtpPacket(void) { m_HasData = 0; m_HasExtension = false; m_HasMarker = false; m_NumCsrcs = 0; m_PayloadType = 0; m_SeqNum = 0; m_TimeStamp = 0; m_ssrc = 0; m_payload = NULL; m_PacketLength = 0; m_PayloadLength = 0; m_extid = 0; m_extension = NULL; m_ExtensionLength = 0; } CRtpPacket::~CRtpPacket(void) { m_HasData = 0; m_HasExtension = false; m_HasMarker = false; m_NumCsrcs = 0; m_PayloadType = 0; m_SeqNum = 0; m_TimeStamp = 0; m_ssrc = 0; m_payload = NULL; m_PacketLength = 0; m_PayloadLength = 0; m_extid = 0; m_extension = NULL; } int CRtpPacket::ParseRawData() { if(m_packet[0] == '/0' || m_PacketLength <= 0) return -1; // The length should be at least the size of the RTP header if(m_PacketLength < sizeof(RTPHeader)) return ERR_RTP_INVALIDPACKET; RTPHeader *pRtpHeader = NULL; int nPayloadOffset = 0; RTPExtensionHeader *pRtpExtheader = NULL; unsigned short nExtNum = 0; pRtpHeader = (RTPHeader *)m_packet; // The version number should be correct if (pRtpHeader->version != RTP_VERSION) return ERR_RTP_INVALIDPACKET; //padding int nPadBytes = 0; if (pRtpHeader->padding) // adjust payload length to take padding into account { nPadBytes = (int)m_packet[m_PacketLength - 1]; // last byte contains number of padding bytes if (nPadBytes <= 0) return ERR_RTP_INVALIDPACKET; } //number of csrc m_NumCsrcs = pRtpHeader->csrccount; nPayloadOffset = sizeof(RTPHeader) + (int)(m_NumCsrcs * sizeof(unsigned int)); //extension m_HasExtension = (pRtpHeader->extension == 0)?false:true; if(m_HasExtension) // got header extension { pRtpExtheader = (RTPExtensionHeader *)(m_packet + nPayloadOffset); m_extid = ntohs(pRtpExtheader->extid); nPayloadOffset += sizeof(RTPExtensionHeader); nExtNum = ntohs(pRtpExtheader->length); m_ExtensionLength = ((int)nExtNum) * sizeof(unsigned int); nPayloadOffset += m_ExtensionLength; m_extension = ((unsigned char*)pRtpExtheader) + sizeof(RTPExtensionHeader); } //marker and payload m_HasMarker = (pRtpHeader->marker == 0)?false:true; m_PayloadType = pRtpHeader->payloadtype; //sequence number,timestamp m_SeqNum = (unsigned int)ntohs(pRtpHeader->sequencenumber); m_TimeStamp = ntohl(pRtpHeader->timestamp); m_ssrc = ntohl(pRtpHeader->ssrc); //payload m_payload = m_packet + nPayloadOffset; m_PayloadLength = m_PacketLength - nPadBytes - nPayloadOffset; if (m_PayloadLength < 0) return ERR_RTP_INVALIDPACKET; return 0; } #pragma once #include "datatype.h" class CRtpPacket { public: CRtpPacket(void); virtual ~CRtpPacket(void); //Function int ParseRawData(); //Data public: char m_HasData; bool m_HasExtension,m_HasMarker; int m_NumCsrcs; unsigned char m_PayloadType; unsigned int m_SeqNum,m_TimeStamp,m_ssrc; char m_packet[1400]; char *m_payload; size_t m_PacketLength,m_PayloadLength; unsigned short m_extid; unsigned char *m_extension; size_t m_ExtensionLength; };