├── android └── jni │ ├── Application.mk │ ├── JNICommon.h │ ├── RTSPClientJNI.h │ ├── RTSPClientJNI.cpp │ └── Android.mk ├── RTSPClient ├── RTP │ ├── RTPSource.h │ ├── AC3RTPSource.h │ ├── H265RTPSource.h │ ├── H264RTPSource.h │ ├── JPEGRTPSource.h │ ├── MPEG4ESRTPSource.h │ ├── MPEG4GenericRTPSource.h │ ├── AC3RTPSource.cpp │ ├── RTPPacketBuffer.h │ ├── H265RTPSource.cpp │ ├── MPEG4ESRTPSource.cpp │ ├── MPEG4GenericRTPSource.cpp │ ├── H264RTPSource.cpp │ └── RTPPacketBuffer.cpp ├── RTCP │ ├── HashTable.cpp │ ├── HashTable.hh │ ├── OutPacketBuffer.h │ ├── rtcp_from_spec.h │ ├── RTCPInstance.h │ ├── BasicHashTable.hh │ ├── OutPacketBuffer.cpp │ ├── RTCP.h │ └── BasicHashTable.cpp ├── Common │ ├── BitVector.hh │ ├── DigestAuthentication.hh │ ├── DigestAuthentication.cpp │ └── BitVector.cpp └── RTSP │ └── RTSPClient.h ├── win32 ├── RTSPClientDll │ ├── stdafx.cpp │ ├── stdafx.h │ ├── dllmain.cpp │ ├── targetver.h │ ├── RTSPClientDll.cpp │ ├── ReadMe.txt │ ├── RTSPClientDll.h │ ├── RTSPClientDll.vcxproj.filters │ └── RTSPClientDll.sln ├── RTSPClientTest │ ├── RTSPClientTest.vcxproj.filters │ ├── RTSPClientTest.sln │ └── RTSPClientTest.vcxproj ├── RTSPClientLib │ ├── RTSPClientLib.sln │ └── RTSPClientLib.vcxproj.filters ├── RTSPServerLib │ ├── RTSPServerLib.sln │ └── RTSPServerLib.vcxproj.filters └── RTSPServerTest │ └── RTSPServerTest.sln ├── OS_Common ├── MySemaphore.h ├── Mutex.h ├── Thread.h ├── Event.h ├── Thread.cpp ├── NetCommon.h ├── MySemaphore.cpp ├── Mutex.cpp └── Event.cpp ├── Util ├── util.h ├── Base64.hh ├── our_md5hl.c ├── our_md5.h ├── util.cpp └── Base64.cpp ├── README.md ├── RTSPServer ├── Common │ ├── NetAddress.cpp │ ├── NetAddress.h │ └── MyList.h └── RTSP │ ├── LiveServerMediaSession.h │ ├── ClientSocket.h │ ├── OnDemandServerMediaSession.h │ ├── LiveServerMediaSession.cpp │ ├── OnDemandServerMediaSession.cpp │ ├── ClientSocket.cpp │ ├── ServerMediaSession.h │ └── RTSPServer.h ├── tests ├── Makefile ├── RTSPLiveStreamer.h ├── rtspserver.cpp ├── rtspclient.cpp └── RTSPLiveStreamer.cpp ├── Common ├── RTSPCommonEnv.h ├── RTSPCommonEnv.cpp └── RTSPCommon.h └── Sock ├── SockCommon.h ├── TaskScheduler.h ├── MySock.h ├── MySock.cpp └── TaskScheduler.cpp /android/jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := armeabi-v7a 2 | APP_PLATFORM := android-21 -------------------------------------------------------------------------------- /RTSPClient/RTP/RTPSource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khaos67/RTSP/HEAD/RTSPClient/RTP/RTPSource.h -------------------------------------------------------------------------------- /win32/RTSPClientDll/stdafx.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khaos67/RTSP/HEAD/win32/RTSPClientDll/stdafx.cpp -------------------------------------------------------------------------------- /win32/RTSPClientDll/stdafx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khaos67/RTSP/HEAD/win32/RTSPClientDll/stdafx.h -------------------------------------------------------------------------------- /win32/RTSPClientDll/dllmain.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khaos67/RTSP/HEAD/win32/RTSPClientDll/dllmain.cpp -------------------------------------------------------------------------------- /win32/RTSPClientDll/targetver.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khaos67/RTSP/HEAD/win32/RTSPClientDll/targetver.h -------------------------------------------------------------------------------- /win32/RTSPClientDll/RTSPClientDll.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khaos67/RTSP/HEAD/win32/RTSPClientDll/RTSPClientDll.cpp -------------------------------------------------------------------------------- /android/jni/JNICommon.h: -------------------------------------------------------------------------------- 1 | #ifndef __JNI_COMMON_H__ 2 | #define __JNI_COMMON_H__ 3 | 4 | #define MAX_CHANNELS (32) 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /win32/RTSPClientTest/RTSPClientTest.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /RTSPClient/RTP/AC3RTPSource.h: -------------------------------------------------------------------------------- 1 | #ifndef __AC3_RTP_SOURCE_H__ 2 | #define __AC3_RTP_SOURCE_H__ 3 | 4 | #include "RTPSource.h" 5 | 6 | class AC3RTPSource : public RTPSource 7 | { 8 | public: 9 | AC3RTPSource(int connType, MediaSubsession &subsession, TaskScheduler &task); 10 | virtual ~AC3RTPSource(); 11 | 12 | protected: 13 | virtual void processFrame(RTPPacketBuffer *packet); 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /OS_Common/MySemaphore.h: -------------------------------------------------------------------------------- 1 | #ifndef __MY_SEMAPHORE_H__ 2 | #define __MY_SEMAPHORE_H__ 3 | 4 | #ifdef WIN32 5 | #include 6 | #define SEMAPHORE HANDLE 7 | #else 8 | #include 9 | #define SEMAPHORE sem_t 10 | #endif 11 | 12 | int SEM_INIT(SEMAPHORE *sem, int init, int max); 13 | int SEM_WAIT(SEMAPHORE *sem); 14 | int SEM_POST(SEMAPHORE *sem); 15 | int SEM_DESTROY(SEMAPHORE *sem); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /RTSPClient/RTP/H265RTPSource.h: -------------------------------------------------------------------------------- 1 | #ifndef __H265_RTP_SOURCE_H__ 2 | #define __H265_RTP_SOURCE_H__ 3 | 4 | #include "H264RTPSource.h" 5 | 6 | class H265RTPSource : public H264RTPSource 7 | { 8 | public: 9 | H265RTPSource(int connType, MediaSubsession& subsession, TaskScheduler& task); 10 | virtual ~H265RTPSource(); 11 | 12 | protected: 13 | virtual void processFrame(RTPPacketBuffer* packet); 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /Util/util.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTIL_H__ 2 | #define __UTIL_H__ 3 | 4 | #include 5 | #include 6 | 7 | #ifdef WIN32 8 | #include 9 | int gettimeofday(struct timeval* tp, int* /*tz*/); 10 | #else 11 | #include 12 | #endif 13 | 14 | extern char* strDup(char const* str); 15 | extern char* strDupSize(char const* str); 16 | extern int CheckUdpPort(unsigned short port); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RTSP 2 | c++ RTSP Client/Server - win32/linux/android 3 | 4 | this project is RTSP client/server library for windows/linux/android. 5 | 6 | under 'test' folder there are test examples. 7 | 8 | parts of this project's source code are from open source streaming library live555. 9 | 10 | as many developer knows live555 source code is terribly complicated. 11 | 12 | so i decided to simplify it and make cross-platform library. 13 | -------------------------------------------------------------------------------- /OS_Common/Mutex.h: -------------------------------------------------------------------------------- 1 | #ifndef __MUTEX_H__ 2 | #define __MUTEX_H__ 3 | 4 | #ifdef WIN32 5 | #include 6 | #include 7 | 8 | #define MUTEX HANDLE 9 | #define PTHREAD_MUTEX_INITIALIZER CreateMutex(NULL, FALSE, NULL) 10 | #else 11 | #include 12 | 13 | #define MUTEX pthread_mutex_t 14 | #endif 15 | 16 | int MUTEX_INIT(MUTEX *mutex); 17 | int MUTEX_LOCK(MUTEX *mutex); 18 | int MUTEX_UNLOCK(MUTEX *mutex); 19 | int MUTEX_DESTROY(MUTEX *mutex); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /OS_Common/Thread.h: -------------------------------------------------------------------------------- 1 | #ifndef __THREAD_H__ 2 | #define __THREAD_H__ 3 | 4 | #ifdef WIN32 5 | #include 6 | #include 7 | 8 | #define THREAD HANDLE 9 | #define THREAD_FUNC unsigned __stdcall 10 | #else 11 | #include 12 | 13 | #define THREAD pthread_t 14 | #define THREAD_FUNC void* 15 | #endif 16 | 17 | int THREAD_CREATE(THREAD *thread, THREAD_FUNC func(void *), void *param); 18 | int THREAD_JOIN(THREAD *thread); 19 | void THREAD_DESTROY(THREAD *thread); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /RTSPClient/RTP/H264RTPSource.h: -------------------------------------------------------------------------------- 1 | #ifndef __H264_RTP_SOURCE_H__ 2 | #define __H264_RTP_SOURCE_H__ 3 | 4 | #include "RTPSource.h" 5 | 6 | class H264RTPSource : public RTPSource 7 | { 8 | public: 9 | H264RTPSource(int connType, MediaSubsession &subsession, TaskScheduler &task); 10 | virtual ~H264RTPSource(); 11 | 12 | protected: 13 | virtual void processFrame(RTPPacketBuffer *packet); 14 | 15 | void putStartCode(); 16 | int parseSpropParameterSets(char *spropParameterSets); 17 | }; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /RTSPClient/RTP/JPEGRTPSource.h: -------------------------------------------------------------------------------- 1 | #ifndef __JPEG_RTP_SOURCE_H__ 2 | #define __JPEG_RTP_SOURCE_H__ 3 | 4 | #include "RTPSource.h" 5 | 6 | #define MAX_JPEG_HEADER_SIZE (1024) 7 | 8 | class JPEGRTPSource : public RTPSource 9 | { 10 | public: 11 | JPEGRTPSource(int connType, MediaSubsession &subsession, TaskScheduler &task); 12 | virtual ~JPEGRTPSource(); 13 | 14 | protected: 15 | virtual void processFrame(RTPPacketBuffer *packet); 16 | 17 | protected: 18 | unsigned fDefaultWidth, fDefaultHeight; 19 | }; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /OS_Common/Event.h: -------------------------------------------------------------------------------- 1 | #ifndef __EVENT_H__ 2 | #define __EVENT_H__ 3 | 4 | #ifdef WIN32 5 | #include 6 | #define EVENT HANDLE 7 | #else 8 | #include 9 | 10 | typedef struct { 11 | pthread_mutex_t mutex; 12 | pthread_cond_t cond; 13 | bool triggered; 14 | } mrevent; 15 | 16 | #define EVENT mrevent 17 | #endif 18 | 19 | void EVENT_INIT(EVENT *event); 20 | void EVENT_DESTROY(EVENT *event); 21 | void EVENT_WAIT(EVENT *event); 22 | void EVENT_SET(EVENT *event); 23 | void EVENT_RESET(EVENT *event); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /RTSPClient/RTP/MPEG4ESRTPSource.h: -------------------------------------------------------------------------------- 1 | #ifndef __MPEG4ES_RTP_SOURCE_H__ 2 | #define __MPEG4ES_RTP_SOURCE_H__ 3 | 4 | #include "RTPSource.h" 5 | 6 | class MPEG4ESRTPSource : public RTPSource 7 | { 8 | public: 9 | MPEG4ESRTPSource(int streamType, MediaSubsession &subsession, TaskScheduler &task); 10 | virtual ~MPEG4ESRTPSource(); 11 | 12 | protected: 13 | virtual void processFrame(RTPPacketBuffer *packet); 14 | unsigned char* parseConfigStr(char const* configStr, unsigned& configSize); 15 | 16 | protected: 17 | struct AUHeader* fAUHeaders; 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /OS_Common/Thread.cpp: -------------------------------------------------------------------------------- 1 | #include "Thread.h" 2 | 3 | int THREAD_CREATE(THREAD *thread, THREAD_FUNC func(void *), void *param) 4 | { 5 | #ifdef WIN32 6 | *thread = (HANDLE)_beginthreadex(NULL, 0, func, param, 0, NULL); 7 | return *thread == NULL ? -1 : 0; 8 | #else 9 | return pthread_create(thread, NULL, func, param); 10 | #endif 11 | } 12 | 13 | int THREAD_JOIN(THREAD *thread) 14 | { 15 | #ifdef WIN32 16 | return WaitForSingleObject(*thread, INFINITE) == WAIT_FAILED ? -1 : 0; 17 | #else 18 | int status; 19 | return pthread_join(*thread, (void **)&status); 20 | #endif 21 | } 22 | 23 | void THREAD_DESTROY(THREAD *thread) 24 | { 25 | #ifdef WIN32 26 | if (*thread) 27 | CloseHandle(*thread); 28 | #endif 29 | *thread = NULL; 30 | } 31 | -------------------------------------------------------------------------------- /OS_Common/NetCommon.h: -------------------------------------------------------------------------------- 1 | #ifndef __NETCOMMON_H__ 2 | #define __NETCOMMON_H__ 3 | 4 | #ifdef WIN32 5 | 6 | #include 7 | #include 8 | 9 | #define closeSocket closesocket 10 | #define EWOULDBLOCK WSAEWOULDBLOCK 11 | #define EINPROGRESS WSAEWOULDBLOCK 12 | #define EINTR WSAEINTR 13 | 14 | #define _strcasecmp _strnicmp 15 | 16 | #if _MSC_VER <= 1700 17 | #define snprintf _snprintf 18 | #endif 19 | 20 | #else 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #define closeSocket close 31 | #define WSAGetLastError() errno 32 | 33 | #include 34 | #include 35 | #define _strcasecmp strncasecmp 36 | #endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /RTSPServer/Common/NetAddress.cpp: -------------------------------------------------------------------------------- 1 | #include "NetAddress.h" 2 | #include 3 | 4 | AddressString::AddressString(struct sockaddr_in const& addr) 5 | { 6 | init(addr.sin_addr.s_addr); 7 | } 8 | 9 | AddressString::AddressString(struct in_addr const& addr) 10 | { 11 | init(addr.s_addr); 12 | } 13 | 14 | AddressString::AddressString(netAddressBits addr) 15 | { 16 | init(addr); 17 | } 18 | 19 | void AddressString::init(netAddressBits addr) 20 | { 21 | fVal = new char[16]; // large enough for "abc.def.ghi.jkl" 22 | netAddressBits addrNBO = htonl(addr); // make sure we have a value in a known byte order: big endian 23 | sprintf(fVal, "%u.%u.%u.%u", (addrNBO>>24)&0xFF, (addrNBO>>16)&0xFF, (addrNBO>>8)&0xFF, addrNBO&0xFF); 24 | } 25 | 26 | AddressString::~AddressString() 27 | { 28 | delete[] fVal; 29 | } 30 | -------------------------------------------------------------------------------- /RTSPClient/RTP/MPEG4GenericRTPSource.h: -------------------------------------------------------------------------------- 1 | #ifndef __MPEG4GENERIC_RTP_SOURCE_H__ 2 | #define __MPEG4GENERIC_RTP_SOURCE_H__ 3 | 4 | #include "RTPSource.h" 5 | 6 | class MPEG4GenericRTPSource : public RTPSource 7 | { 8 | public: 9 | MPEG4GenericRTPSource(int streamType, MediaSubsession &subsession, TaskScheduler &task, 10 | char const *mode, unsigned sizeLength, unsigned indexLength, unsigned indexDeltaLength); 11 | virtual ~MPEG4GenericRTPSource(); 12 | 13 | protected: 14 | virtual void processFrame(RTPPacketBuffer *packet); 15 | 16 | protected: 17 | char *fMode; 18 | unsigned fSizeLength, fIndexLength, fIndexDeltaLength; 19 | unsigned fNumAUHeaders; // in the most recently read packet 20 | unsigned fNextAUHeader; // index of the next AU Header to read 21 | struct AUHeader* fAUHeaders; 22 | }; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /RTSPServer/RTSP/LiveServerMediaSession.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIVE_SERVER_MEDIA_SESSION_H__ 2 | #define __LIVE_SERVER_MEDIA_SESSION_H__ 3 | 4 | #include "ServerMediaSession.h" 5 | 6 | class LiveServerMediaSession : public ServerMediaSession 7 | { 8 | public: 9 | LiveServerMediaSession( 10 | char const* streamName, 11 | char const* info, 12 | char const* description, 13 | bool isSSM, 14 | char const* miscSDPLines, 15 | StreamControl* streamControl = NULL); 16 | 17 | virtual ~LiveServerMediaSession(); 18 | }; 19 | 20 | class LiveServerMediaSubsession : public ServerMediaSubsession 21 | { 22 | public: 23 | LiveServerMediaSubsession(char const* trackId, char const* sdp, char const* codec, unsigned char rtpPayloadType, unsigned timestampFrequency); 24 | virtual ~LiveServerMediaSubsession(); 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /OS_Common/MySemaphore.cpp: -------------------------------------------------------------------------------- 1 | #include "MySemaphore.h" 2 | 3 | int SEM_INIT(SEMAPHORE *sem, int init, int max) 4 | { 5 | #ifdef WIN32 6 | *sem = CreateSemaphore(NULL, init, max, NULL); 7 | return *sem == NULL ? -1 : 0; 8 | #else 9 | return sem_init(sem, 0, init); 10 | #endif 11 | } 12 | 13 | int SEM_DESTROY(SEMAPHORE *sem) 14 | { 15 | #ifdef WIN32 16 | if (*sem) { 17 | CloseHandle(*sem); 18 | *sem = NULL; 19 | } 20 | return 0; 21 | #else 22 | return sem_destroy(sem); 23 | #endif 24 | } 25 | 26 | int SEM_WAIT(SEMAPHORE *sem) 27 | { 28 | #ifdef WIN32 29 | return WaitForSingleObject(*sem, INFINITE); 30 | #else 31 | return sem_wait(sem); 32 | #endif 33 | } 34 | 35 | int SEM_POST(SEMAPHORE *sem) 36 | { 37 | #ifdef WIN32 38 | return ReleaseSemaphore(*sem, 1, NULL) == TRUE ? 0 : -1; 39 | #else 40 | return sem_post(sem); 41 | #endif 42 | } 43 | -------------------------------------------------------------------------------- /RTSPServer/RTSP/ClientSocket.h: -------------------------------------------------------------------------------- 1 | #ifndef __CLIENT_SOCKET_H__ 2 | #define __CLIENT_SOCKET_H__ 3 | 4 | #include "MySock.h" 5 | 6 | class ClientSocket 7 | { 8 | public: 9 | ClientSocket(MySock& rtspSock, unsigned char rtpChannelId, unsigned char rtcpChannelId); 10 | ClientSocket(MySock& rtpSock, struct sockaddr_in& rtpDestAddr, MySock& rtcpSock, struct sockaddr_in& rtcpDestAddr); 11 | virtual ~ClientSocket(); 12 | 13 | int sendRTP(char *buf, int len); 14 | int sendRTCP(char *buf, int len); 15 | void activate(); 16 | 17 | bool isActivated() { return fActive; } 18 | 19 | protected: 20 | MySock* fRtpSock; 21 | struct sockaddr_in fRtpDestAddr; 22 | MySock* fRtcpSock; 23 | struct sockaddr_in fRtcpDestAddr; 24 | 25 | unsigned char fRtpChannelId; 26 | unsigned char fRtcpChannelId; 27 | bool fIsTCP; 28 | bool fActive; 29 | }; 30 | 31 | #endif -------------------------------------------------------------------------------- /RTSPServer/RTSP/OnDemandServerMediaSession.h: -------------------------------------------------------------------------------- 1 | #ifndef __ONDEMAND_SERVER_MEDIA_SESSION_H__ 2 | #define __ONDEMAND_SERVER_MEDIA_SESSION_H__ 3 | 4 | #include "ServerMediaSession.h" 5 | 6 | class OnDemandServerMediaSession : public ServerMediaSession 7 | { 8 | public: 9 | OnDemandServerMediaSession( 10 | char const* streamName, 11 | char const* info, 12 | char const* description, 13 | bool isSSM, 14 | char const* miscSDPLines, 15 | StreamControl* streamControl); 16 | 17 | virtual ~OnDemandServerMediaSession(); 18 | }; 19 | 20 | class OnDemandServerMediaSubsession : public ServerMediaSubsession 21 | { 22 | public: 23 | OnDemandServerMediaSubsession(char const* trackId, char const* sdp, 24 | char const* codec, unsigned char rtpPayloadType, unsigned timestampFrequency); 25 | virtual ~OnDemandServerMediaSubsession(); 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /RTSPServer/RTSP/LiveServerMediaSession.cpp: -------------------------------------------------------------------------------- 1 | #include "LiveServerMediaSession.h" 2 | #include "util.h" 3 | 4 | LiveServerMediaSession::LiveServerMediaSession( 5 | const char *streamName, const char *info, const char *description, bool isSSM, const char *miscSDPLines, 6 | StreamControl* streamControl) 7 | : ServerMediaSession(streamName, info, description, isSSM, miscSDPLines, streamControl) 8 | { 9 | fSessionType = SESSION_LIVE; 10 | } 11 | 12 | LiveServerMediaSession::~LiveServerMediaSession() 13 | { 14 | } 15 | 16 | LiveServerMediaSubsession::LiveServerMediaSubsession(char const* trackId, char const* sdp, 17 | char const* codec, unsigned char rtpPayloadType, unsigned timestampFrequency) 18 | : ServerMediaSubsession(trackId, codec, rtpPayloadType, timestampFrequency) 19 | { 20 | fSDPLines = strDup(sdp); 21 | } 22 | 23 | LiveServerMediaSubsession::~LiveServerMediaSubsession() 24 | { 25 | if (fSDPLines) 26 | delete[] fSDPLines; 27 | } 28 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | OBJ_DIR = ../objs 2 | INC = -I../Sock -I../OS_Common -I../Common -I../Util \ 3 | -I../RTSPClient/RTSP -I../RTSPClient/RTP -I../RTSPClient/RTCP -I../RTSPClient/Common \ 4 | -I../RTSPServer/RTSP -I../RTSPServer/Common 5 | CXXFLAGS = -Wall -W -O2 -fPIC -g -DLINUX $(INC) 6 | 7 | LIB_RTSP_CLIENT_SERVER = libRTSPClient.so libRTSPServer.so 8 | 9 | TARGET = rtspclient rtspserver 10 | 11 | all : makebuilddir $(TARGET) 12 | 13 | makebuilddir: 14 | -@if [ ! -d $(OBJ_DIR) ]; then mkdir -p $(OBJ_DIR); fi 15 | 16 | $(TARGET) : $(LIB_RTSP_CLIENT_SERVER) 17 | g++ -o rtspclient $(CXXFLAGS) rtspclient.cpp -lRTSPClient -L./ 18 | g++ -o rtspserver $(CXXFLAGS) rtspserver.cpp RTSPLiveStreamer.cpp -lRTSPServer -lRTSPClient -L./ 19 | 20 | clean : 21 | rm -rf $(TARGET) $(LIB_RTSP_CLIENT_SERVER) 22 | 23 | libRTSPClient.so : 24 | cd ../ && $(MAKE) 25 | cp -f $(OBJ_DIR)/libRTSPClient.so ./ 26 | libRTSPServer.so : 27 | cd ../ && $(MAKE) 28 | cp -f $(OBJ_DIR)/libRTSPServer.so ./ 29 | -------------------------------------------------------------------------------- /RTSPServer/Common/NetAddress.h: -------------------------------------------------------------------------------- 1 | #ifndef __NET_ADDRESS_H__ 2 | #define __NET_ADDRESS_H__ 3 | 4 | #ifdef WIN32 5 | #include 6 | #else 7 | #include 8 | #endif 9 | 10 | typedef unsigned int netAddressBits; 11 | 12 | bool IsMulticastAddress(netAddressBits address); 13 | 14 | // A mechanism for displaying an IPv4 address in ASCII. This is intended to replace "inet_ntoa()", which is not thread-safe. 15 | class AddressString 16 | { 17 | public: 18 | AddressString(struct sockaddr_in const& addr); 19 | AddressString(struct in_addr const& addr); 20 | AddressString(netAddressBits addr); // "addr" is assumed to be in host byte order here 21 | 22 | virtual ~AddressString(); 23 | 24 | char const* val() const { return fVal; } 25 | 26 | private: 27 | void init(netAddressBits addr); // used to implement each of the constructors 28 | 29 | private: 30 | char* fVal; // The result ASCII string: allocated by the constructor; deleted by the destructor 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /OS_Common/Mutex.cpp: -------------------------------------------------------------------------------- 1 | #include "Mutex.h" 2 | 3 | int MUTEX_INIT(MUTEX *mutex) 4 | { 5 | #ifdef WIN32 6 | *mutex = CreateMutex(NULL, FALSE, NULL); 7 | return *mutex == NULL ? -1 : 0; 8 | #else 9 | pthread_mutexattr_t attr; 10 | pthread_mutexattr_init(&attr); 11 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 12 | return pthread_mutex_init(mutex, &attr); 13 | #endif 14 | } 15 | 16 | int MUTEX_DESTROY(MUTEX *mutex) 17 | { 18 | #ifdef WIN32 19 | if (*mutex) { 20 | CloseHandle(*mutex); 21 | *mutex = NULL; 22 | } 23 | return 0; 24 | #else 25 | return pthread_mutex_destroy(mutex); 26 | #endif 27 | } 28 | 29 | int MUTEX_LOCK(MUTEX *mutex) 30 | { 31 | #ifdef WIN32 32 | return WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED ? -1 : 0; 33 | #else 34 | return pthread_mutex_lock(mutex); 35 | #endif 36 | } 37 | 38 | int MUTEX_UNLOCK(MUTEX *mutex) 39 | { 40 | #ifdef WIN32 41 | return ReleaseMutex(*mutex) == 0 ? -1 : 1; 42 | #else 43 | return pthread_mutex_unlock(mutex); 44 | #endif 45 | } 46 | -------------------------------------------------------------------------------- /RTSPServer/RTSP/OnDemandServerMediaSession.cpp: -------------------------------------------------------------------------------- 1 | #include "OnDemandServerMediaSession.h" 2 | #include "util.h" 3 | 4 | OnDemandServerMediaSession::OnDemandServerMediaSession( 5 | const char *streamName, const char *info, const char *description, bool isSSM, const char *miscSDPLines, 6 | StreamControl* streamControl) 7 | : ServerMediaSession(streamName, info, description, isSSM, miscSDPLines, streamControl) 8 | { 9 | fSessionType = SESSION_ONDEMAND; 10 | } 11 | 12 | OnDemandServerMediaSession::~OnDemandServerMediaSession() 13 | { 14 | } 15 | 16 | OnDemandServerMediaSubsession::OnDemandServerMediaSubsession(char const* trackId, char const* sdp, 17 | char const* codec, unsigned char rtpPayloadType, unsigned timestampFrequency) 18 | : ServerMediaSubsession(trackId, codec, rtpPayloadType, timestampFrequency) 19 | { 20 | fSDPLines = strDup(sdp); 21 | fRTPPayloadType = rtpPayloadType; 22 | fTimestampFrequency = timestampFrequency; 23 | } 24 | 25 | OnDemandServerMediaSubsession::~OnDemandServerMediaSubsession() 26 | { 27 | if (fSDPLines) 28 | delete[] fSDPLines; 29 | } 30 | -------------------------------------------------------------------------------- /android/jni/RTSPClientJNI.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class com_example_rtspclienttestapp_RTSPClient */ 4 | 5 | #ifndef _Included_com_example_rtspclienttestapp_RTSPClient 6 | #define _Included_com_example_rtspclienttestapp_RTSPClient 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: com_example_rtspclienttestapp_RTSPClient 12 | * Method: openURL 13 | * Signature: (ILjava/lang/String;I)I 14 | */ 15 | JNIEXPORT jint JNICALL Java_com_example_rtspclienttestapp_RTSPClient_openURL 16 | (JNIEnv *, jobject, jint, jstring, jint); 17 | 18 | /* 19 | * Class: com_example_rtspclienttestapp_RTSPClient 20 | * Method: playURL 21 | * Signature: (I)I 22 | */ 23 | JNIEXPORT jint JNICALL Java_com_example_rtspclienttestapp_RTSPClient_playURL 24 | (JNIEnv *, jobject, jint); 25 | 26 | /* 27 | * Class: com_example_rtspclienttestapp_RTSPClient 28 | * Method: closeURL 29 | * Signature: (I)V 30 | */ 31 | JNIEXPORT void JNICALL Java_com_example_rtspclienttestapp_RTSPClient_closeURL 32 | (JNIEnv *, jobject, jint); 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | #endif 38 | -------------------------------------------------------------------------------- /RTSPClient/RTP/AC3RTPSource.cpp: -------------------------------------------------------------------------------- 1 | #include "AC3RTPSource.h" 2 | #include "MediaSession.h" 3 | 4 | AC3RTPSource::AC3RTPSource(int connType, MediaSubsession &subsession, TaskScheduler &task) 5 | : RTPSource(connType, subsession, task) 6 | { 7 | } 8 | 9 | AC3RTPSource::~AC3RTPSource() 10 | { 11 | } 12 | 13 | void AC3RTPSource::processFrame(RTPPacketBuffer *packet) 14 | { 15 | uint8_t *buf = packet->payload(); 16 | int len = packet->payloadLen(); 17 | int64_t media_timestamp = packet->extTimestamp() == 0 ? getMediaTimestamp(packet->timestamp()) : packet->extTimestamp(); 18 | 19 | unsigned char* headerStart = buf; 20 | 21 | // There's a 2-byte payload header at the beginning: 22 | if (len < 2) return; 23 | 24 | unsigned char FT = headerStart[0]&0x03; 25 | fBeginFrame = FT != 3; 26 | 27 | if (fBeginFrame) 28 | copyToFrameBuffer(&buf[2], len-2); 29 | 30 | // The RTP "M" (marker) bit indicates the last fragment of a frame. 31 | // In case the sender did not set the "M" bit correctly, we also test for FT == 0: 32 | if (packet->markerBit() || FT == 0) { 33 | if (fFrameHandlerFunc) 34 | fFrameHandlerFunc(fFrameHandlerFuncData, fFrameType, media_timestamp, fFrameBuf, fFrameBufPos); 35 | resetFrameBuf(); 36 | fBeginFrame = false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /OS_Common/Event.cpp: -------------------------------------------------------------------------------- 1 | #include "Event.h" 2 | 3 | void EVENT_INIT(EVENT *event) 4 | { 5 | #ifdef WIN32 6 | *event = CreateEvent(NULL, TRUE, FALSE, NULL); 7 | #else 8 | pthread_mutex_init(&event->mutex, 0); 9 | pthread_cond_init(&event->cond, 0); 10 | event->triggered = false; 11 | #endif 12 | } 13 | 14 | void EVENT_DESTROY(EVENT *event) 15 | { 16 | #ifdef WIN32 17 | CloseHandle(*event); 18 | #else 19 | pthread_mutex_destroy(&event->mutex); 20 | pthread_cond_destroy(&event->cond); 21 | #endif 22 | } 23 | 24 | void EVENT_WAIT(EVENT *event) 25 | { 26 | #ifdef WIN32 27 | WaitForSingleObject(*event, INFINITE); 28 | #else 29 | pthread_mutex_lock(&event->mutex); 30 | while (!event->triggered) 31 | pthread_cond_wait(&event->cond, &event->mutex); 32 | pthread_mutex_unlock(&event->mutex); 33 | #endif 34 | } 35 | 36 | void EVENT_SET(EVENT *event) 37 | { 38 | #ifdef WIN32 39 | SetEvent(*event); 40 | #else 41 | pthread_mutex_lock(&event->mutex); 42 | event->triggered = true; 43 | pthread_cond_signal(&event->cond); 44 | pthread_mutex_unlock(&event->mutex); 45 | #endif 46 | } 47 | 48 | void EVENT_RESET(EVENT *event) 49 | { 50 | #ifdef WIN32 51 | ResetEvent(*event); 52 | #else 53 | pthread_mutex_lock(&event->mutex); 54 | event->triggered = false; 55 | pthread_mutex_unlock(&event->mutex); 56 | #endif 57 | } 58 | -------------------------------------------------------------------------------- /win32/RTSPClientLib/RTSPClientLib.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTSPClientLib", "RTSPClientLib.vcxproj", "{4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Debug|Win32.Build.0 = Debug|Win32 16 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Debug|x64.ActiveCfg = Debug|x64 17 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Debug|x64.Build.0 = Debug|x64 18 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Release|Win32.ActiveCfg = Release|Win32 19 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Release|Win32.Build.0 = Release|Win32 20 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Release|x64.ActiveCfg = Release|x64 21 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /win32/RTSPServerLib/RTSPServerLib.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTSPServerLib", "RTSPServerLib.vcxproj", "{252D25BE-1744-42A9-9DCC-0596B975AC48}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {252D25BE-1744-42A9-9DCC-0596B975AC48}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {252D25BE-1744-42A9-9DCC-0596B975AC48}.Debug|Win32.Build.0 = Debug|Win32 16 | {252D25BE-1744-42A9-9DCC-0596B975AC48}.Debug|x64.ActiveCfg = Debug|x64 17 | {252D25BE-1744-42A9-9DCC-0596B975AC48}.Debug|x64.Build.0 = Debug|x64 18 | {252D25BE-1744-42A9-9DCC-0596B975AC48}.Release|Win32.ActiveCfg = Release|Win32 19 | {252D25BE-1744-42A9-9DCC-0596B975AC48}.Release|Win32.Build.0 = Release|Win32 20 | {252D25BE-1744-42A9-9DCC-0596B975AC48}.Release|x64.ActiveCfg = Release|x64 21 | {252D25BE-1744-42A9-9DCC-0596B975AC48}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /tests/RTSPLiveStreamer.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTSP_LIVE_STREAMER_H__ 2 | #define __RTSP_LIVE_STREAMER_H__ 3 | 4 | #include "RTSPClient.h" 5 | #include "ServerMediaSession.h" 6 | #include "RTSPServer.h" 7 | 8 | typedef enum { 9 | STREAMER_STATE_STOPPED = 0, 10 | STREAMER_STATE_OPENED = 1, 11 | STREAMER_STATE_PAUSED = 2, 12 | STREAMER_STATE_RUNNING = 3 13 | } STREAMER_STATE; 14 | 15 | class RTSPLiveStreamer 16 | { 17 | public: 18 | RTSPLiveStreamer(); 19 | virtual ~RTSPLiveStreamer(); 20 | 21 | STREAMER_STATE state() { return m_nState; } 22 | 23 | int open(const char *url, int stream_type, const char *sessionName); 24 | int run(); 25 | void close(); 26 | 27 | protected: 28 | static void onRtpReceived(void *arg, const char *trackId, char *buf, int len); 29 | void onRtpReceived1(const char *trackId, char *buf, int len); 30 | 31 | static void onRtcpReceived(void *arg, const char *trackId, char *buf, int len); 32 | void onRtcpReceived1(const char *trackId, char *buf, int len); 33 | 34 | protected: 35 | char* checkControlPath(const char *controlPath); 36 | char* updateSdpLines(const char *sdpLines, const char *orgControlPath, const char *newControlPath); 37 | 38 | protected: 39 | RTSPClient* m_pRtspClient; 40 | STREAMER_STATE m_nState; 41 | 42 | ServerMediaSession* m_pServerSession; 43 | RTSPServer* m_pRtspServer; 44 | char* m_pSessionName; 45 | }; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /RTSPServer/RTSP/ClientSocket.cpp: -------------------------------------------------------------------------------- 1 | #include "ClientSocket.h" 2 | 3 | ClientSocket::ClientSocket(MySock& rtspSock, unsigned char rtpChannelId, unsigned char rtcpChannelId) 4 | : fRtpSock(&rtspSock), fRtcpSock(&rtspSock), fRtpChannelId(rtpChannelId), fRtcpChannelId(rtcpChannelId), fIsTCP(true), fActive(false) 5 | { 6 | } 7 | 8 | ClientSocket::ClientSocket(MySock& rtpSock, sockaddr_in& rtpDestAddr, MySock& rtcpSock, sockaddr_in& rtcpDestAddr) 9 | : fRtpSock(&rtpSock), fRtpDestAddr(rtpDestAddr), fRtcpSock(&rtcpSock), fRtcpDestAddr(rtcpDestAddr), fIsTCP(false), fActive(false) 10 | { 11 | } 12 | 13 | ClientSocket::~ClientSocket() 14 | { 15 | if (!fIsTCP) { 16 | if (fRtpSock) { 17 | fRtpSock->closeSock(); 18 | delete fRtpSock; 19 | } 20 | if (fRtcpSock) { 21 | fRtcpSock->closeSock(); 22 | delete fRtcpSock; 23 | } 24 | } 25 | } 26 | 27 | int ClientSocket::sendRTP(char *buf, int len) 28 | { 29 | if (fIsTCP) { 30 | return fRtpSock->sendRTPOverTCP(buf, len, fRtpChannelId); 31 | } else { 32 | return fRtpSock->writeSocket(buf, len, fRtpDestAddr); 33 | } 34 | } 35 | 36 | int ClientSocket::sendRTCP(char *buf, int len) 37 | { 38 | if (fIsTCP) { 39 | return fRtcpSock->sendRTPOverTCP(buf, len, fRtcpChannelId); 40 | } else { 41 | return fRtcpSock->writeSocket(buf, len, fRtcpDestAddr); 42 | } 43 | } 44 | 45 | void ClientSocket::activate() 46 | { 47 | fActive = true; 48 | } 49 | -------------------------------------------------------------------------------- /Common/RTSPCommonEnv.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTSP_COMMON_ENV_H__ 2 | #define __RTSP_COMMON_ENV_H__ 3 | 4 | #ifdef WIN32 5 | #include 6 | #else 7 | #include 8 | extern int _vscprintf (const char * format, va_list pargs); 9 | #endif 10 | 11 | #ifdef ANDROID 12 | #include 13 | #define DPRINTF(...) __android_log_print(ANDROID_LOG_DEBUG, "RTSPClient", __VA_ARGS__) 14 | #define DPRINTF0(X) __android_log_print(ANDROID_LOG_DEBUG, "RTSPClient", "%s\n", X) 15 | #else 16 | #define DPRINTF RTSPCommonEnv::DebugPrint 17 | #define DPRINTF0 RTSPCommonEnv::DebugPrint 18 | #endif 19 | 20 | #define DEBUG_FLAG_RTSP (0x01) 21 | #define DEBUG_FLAG_RTP (0x02) 22 | #define DEBUG_FLAG_RTP_PAYLOAD (0x04) 23 | #define DEBUG_FLAG_ALL (0xFF) 24 | 25 | #define DELETE_OBJECT(obj) if (obj) { delete obj; obj = NULL; } 26 | #define DELETE_ARRAY(arr) if (arr) { delete[] arr; arr = NULL; } 27 | 28 | class RTSPCommonEnv 29 | { 30 | public: 31 | static int nDebugFlag; 32 | static int nDebugPrint; // 0:console, 1:debugview, others:none 33 | 34 | static unsigned short nClientPortRangeMin; 35 | static unsigned short nClientPortRangeMax; 36 | 37 | static unsigned short nServerPortRangeMin; 38 | static unsigned short nServerPortRangeMax; 39 | 40 | static void DebugPrint(char *lpszFormat, ...); 41 | static void SetDebugFlag(int flag); 42 | static void UnsetDebugFlag(int flag); 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /RTSPClient/RTCP/HashTable.cpp: -------------------------------------------------------------------------------- 1 | /********** 2 | This library is free software; you can redistribute it and/or modify it under 3 | the terms of the GNU Lesser General Public License as published by the 4 | Free Software Foundation; either version 2.1 of the License, or (at your 5 | option) any later version. (See .) 6 | 7 | This library is distributed in the hope that it will be useful, but WITHOUT 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 10 | more details. 11 | 12 | You should have received a copy of the GNU Lesser General Public License 13 | along with this library; if not, write to the Free Software Foundation, Inc., 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 15 | **********/ 16 | // Copyright (c) 1996-2008 Live Networks, Inc. All rights reserved. 17 | // Generic Hash Table 18 | // Implementation 19 | 20 | #include "HashTable.hh" 21 | 22 | HashTable::HashTable() { 23 | } 24 | 25 | HashTable::~HashTable() { 26 | } 27 | 28 | HashTable::Iterator::Iterator() { 29 | } 30 | 31 | HashTable::Iterator::~Iterator() {} 32 | 33 | void* HashTable::RemoveNext() { 34 | Iterator* iter = Iterator::create(*this); 35 | char const* key; 36 | void* removedValue = iter->next(key); 37 | if (removedValue != 0) Remove(key); 38 | 39 | delete iter; 40 | return removedValue; 41 | } 42 | -------------------------------------------------------------------------------- /Util/Base64.hh: -------------------------------------------------------------------------------- 1 | /********** 2 | This library is free software; you can redistribute it and/or modify it under 3 | the terms of the GNU Lesser General Public License as published by the 4 | Free Software Foundation; either version 2.1 of the License, or (at your 5 | option) any later version. (See .) 6 | 7 | This library is distributed in the hope that it will be useful, but WITHOUT 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 10 | more details. 11 | 12 | You should have received a copy of the GNU Lesser General Public License 13 | along with this library; if not, write to the Free Software Foundation, Inc., 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 15 | **********/ 16 | // "liveMedia" 17 | // Copyright (c) 1996-2008 Live Networks, Inc. All rights reserved. 18 | // Base64 encoding and decoding 19 | // C++ header 20 | 21 | #ifndef _BASE64_HH 22 | #define _BASE64_HH 23 | 24 | unsigned char* base64Decode(char* in, unsigned& resultSize, 25 | bool trimTrailingZeros = true); 26 | // returns a newly allocated array - of size "resultSize" - that 27 | // the caller is responsible for delete[]ing. 28 | 29 | char* base64Encode(char const* orig, unsigned origLength); 30 | // returns a 0-terminated string that 31 | // the caller is responsible for delete[]ing. 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /win32/RTSPClientDll/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | 동적 연결 라이브러리: RTSPClientDll 프로젝트 개요 3 | ======================================================================== 4 | 5 | 응용 프로그램 마법사에서 이 RTSPClientDll DLL을 만들었습니다. 6 | 7 | RTSPClientDll 응용 프로그램을 구성하는 각 파일에 대한 8 | 요약 설명이 포함되어 있습니다. 9 | 10 | 11 | RTSPClientDll.vcxproj 12 | 응용 프로그램 마법사를 사용하여 생성한 VC++ 프로젝트의 기본 프로젝트 파일입니다. 파일을 생성한 Visual C++ 버전에 대한 정보와 응용 프로그램 마법사를 사용하여 선택한 플랫폼, 구성 및 프로젝트 기능에 대한 정보가 포함되어 있습니다. 13 | 14 | RTSPClientDll.vcxproj.filters 15 | 응용 프로그램 마법사를 사용하여 생성된 VC++ 프로젝트의 필터 파일입니다. 이 파일에는 프로젝트의 파일과 필터 간의 연결 정보가 들어 있습니다. 이러한 연결은 특정 노드에서 유사한 확장명으로 그룹화된 파일을 표시하기 위해 IDE에서 사용됩니다. 예를 들어 ".cpp" 파일은 "소스 파일" 필터와 연결되어 있습니다. 16 | 17 | RTSPClientDll.cpp 18 | 기본 DLL 소스 파일입니다. 19 | 20 | 이 DLL은 만들어질 때 기호를 내보내지 않으므로, 빌드될 때 .lib 파일이 생성되지 않습니다. 이 프로젝트가 다른 프로젝트에 종속되게 하려면 해당 DLL에서 일부 기호를 내보내도록 하는 코드를 추가하여 내보내기 라이브러리가 생성되게 하거나, 프로젝트의 [속성 페이지] 대화 상자에 있는 [링커] 폴더의 [일반] 속성 페이지에서 입력 라이브러리 속성 무시를 [예]로 설정합니다. 21 | 22 | ///////////////////////////////////////////////////////////////////////////// 23 | 기타 표준 파일: 24 | 25 | StdAfx.h, StdAfx.cpp 26 | 이 파일은 미리 컴파일된 헤더(PCH) 파일 RTSPClientDll.pch와 미리 컴파일된 형식(PCT) 파일 StdAfx.obj를 빌드하는 데 사용됩니다. 27 | 28 | ///////////////////////////////////////////////////////////////////////////// 29 | 기타 참고: 30 | 31 | 응용 프로그램 마법사에서 사용하는 "TODO:" 주석은 사용자가 추가하거나 사용자 지정해야 하는 소스 코드 부분을 나타냅니다. 32 | 33 | ///////////////////////////////////////////////////////////////////////////// 34 | -------------------------------------------------------------------------------- /win32/RTSPClientDll/RTSPClientDll.h: -------------------------------------------------------------------------------- 1 | // The following ifdef block is the standard way of creating macros which make exporting 2 | // from a DLL simpler. All files within this DLL are compiled with the RTSPCLIENTDLL_EXPORTS 3 | // symbol defined on the command line. this symbol should not be defined on any project 4 | // that uses this DLL. This way any other project whose source files include this file see 5 | // RTSPCLIENTDLL_API functions as being imported from a DLL, whereas this DLL sees symbols 6 | // defined with this macro as being exported. 7 | #ifdef RTSPCLIENTDLL_EXPORTS 8 | #define RTSPCLIENTDLL_API __declspec(dllexport) 9 | #else 10 | #define RTSPCLIENTDLL_API __declspec(dllimport) 11 | #endif 12 | 13 | #define DEBUG_FLAG_RTSP (0x00000001) 14 | #define DEBUG_FLAG_RTP (0x00000010) 15 | #define DEBUG_FLAG_RTP_PAYLOAD (0x00000100) 16 | 17 | typedef enum DLL_RTP_FRAME_TYPE { DLL_FRAME_TYPE_VIDEO, DLL_FRAME_TYPE_AUDIO, DLL_FRAME_TYPE_ETC }; 18 | typedef void DllFrameHandlerFunc(void *arg, DLL_RTP_FRAME_TYPE frame_type, __int64 timestamp, unsigned char *buf, int len); 19 | 20 | RTSPCLIENTDLL_API void* rtspclient_new(); 21 | RTSPCLIENTDLL_API void rtspclient_delete(void *rtspclient); 22 | RTSPCLIENTDLL_API int rtspclient_open_url(void *rtspclient, const char *url, int conn_type, int timeout); 23 | RTSPCLIENTDLL_API int rtspclient_play_url(void *rtspclient, DllFrameHandlerFunc *func, void *funcData); 24 | RTSPCLIENTDLL_API void rtspclient_close_url(void *rtspclient); 25 | RTSPCLIENTDLL_API void rtspclient_set_debug_flag(int flag); 26 | RTSPCLIENTDLL_API void rtspclient_set_debug_print(int print); 27 | -------------------------------------------------------------------------------- /win32/RTSPClientDll/RTSPClientDll.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 헤더 파일 23 | 24 | 25 | 헤더 파일 26 | 27 | 28 | 헤더 파일 29 | 30 | 31 | 32 | 33 | 소스 파일 34 | 35 | 36 | 소스 파일 37 | 38 | 39 | 소스 파일 40 | 41 | 42 | -------------------------------------------------------------------------------- /Common/RTSPCommonEnv.cpp: -------------------------------------------------------------------------------- 1 | #include "RTSPCommonEnv.h" 2 | 3 | #include 4 | #ifndef WIN32 5 | #include 6 | #include 7 | int _vscprintf (const char * format, va_list pargs) 8 | { 9 | int retval; 10 | va_list argcopy; 11 | va_copy(argcopy, pargs); 12 | retval = vsnprintf(NULL, 0, format, argcopy); 13 | va_end(argcopy); 14 | return retval; 15 | } 16 | #endif 17 | 18 | int RTSPCommonEnv::nDebugPrint = 0; 19 | int RTSPCommonEnv::nDebugFlag = DEBUG_FLAG_RTSP; 20 | 21 | unsigned short RTSPCommonEnv::nClientPortRangeMin = 10000; 22 | unsigned short RTSPCommonEnv::nClientPortRangeMax = 65535; 23 | 24 | unsigned short RTSPCommonEnv::nServerPortRangeMin = 20000; 25 | unsigned short RTSPCommonEnv::nServerPortRangeMax = 65535; 26 | 27 | #ifndef ANDROID 28 | void RTSPCommonEnv::DebugPrint(char *lpszFormat, ...) 29 | { 30 | va_list args; 31 | int len; 32 | char *buffer; 33 | 34 | va_start(args, lpszFormat); 35 | 36 | len = _vscprintf(lpszFormat, args) + 32; 37 | buffer = (char *)malloc(len * sizeof(char)); 38 | 39 | const char *prefix = "[RTSP] "; 40 | 41 | int prefix_len = strlen(prefix); 42 | memcpy(buffer, prefix, prefix_len); 43 | 44 | vsprintf(&buffer[prefix_len], lpszFormat, args); 45 | #ifdef WIN32 46 | if (nDebugPrint == 0) fprintf(stdout, buffer); 47 | else if (nDebugPrint == 1) OutputDebugString(buffer); 48 | #else 49 | fprintf(stdout, buffer); 50 | #endif 51 | 52 | free(buffer); 53 | } 54 | #endif 55 | 56 | void RTSPCommonEnv::SetDebugFlag(int flag) 57 | { 58 | nDebugFlag |= flag; 59 | } 60 | 61 | void RTSPCommonEnv::UnsetDebugFlag(int flag) 62 | { 63 | int x = ~flag; 64 | nDebugFlag &= x; 65 | } 66 | -------------------------------------------------------------------------------- /Util/our_md5hl.c: -------------------------------------------------------------------------------- 1 | #define LENGTH 16 2 | /* md5hl.c 3 | * ---------------------------------------------------------------------------- 4 | * "THE BEER-WARE LICENSE" (Revision 42): 5 | * wrote this file. As long as you retain this notice you 6 | * can do whatever you want with this stuff. If we meet some day, and you think 7 | * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 8 | * ---------------------------------------------------------------------------- 9 | */ 10 | 11 | #include 12 | #include 13 | #include "our_md5.h" 14 | 15 | #ifndef BUFSIZ //pocket pc 16 | #define BUFSIZ 255 17 | #endif 18 | 19 | 20 | char * 21 | our_MD5End(MD5_CTX *ctx, char *buf) 22 | { 23 | int i; 24 | unsigned char digest[LENGTH]; 25 | static const char hex[]="0123456789abcdef"; 26 | 27 | if (!buf) 28 | buf = (char*)malloc(2*LENGTH + 1); 29 | if (!buf) 30 | return 0; 31 | our_MD5Final(digest, ctx); 32 | for (i = 0; i < LENGTH; i++) { 33 | buf[i+i] = hex[digest[i] >> 4]; 34 | buf[i+i+1] = hex[digest[i] & 0x0f]; 35 | } 36 | buf[i+i] = '\0'; 37 | return buf; 38 | } 39 | 40 | char * 41 | our_MD5File(const char *filename, char *buf) 42 | { 43 | unsigned char buffer[BUFSIZ]; 44 | MD5_CTX ctx; 45 | int i; 46 | FILE* f; 47 | 48 | our_MD5Init(&ctx); 49 | f = fopen(filename, "r"); 50 | if (f == NULL) return 0; 51 | while ((i = fread(buffer,1,sizeof buffer,f)) > 0) { 52 | ourMD5Update(&ctx,buffer,i); 53 | } 54 | fclose(f); 55 | if (i < 0) return 0; 56 | return our_MD5End(&ctx, buf); 57 | } 58 | 59 | char * 60 | our_MD5Data (const unsigned char *data, unsigned int len, char *buf) 61 | { 62 | MD5_CTX ctx; 63 | 64 | our_MD5Init(&ctx); 65 | ourMD5Update(&ctx,data,len); 66 | return our_MD5End(&ctx, buf); 67 | } 68 | -------------------------------------------------------------------------------- /tests/rtspserver.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "RTSPServer.h" 3 | #include "RTSPLiveStreamer.h" 4 | 5 | #ifdef WIN32 6 | #include 7 | #include 8 | 9 | #ifdef _DEBUG 10 | #include 11 | #endif 12 | #define mygetch getch 13 | 14 | #elif defined(LINUX) 15 | #include 16 | #include 17 | #include 18 | 19 | int mygetch(void) 20 | { 21 | struct termios oldt, 22 | newt; 23 | int ch; 24 | tcgetattr( STDIN_FILENO, &oldt ); 25 | newt = oldt; 26 | newt.c_lflag &= ~( ICANON | ECHO ); 27 | tcsetattr( STDIN_FILENO, TCSANOW, &newt ); 28 | ch = getchar(); 29 | tcsetattr( STDIN_FILENO, TCSANOW, &oldt ); 30 | return ch; 31 | } 32 | #endif 33 | 34 | #define NUM_STREAMER (5) 35 | 36 | RTSPLiveStreamer *streamers[NUM_STREAMER] = { NULL }; 37 | 38 | void addServerSessions() 39 | { 40 | streamers[0] = new RTSPLiveStreamer(); 41 | streamers[0]->open("rtsp://172.30.1.213/live/main", 0, "stream1"); 42 | streamers[0]->run(); 43 | 44 | streamers[1] = new RTSPLiveStreamer(); 45 | streamers[1]->open("rtsp://admin:1234@172.30.10.103/h264", 0, "stream2"); 46 | streamers[1]->run(); 47 | } 48 | 49 | void removeServerSessions() 50 | { 51 | for (int i=0; iclose(); 54 | delete streamers[i]; 55 | streamers[i] = NULL; 56 | } 57 | } 58 | } 59 | 60 | int main(int argc, char *argv[]) 61 | { 62 | #ifdef _DEBUG 63 | _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); 64 | #endif 65 | 66 | addServerSessions(); 67 | 68 | RTSPServer *rtspServer = RTSPServer::instance(); 69 | rtspServer->startServer(8554); 70 | 71 | char c; 72 | while (c = mygetch() != 'q') { 73 | #ifdef WIN32 74 | Sleep(10); 75 | #else 76 | usleep(10000); 77 | #endif 78 | } 79 | 80 | removeServerSessions(); 81 | 82 | rtspServer->stopServer(); 83 | 84 | rtspServer->destroy(); 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /win32/RTSPClientDll/RTSPClientDll.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTSPClientDll", "RTSPClientDll.vcxproj", "{69A347A8-7926-43BD-B91A-7DAE5BD3355D}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTSPClientLib", "..\RTSPClientLib\RTSPClientLib.vcxproj", "{4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Debug|x64 = Debug|x64 12 | Release|Win32 = Release|Win32 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {69A347A8-7926-43BD-B91A-7DAE5BD3355D}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {69A347A8-7926-43BD-B91A-7DAE5BD3355D}.Debug|Win32.Build.0 = Debug|Win32 18 | {69A347A8-7926-43BD-B91A-7DAE5BD3355D}.Debug|x64.ActiveCfg = Debug|Win32 19 | {69A347A8-7926-43BD-B91A-7DAE5BD3355D}.Release|Win32.ActiveCfg = Release|Win32 20 | {69A347A8-7926-43BD-B91A-7DAE5BD3355D}.Release|Win32.Build.0 = Release|Win32 21 | {69A347A8-7926-43BD-B91A-7DAE5BD3355D}.Release|x64.ActiveCfg = Release|Win32 22 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Debug|Win32.ActiveCfg = Debug|Win32 23 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Debug|Win32.Build.0 = Debug|Win32 24 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Debug|x64.ActiveCfg = Debug|x64 25 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Debug|x64.Build.0 = Debug|x64 26 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Release|Win32.ActiveCfg = Release|Win32 27 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Release|Win32.Build.0 = Release|Win32 28 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Release|x64.ActiveCfg = Release|x64 29 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Release|x64.Build.0 = Release|x64 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /Sock/SockCommon.h: -------------------------------------------------------------------------------- 1 | #ifndef __SOCK_COMMON_H__ 2 | #define __SOCK_COMMON_H__ 3 | 4 | #include "NetCommon.h" 5 | 6 | int setupStreamSock(short port, int makeNonBlocking); 7 | int setupDatagramSock(short port, int makeNonBlocking); 8 | int setupServerSock(short port, int makeNonBlocking); 9 | int setupClientSock(int serverSock, int makeNonBlocking, struct sockaddr_in& clientAddr); 10 | int makeSocketNonBlocking(int sock); 11 | 12 | int makeTCP_NoDelay(int sock); 13 | 14 | unsigned setSendBufferTo(int sock, unsigned requestedSize); 15 | unsigned setReceiveBufferTo(int sock, unsigned requestedSize); 16 | unsigned getSendBufferSize(int sock); 17 | unsigned getReceiveBufferSize(int sock); 18 | 19 | unsigned getBufferSize(int bufOptName, int sock); 20 | unsigned setBufferSizeTo(int bufOptName, int sock, int requestedSize); 21 | 22 | int blockUntilReadable(int sock, struct timeval* timeout); 23 | 24 | int readSocket1(int sock, char *buffer, unsigned bufferSize, struct sockaddr_in &fromAddress); 25 | int readSocket(int sock, char *buffer, unsigned bufferSize, struct sockaddr_in &fromAddress, struct timeval *timeout = NULL); 26 | int readSocketExact(int sock, char *buffer, unsigned bufferSize, struct sockaddr_in &fromAddress, struct timeval *timeout = NULL); 27 | 28 | int writeSocket(int sock, char *buffer, unsigned bufferSize); 29 | int writeSocket(int sock, char *buffer, unsigned bufferSize, struct sockaddr_in& toAddress); 30 | 31 | int sendRTPOverTCP(int sock, char *buffer, int len, unsigned char streamChannelId); 32 | 33 | void shutdown(int sock); 34 | 35 | bool isMulticastAddress(unsigned int address); 36 | bool socketJoinGroupSSM(int sock, unsigned int groupAddress, unsigned int sourceFilterAddr); 37 | bool socketLeaveGroupSSM(int sock, unsigned int groupAddress, unsigned int sourceFilterAddr); 38 | bool socketJoinGroup(int sock, unsigned int groupAddress); 39 | bool socketLeaveGroup(int sock, unsigned int groupAddress); 40 | 41 | unsigned int ourIPAddress(); 42 | 43 | extern unsigned int ReceivingInterfaceAddr; 44 | #endif 45 | -------------------------------------------------------------------------------- /Util/our_md5.h: -------------------------------------------------------------------------------- 1 | /* Because MD5 may not be implemented (at least, with the same 2 | * interface) on all systems, we have our own copy here. 3 | */ 4 | 5 | /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All 6 | rights reserved. 7 | 8 | License to copy and use this software is granted provided that it 9 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest 10 | Algorithm" in all material mentioning or referencing this software 11 | or this function. 12 | 13 | License is also granted to make and use derivative works provided 14 | that such works are identified as "derived from the RSA Data 15 | Security, Inc. MD5 Message-Digest Algorithm" in all material 16 | mentioning or referencing the derived work. 17 | 18 | RSA Data Security, Inc. makes no representations concerning either 19 | the merchantability of this software or the suitability of this 20 | software for any particular purpose. It is provided "as is" 21 | without express or implied warranty of any kind. 22 | 23 | These notices must be retained in any copies of any part of this 24 | documentation and/or software. 25 | */ 26 | 27 | #ifndef _SYS_MD5_H_ 28 | #define _SYS_MD5_H_ 29 | 30 | typedef unsigned UNSIGNED32; 31 | 32 | /* Definitions of _ANSI_ARGS and EXTERN that will work in either 33 | C or C++ code: 34 | */ 35 | #undef _ANSI_ARGS_ 36 | #if ((defined(__STDC__) || defined(SABER)) && !defined(NO_PROTOTYPE)) || defined(__cplusplus) || defined(USE_PROTOTYPE) 37 | # define _ANSI_ARGS_(x) x 38 | #else 39 | # define _ANSI_ARGS_(x) () 40 | #endif 41 | #ifdef __cplusplus 42 | # define EXTERN extern "C" 43 | #else 44 | # define EXTERN extern 45 | #endif 46 | 47 | /* MD5 context. */ 48 | typedef struct MD5Context { 49 | UNSIGNED32 state[4]; /* state (ABCD) */ 50 | UNSIGNED32 count[2]; /* number of bits, modulo 2^64 (lsb first) */ 51 | unsigned char buffer[64]; /* input buffer */ 52 | } MD5_CTX; 53 | 54 | EXTERN void our_MD5Init (MD5_CTX *); 55 | EXTERN void ourMD5Update (MD5_CTX *, const unsigned char *, unsigned int); 56 | EXTERN void our_MD5Pad (MD5_CTX *); 57 | EXTERN void our_MD5Final (unsigned char [16], MD5_CTX *); 58 | EXTERN char * our_MD5End(MD5_CTX *, char *); 59 | EXTERN char * our_MD5File(const char *, char *); 60 | EXTERN char * our_MD5Data(const unsigned char *, unsigned int, char *); 61 | #endif /* _SYS_MD5_H_ */ 62 | -------------------------------------------------------------------------------- /RTSPClient/Common/BitVector.hh: -------------------------------------------------------------------------------- 1 | /********** 2 | This library is free software; you can redistribute it and/or modify it under 3 | the terms of the GNU Lesser General Public License as published by the 4 | Free Software Foundation; either version 2.1 of the License, or (at your 5 | option) any later version. (See .) 6 | 7 | This library is distributed in the hope that it will be useful, but WITHOUT 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 10 | more details. 11 | 12 | You should have received a copy of the GNU Lesser General Public License 13 | along with this library; if not, write to the Free Software Foundation, Inc., 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 15 | **********/ 16 | // "liveMedia" 17 | // Copyright (c) 1996-2014 Live Networks, Inc. All rights reserved. 18 | // Bit Vector data structure 19 | // C++ header 20 | 21 | #ifndef _BIT_VECTOR_HH 22 | #define _BIT_VECTOR_HH 23 | 24 | class BitVector { 25 | public: 26 | BitVector(unsigned char* baseBytePtr, 27 | unsigned baseBitOffset, 28 | unsigned totNumBits); 29 | 30 | void setup(unsigned char* baseBytePtr, 31 | unsigned baseBitOffset, 32 | unsigned totNumBits); 33 | 34 | void putBits(unsigned from, unsigned numBits); // "numBits" <= 32 35 | void put1Bit(unsigned bit); 36 | 37 | unsigned getBits(unsigned numBits); // "numBits" <= 32 38 | unsigned get1Bit(); 39 | bool get1BitBoolean() { return get1Bit() != 0; } 40 | 41 | void skipBits(unsigned numBits); 42 | 43 | unsigned curBitIndex() const { return fCurBitIndex; } 44 | unsigned totNumBits() const { return fTotNumBits; } 45 | unsigned numBitsRemaining() const { return fTotNumBits - fCurBitIndex; } 46 | 47 | unsigned get_expGolomb(); 48 | // Returns the value of the next bits, assuming that they were encoded using an exponential-Golomb code of order 0 49 | 50 | private: 51 | unsigned char* fBaseBytePtr; 52 | unsigned fBaseBitOffset; 53 | unsigned fTotNumBits; 54 | unsigned fCurBitIndex; 55 | }; 56 | 57 | // A general bit copy operation: 58 | void shiftBits(unsigned char* toBasePtr, unsigned toBitOffset, 59 | unsigned char const* fromBasePtr, unsigned fromBitOffset, 60 | unsigned numBits); 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /RTSPClient/RTP/RTPPacketBuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTP_PACKET_BUFFER_H__ 2 | #define __RTP_PACKET_BUFFER_H__ 3 | 4 | #include "NetCommon.h" 5 | #include "RTSPCommon.h" 6 | 7 | #define MAX_RTP_PACKET_SIZE (1024*1024) 8 | 9 | class RTPPacketBuffer { 10 | public: 11 | RTPPacketBuffer(); 12 | virtual ~RTPPacketBuffer(); 13 | 14 | uint8_t* buf() { return fBuf; } 15 | uint8_t* payload(); 16 | int length() { return fLength; } 17 | int payloadLen(); 18 | 19 | uint16_t version() { return fVersion; } 20 | uint16_t padding() { return fPadding; } 21 | uint16_t extension() { return fExtension; } 22 | uint16_t csrcCount() { return fCSRCCount; } 23 | uint16_t markerBit() { return fMarkerBit; } 24 | uint16_t payloadType() { return fPayloadType; } 25 | uint16_t sequenceNum() { return fSequenceNum; } 26 | uint32_t timestamp() { return fTimestamp; } 27 | uint32_t ssrc() { return fSSRC; } 28 | 29 | int64_t extTimestamp() { return fExtTimestamp; } 30 | 31 | bool packetHandler(uint8_t *buf, int len); 32 | void reset(); 33 | 34 | struct timeval const& timeReceived() const { return fTimeReceived; } 35 | bool& isFirstPacket() { return fIsFirstPacket; } 36 | RTPPacketBuffer*& nextPacket() { return fNextPacket; } 37 | 38 | private: 39 | uint8_t* fBuf; 40 | uint8_t* fCurPtr; 41 | int fLength; 42 | uint16_t fVersion; 43 | uint16_t fPadding; 44 | uint16_t fExtension; 45 | uint16_t fCSRCCount; 46 | uint16_t fMarkerBit; 47 | uint16_t fPayloadType; 48 | uint16_t fSequenceNum; 49 | uint32_t fTimestamp; 50 | uint32_t fSSRC; 51 | int64_t fExtTimestamp; 52 | 53 | struct timeval fTimeReceived; 54 | bool fIsFirstPacket; 55 | 56 | RTPPacketBuffer *fNextPacket; 57 | }; 58 | 59 | class ReorderingPacketBuffer { 60 | public: 61 | ReorderingPacketBuffer(); 62 | virtual ~ReorderingPacketBuffer(); 63 | void reset(); 64 | 65 | RTPPacketBuffer* getFreePacket(); 66 | void freePacket(RTPPacketBuffer *packet); 67 | bool storePacket(RTPPacketBuffer *packet); 68 | void releaseUsedPacket(RTPPacketBuffer *packet); 69 | RTPPacketBuffer* getNextCompletedPacket(bool& packetLostPreceded); 70 | 71 | private: 72 | unsigned fThresholdTime; // useconds 73 | bool fHaveSeenFirstPacket; 74 | unsigned short fNextExpectedSeqNo; 75 | 76 | RTPPacketBuffer* fHeadPacket; 77 | RTPPacketBuffer* fTailPacket; 78 | RTPPacketBuffer* fSavedPacket; 79 | bool fSavedPacketFree; 80 | }; 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /Sock/TaskScheduler.h: -------------------------------------------------------------------------------- 1 | #ifndef __TASK_SCHEDULER_H__ 2 | #define __TASK_SCHEDULER_H__ 3 | 4 | #include "NetCommon.h" 5 | #include "Mutex.h" 6 | #include "Thread.h" 7 | 8 | #define SOCKET_READABLE (1<<1) 9 | #define SOCKET_WRITABLE (1<<2) 10 | #define SOCKET_EXCEPTION (1<<3) 11 | 12 | class HandlerSet; 13 | 14 | class TaskScheduler 15 | { 16 | public: 17 | TaskScheduler(); 18 | virtual ~TaskScheduler(); 19 | 20 | typedef void BackgroundHandlerProc(void* clientData, int mask); 21 | 22 | void turnOnBackgroundReadHandling(int socketNum, BackgroundHandlerProc* handlerProc, void *clientData); 23 | void turnOffBackgroundReadHandling(int socketNum); 24 | 25 | int startEventLoop(); 26 | void stopEventLoop(); 27 | void doEventLoop(); 28 | 29 | int isRunning() { return fTaskLoop; } 30 | 31 | protected: 32 | virtual void SingleStep(); 33 | void taskLock(); 34 | void taskUnlock(); 35 | 36 | protected: 37 | int fTaskLoop; 38 | MUTEX fMutex; 39 | THREAD fThread; 40 | 41 | HandlerSet *fReadHandlers; 42 | int fLastHandledSocketNum; 43 | 44 | int fMaxNumSockets; 45 | fd_set fReadSet; 46 | }; 47 | 48 | class HandlerDescriptor { 49 | HandlerDescriptor(HandlerDescriptor* nextHandler); 50 | virtual ~HandlerDescriptor(); 51 | 52 | public: 53 | int socketNum; 54 | TaskScheduler::BackgroundHandlerProc* handlerProc; 55 | void* clientData; 56 | 57 | private: 58 | // Descriptors are linked together in a doubly-linked list: 59 | friend class HandlerSet; 60 | friend class HandlerIterator; 61 | HandlerDescriptor* fNextHandler; 62 | HandlerDescriptor* fPrevHandler; 63 | }; 64 | 65 | class HandlerSet { 66 | public: 67 | HandlerSet(); 68 | virtual ~HandlerSet(); 69 | 70 | void assignHandler(int socketNum, TaskScheduler::BackgroundHandlerProc* handlerProc, void* clientData); 71 | void removeHandler(int socketNum); 72 | void moveHandler(int oldSocketNum, int newSocketNum); 73 | 74 | private: 75 | HandlerDescriptor* lookupHandler(int socketNum); 76 | 77 | private: 78 | friend class HandlerIterator; 79 | HandlerDescriptor fHandlers; 80 | }; 81 | 82 | class HandlerIterator { 83 | public: 84 | HandlerIterator(HandlerSet& handlerSet); 85 | virtual ~HandlerIterator(); 86 | 87 | HandlerDescriptor* next(); // returns NULL if none 88 | void reset(); 89 | 90 | private: 91 | HandlerSet& fOurSet; 92 | HandlerDescriptor* fNextPtr; 93 | }; 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /Sock/MySock.h: -------------------------------------------------------------------------------- 1 | #ifndef __MY_SOCK_H__ 2 | #define __MY_SOCK_H__ 3 | 4 | #include "SockCommon.h" 5 | #include "Mutex.h" 6 | 7 | class MySock 8 | { 9 | public: 10 | MySock(); 11 | ~MySock(); 12 | 13 | int sock() { return fSock; } 14 | unsigned short port() { return fPort; } 15 | struct sockaddr_in& clientAddress() { return fClientAddr; } 16 | bool isOpened() { return fSock != -1; } 17 | 18 | int setupStreamSock(short port, int makeNonBlocking); 19 | int setupDatagramSock(short port, int makeNonBlocking); 20 | int setupServerSock(short port, int makeNonBlocking); 21 | int setupClientSock(int serverSock, int makeNonBlocking); 22 | void closeSock(); 23 | void shutdown(); 24 | 25 | int makeTCP_NoDelay() { return ::makeTCP_NoDelay(fSock); } 26 | unsigned setSendBufferTo(unsigned requestedSize) { return ::setSendBufferTo(fSock, requestedSize); } 27 | unsigned setReceiveBufferTo(unsigned requestedSize) { return ::setReceiveBufferTo(fSock, requestedSize); } 28 | unsigned getSendBufferSize() { return ::getSendBufferSize(fSock); } 29 | unsigned getReceiveBufferSize() { return ::getReceiveBufferSize(fSock); } 30 | 31 | int readSocket1(char *buffer, unsigned bufferSize, struct sockaddr_in &fromAddress) { 32 | return ::readSocket1(fSock, buffer, bufferSize, fromAddress); 33 | } 34 | 35 | int readSocket(char *buffer, unsigned bufferSize, struct sockaddr_in &fromAddress, struct timeval *timeout = NULL) { 36 | return ::readSocket(fSock, buffer, bufferSize, fromAddress, timeout); 37 | } 38 | 39 | int readSocketExact(char *buffer, unsigned bufferSize, struct sockaddr_in &fromAddress, struct timeval *timeout = NULL) { 40 | return ::readSocketExact(fSock, buffer, bufferSize, fromAddress, timeout); 41 | } 42 | 43 | int writeSocket(char *buffer, unsigned bufferSize); 44 | int writeSocket(char *buffer, unsigned bufferSize, struct sockaddr_in &toAddress); 45 | int sendRTPOverTCP(char *buffer, int len, unsigned char streamChannelId); 46 | 47 | bool joinGroupSSM(unsigned int groupAddress, unsigned int sourceFilterAddr); 48 | bool leaveGroupSSM(unsigned int groupAddress, unsigned int sourceFilterAddr); 49 | bool joinGroup(unsigned int groupAddress); 50 | bool leaveGroup(unsigned int groupAddress); 51 | bool changePort(short port); 52 | void changeDestination(struct in_addr const& newDestAddr, short newDestPort); 53 | 54 | protected: 55 | int fSock; 56 | unsigned short fPort; 57 | 58 | struct sockaddr_in fClientAddr; 59 | 60 | bool fIsSSM; 61 | unsigned int fGroupAddress; 62 | unsigned int fSourceFilterAddr; 63 | 64 | MUTEX fMutex; 65 | }; 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /RTSPClient/RTCP/HashTable.hh: -------------------------------------------------------------------------------- 1 | /********** 2 | This library is free software; you can redistribute it and/or modify it under 3 | the terms of the GNU Lesser General Public License as published by the 4 | Free Software Foundation; either version 2.1 of the License, or (at your 5 | option) any later version. (See .) 6 | 7 | This library is distributed in the hope that it will be useful, but WITHOUT 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 10 | more details. 11 | 12 | You should have received a copy of the GNU Lesser General Public License 13 | along with this library; if not, write to the Free Software Foundation, Inc., 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 15 | **********/ 16 | // Copyright (c) 1996-2008 Live Networks, Inc. All rights reserved. 17 | // Generic Hash Table 18 | // C++ header 19 | 20 | #ifndef _HASH_TABLE_HH 21 | #define _HASH_TABLE_HH 22 | 23 | class HashTable { 24 | public: 25 | virtual ~HashTable(); 26 | 27 | // The following must be implemented by a particular 28 | // implementation (subclass): 29 | static HashTable* create(int keyType); 30 | 31 | virtual void* Add(char const* key, void* value) = 0; 32 | // Returns the old value if different, otherwise 0 33 | virtual bool Remove(char const* key) = 0; 34 | virtual void* Lookup(char const* key) const = 0; 35 | // Returns 0 if not found 36 | virtual unsigned numEntries() const = 0; 37 | bool IsEmpty() const { return numEntries() == 0; } 38 | 39 | // Used to iterate through the members of the table: 40 | class Iterator { 41 | public: 42 | // The following must be implemented by a particular 43 | // implementation (subclass): 44 | static Iterator* create(HashTable& hashTable); 45 | 46 | virtual ~Iterator(); 47 | 48 | virtual void* next(char const*& key) = 0; // returns 0 if none 49 | 50 | protected: 51 | Iterator(); // abstract base class 52 | }; 53 | 54 | // A shortcut that can be used to successively remove each of 55 | // the entries in the table (e.g., so that their values can be 56 | // deleted, if they happen to be pointers to allocated memory). 57 | void* RemoveNext(); 58 | 59 | protected: 60 | HashTable(); // abstract base class 61 | }; 62 | 63 | // Warning: The following are deliberately the same as in 64 | // Tcl's hash table implementation 65 | int const STRING_HASH_KEYS = 0; 66 | int const ONE_WORD_HASH_KEYS = 1; 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /RTSPClient/RTCP/OutPacketBuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef __OUT_PACKET_BUFFER_H__ 2 | #define __OUT_PACKET_BUFFER_H__ 3 | 4 | #include "util.h" 5 | 6 | // A data structure that a sink may use for an output packet: 7 | class OutPacketBuffer 8 | { 9 | public: 10 | OutPacketBuffer(unsigned preferredPacketSize, unsigned maxPacketSize); 11 | ~OutPacketBuffer(); 12 | 13 | static unsigned maxSize; 14 | 15 | unsigned char* curPtr() const {return &fBuf[fPacketStart + fCurOffset];} 16 | unsigned totalBytesAvailable() const { 17 | return fLimit - (fPacketStart + fCurOffset); 18 | } 19 | unsigned totalBufferSize() const { return fLimit; } 20 | unsigned char* packet() const {return &fBuf[fPacketStart];} 21 | unsigned curPacketSize() const {return fCurOffset;} 22 | 23 | void increment(unsigned numBytes) {fCurOffset += numBytes;} 24 | 25 | void enqueue(unsigned char const* from, unsigned numBytes); 26 | void enqueueWord(unsigned word); 27 | void insert(unsigned char const* from, unsigned numBytes, unsigned toPosition); 28 | void insertWord(unsigned word, unsigned toPosition); 29 | void extract(unsigned char* to, unsigned numBytes, unsigned fromPosition); 30 | unsigned extractWord(unsigned fromPosition); 31 | 32 | void skipBytes(unsigned numBytes); 33 | 34 | bool isPreferredSize() const {return fCurOffset >= fPreferred;} 35 | bool wouldOverflow(unsigned numBytes) const { 36 | return (fCurOffset+numBytes) > fMax; 37 | } 38 | unsigned numOverflowBytes(unsigned numBytes) const { 39 | return (fCurOffset+numBytes) - fMax; 40 | } 41 | bool isTooBigForAPacket(unsigned numBytes) const { 42 | return numBytes > fMax; 43 | } 44 | 45 | void setOverflowData(unsigned overflowDataOffset, 46 | unsigned overflowDataSize, 47 | struct timeval const& presentationTime, 48 | unsigned durationInMicroseconds); 49 | unsigned overflowDataSize() const {return fOverflowDataSize;} 50 | struct timeval overflowPresentationTime() const {return fOverflowPresentationTime;} 51 | unsigned overflowDurationInMicroseconds() const {return fOverflowDurationInMicroseconds;} 52 | bool haveOverflowData() const {return fOverflowDataSize > 0;} 53 | void useOverflowData(); 54 | 55 | void adjustPacketStart(unsigned numBytes); 56 | void resetPacketStart(); 57 | void resetOffset() { fCurOffset = 0; } 58 | void resetOverflowData() { fOverflowDataOffset = fOverflowDataSize = 0; } 59 | 60 | private: 61 | unsigned fPacketStart, fCurOffset, fPreferred, fMax, fLimit; 62 | unsigned char* fBuf; 63 | 64 | unsigned fOverflowDataOffset, fOverflowDataSize; 65 | struct timeval fOverflowPresentationTime; 66 | unsigned fOverflowDurationInMicroseconds; 67 | }; 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /RTSPClient/RTCP/rtcp_from_spec.h: -------------------------------------------------------------------------------- 1 | /* RTCP code taken directly from the most recent RTP specification: 2 | * draft-ietf-avt-rtp-new-11.txt 3 | * C header 4 | */ 5 | 6 | #ifndef _RTCP_FROM_SPEC_H 7 | #define _RTCP_FROM_SPEC_H 8 | 9 | #include 10 | 11 | /* Definitions of _ANSI_ARGS and EXTERN that will work in either 12 | C or C++ code: 13 | */ 14 | #undef _ANSI_ARGS_ 15 | #if ((defined(__STDC__) || defined(SABER)) && !defined(NO_PROTOTYPE)) || defined(__cplusplus) || defined(USE_PROTOTYPE) 16 | # define _ANSI_ARGS_(x) x 17 | #else 18 | # define _ANSI_ARGS_(x) () 19 | #endif 20 | #ifdef __cplusplus 21 | # define EXTERN extern "C" 22 | #else 23 | # define EXTERN extern 24 | #endif 25 | 26 | /* The code from the spec assumes a type "event"; make this a void*: */ 27 | typedef void* event; 28 | 29 | #define EVENT_UNKNOWN 0 30 | #define EVENT_REPORT 1 31 | #define EVENT_BYE 2 32 | 33 | /* The code from the spec assumes a type "time_tp"; make this a double: */ 34 | typedef double time_tp; 35 | 36 | /* The code from the spec assumes a type "packet"; make this a void*: */ 37 | typedef void* packet; 38 | 39 | #define PACKET_UNKNOWN_TYPE 0 40 | #define PACKET_RTP 1 41 | #define PACKET_RTCP_REPORT 2 42 | #define PACKET_BYE 3 43 | 44 | /* The code from the spec calls drand48(), but we have drand30() instead */ 45 | #define drand48 drand30 46 | 47 | /* The code calls "exit()", but we don't want to exit, so make it a noop: */ 48 | #define exit(n) do {} while (0) 49 | 50 | #ifndef FALSE 51 | #define FALSE 0 52 | #endif 53 | #ifndef TRUE 54 | #define TRUE 1 55 | #endif 56 | 57 | /* EXPORTS: */ 58 | 59 | EXTERN void OnExpire _ANSI_ARGS_((event, int, int, double, int, double*, int*, time_tp, time_tp*, int*)); 60 | 61 | EXTERN void OnReceive _ANSI_ARGS_((packet, event, int*, int*, int*, double*, double*, double, double)); 62 | 63 | /* IMPORTS: */ 64 | 65 | EXTERN void Schedule _ANSI_ARGS_((double,event)); 66 | EXTERN void Reschedule _ANSI_ARGS_((double,event)); 67 | EXTERN void SendRTCPReport _ANSI_ARGS_((event)); 68 | EXTERN void SendBYEPacket _ANSI_ARGS_((event)); 69 | EXTERN int TypeOfEvent _ANSI_ARGS_((event)); 70 | EXTERN int SentPacketSize _ANSI_ARGS_((event)); 71 | EXTERN int PacketType _ANSI_ARGS_((packet)); 72 | EXTERN int ReceivedPacketSize _ANSI_ARGS_((packet)); 73 | EXTERN int NewMember _ANSI_ARGS_((packet)); 74 | EXTERN int NewSender _ANSI_ARGS_((packet)); 75 | EXTERN void AddMember _ANSI_ARGS_((packet)); 76 | EXTERN void AddSender _ANSI_ARGS_((packet)); 77 | EXTERN void RemoveMember _ANSI_ARGS_((packet)); 78 | EXTERN void RemoveSender _ANSI_ARGS_((packet)); 79 | EXTERN double drand30 _ANSI_ARGS_((void)); 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /RTSPClient/RTP/H265RTPSource.cpp: -------------------------------------------------------------------------------- 1 | #include "H265RTPSource.h" 2 | #include "MediaSession.h" 3 | #include "RTSPCommonEnv.h" 4 | 5 | H265RTPSource::H265RTPSource(int connType, MediaSubsession& subsession, TaskScheduler& task) 6 | : H264RTPSource(connType, subsession, task) 7 | { 8 | 9 | } 10 | 11 | H265RTPSource::~H265RTPSource() 12 | { 13 | 14 | } 15 | 16 | void H265RTPSource::processFrame(RTPPacketBuffer* packet) 17 | { 18 | uint8_t* buf = (uint8_t*)packet->payload(); 19 | int len = packet->payloadLen(); 20 | 21 | uint8_t* buf_ptr = buf; 22 | uint8_t* headerStart = buf; 23 | bool isCompleteFrame = false; 24 | 25 | int64_t media_timestamp = packet->extTimestamp() == 0 ? getMediaTimestamp(packet->timestamp()) : packet->extTimestamp(); 26 | 27 | uint8_t nalUnitType = (headerStart[0] & 0x7E) >> 1; 28 | 29 | if (RTSPCommonEnv::nDebugFlag & DEBUG_FLAG_RTP_PAYLOAD) 30 | DPRINTF("nal_type: %d, size: %d\n", nalUnitType, len); 31 | 32 | switch (nalUnitType) { 33 | case 48: { // Aggregation Packet (AP) 34 | buf_ptr += 2; len -= 2; 35 | while (len > 3) 36 | { 37 | uint16_t nalUSize = (buf_ptr[0] << 8) | (buf_ptr[1]); 38 | if (nalUSize > len) { 39 | DPRINTF("Aggregation Packet process error, staplen: %d, len\n", nalUSize, len); 40 | break; 41 | } 42 | 43 | buf_ptr += 2; len -= 2; 44 | nalUnitType = (buf_ptr[0] & 0x7E) >> 1; 45 | 46 | putStartCode(); 47 | copyToFrameBuffer(buf_ptr, nalUSize); 48 | 49 | buf_ptr += nalUSize; len -= nalUSize; 50 | 51 | if (fFrameHandlerFunc) 52 | fFrameHandlerFunc(fFrameHandlerFuncData, fFrameType, media_timestamp, fFrameBuf, fFrameBufPos); 53 | resetFrameBuf(); 54 | } 55 | } break; 56 | case 49: { // Fragmentation Unit (FU) 57 | uint8_t startBit = headerStart[2] & 0x80; 58 | uint8_t endBit = headerStart[2] & 0x40; 59 | if (startBit) { 60 | uint8_t nal_unit_type = headerStart[2] & 0x3F; 61 | uint8_t newNalHeader[2]; 62 | newNalHeader[0] = (headerStart[0] & 0x81) | (nal_unit_type << 1); 63 | newNalHeader[1] = headerStart[1]; 64 | 65 | headerStart[1] = newNalHeader[0]; 66 | headerStart[2] = newNalHeader[1]; 67 | buf_ptr++; len--; 68 | 69 | putStartCode(); 70 | } 71 | else { 72 | buf_ptr += 3; len -= 3; 73 | } 74 | copyToFrameBuffer(buf_ptr, len); 75 | isCompleteFrame = (endBit != 0); 76 | } break; 77 | default: { // This packet contains one complete NAL unit: 78 | putStartCode(); 79 | copyToFrameBuffer(buf_ptr, len); 80 | isCompleteFrame = true; 81 | } break; 82 | } 83 | 84 | if (isCompleteFrame) { 85 | if (fFrameHandlerFunc) 86 | fFrameHandlerFunc(fFrameHandlerFuncData, fFrameType, media_timestamp, fFrameBuf, fFrameBufPos); 87 | resetFrameBuf(); 88 | } 89 | } -------------------------------------------------------------------------------- /Util/util.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | #include "NetCommon.h" 3 | #include "RTSPCommonEnv.h" 4 | 5 | char* strDup(char const* str) 6 | { 7 | if (str == NULL) return NULL; 8 | size_t len = strlen(str) + 1; 9 | char* copy = new char[len]; 10 | 11 | if (copy != NULL) { 12 | memcpy(copy, str, len); 13 | } 14 | return copy; 15 | } 16 | 17 | char* strDupSize(char const* str) 18 | { 19 | if (str == NULL) return NULL; 20 | size_t len = strlen(str) + 1; 21 | char* copy = new char[len]; 22 | 23 | return copy; 24 | } 25 | 26 | int CheckUdpPort(unsigned short port) 27 | { 28 | int newSocket = socket(AF_INET, SOCK_DGRAM, 0); 29 | if (newSocket < 0) { 30 | DPRINTF("unable to create datagram socket: \n"); 31 | return -1; 32 | } 33 | 34 | struct sockaddr_in c_addr; 35 | memset(&c_addr, 0, sizeof(c_addr)); 36 | c_addr.sin_addr.s_addr = INADDR_ANY; 37 | c_addr.sin_family = AF_INET; 38 | c_addr.sin_port = htons(port); 39 | 40 | if (bind(newSocket, (struct sockaddr*)&c_addr, sizeof c_addr) != 0) { 41 | char tmpBuffer[100]; 42 | sprintf(tmpBuffer, "[%s] bind() error (port number: %d): ", __FUNCTION__, port); 43 | DPRINTF0(tmpBuffer); 44 | closeSocket(newSocket); 45 | return -1; 46 | } 47 | 48 | closeSocket(newSocket); 49 | return 0; 50 | } 51 | 52 | #if (defined(__WIN32__) || defined(_WIN32)) && !defined(IMN_PIM) 53 | // For Windoze, we need to implement our own gettimeofday() 54 | #if !defined(_WIN32_WCE) 55 | #include 56 | #endif 57 | 58 | int gettimeofday(struct timeval* tp, int* /*tz*/) { 59 | #if defined(_WIN32_WCE) 60 | /* FILETIME of Jan 1 1970 00:00:00. */ 61 | static const unsigned __int64 epoch = 116444736000000000L; 62 | 63 | FILETIME file_time; 64 | SYSTEMTIME system_time; 65 | ULARGE_INTEGER ularge; 66 | 67 | GetSystemTime(&system_time); 68 | SystemTimeToFileTime(&system_time, &file_time); 69 | ularge.LowPart = file_time.dwLowDateTime; 70 | ularge.HighPart = file_time.dwHighDateTime; 71 | 72 | tp->tv_sec = (long) ((ularge.QuadPart - epoch) / 10000000L); 73 | tp->tv_usec = (long) (system_time.wMilliseconds * 1000); 74 | #else 75 | #ifdef USE_OLD_GETTIMEOFDAY_FOR_WINDOWS_CODE 76 | struct timeb tb; 77 | ftime(&tb); 78 | tp->tv_sec = tb.time; 79 | tp->tv_usec = 1000*tb.millitm; 80 | #else 81 | LARGE_INTEGER tickNow; 82 | static LARGE_INTEGER tickFrequency; 83 | static BOOL tickFrequencySet = FALSE; 84 | if (tickFrequencySet == FALSE) { 85 | QueryPerformanceFrequency(&tickFrequency); 86 | tickFrequencySet = TRUE; 87 | } 88 | QueryPerformanceCounter(&tickNow); 89 | tp->tv_sec = (long) (tickNow.QuadPart / tickFrequency.QuadPart); 90 | tp->tv_usec = (long) (((tickNow.QuadPart % tickFrequency.QuadPart) * 1000000L) / tickFrequency.QuadPart); 91 | #endif 92 | #endif 93 | return 0; 94 | } 95 | #endif 96 | -------------------------------------------------------------------------------- /RTSPClient/Common/DigestAuthentication.hh: -------------------------------------------------------------------------------- 1 | /********** 2 | This library is free software; you can redistribute it and/or modify it under 3 | the terms of the GNU Lesser General Public License as published by the 4 | Free Software Foundation; either version 2.1 of the License, or (at your 5 | option) any later version. (See .) 6 | 7 | This library is distributed in the hope that it will be useful, but WITHOUT 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 10 | more details. 11 | 12 | You should have received a copy of the GNU Lesser General Public License 13 | along with this library; if not, write to the Free Software Foundation, Inc., 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 15 | **********/ 16 | // "liveMedia" 17 | // Copyright (c) 1996-2008 Live Networks, Inc. All rights reserved. 18 | // A class used for digest authentication. 19 | // C++ header 20 | 21 | #ifndef _DIGEST_AUTHENTICATION_HH 22 | #define _DIGEST_AUTHENTICATION_HH 23 | 24 | // A class used for digest authentication. 25 | // The "realm", and "nonce" fields are supplied by the server 26 | // (in a "401 Unauthorized" response). 27 | // The "username" and "password" fields are supplied by the client. 28 | class Authenticator { 29 | public: 30 | Authenticator(); 31 | Authenticator(const Authenticator& orig); 32 | Authenticator& operator=(const Authenticator& rightSide); 33 | virtual ~Authenticator(); 34 | 35 | void reset(); 36 | void setRealmAndNonce(char const* realm, char const* nonce); 37 | void setRealmAndRandomNonce(char const* realm); 38 | // as above, except that the nonce is created randomly. 39 | // (This is used by servers.) 40 | void setUsernameAndPassword(char const* username, char const* password, 41 | bool passwordIsMD5 = false); 42 | // If "passwordIsMD5" is true, then "password" is actually the value computed 43 | // by md5(::) 44 | 45 | char const* realm() const { return fRealm; } 46 | char const* nonce() const { return fNonce; } 47 | char const* username() const { return fUsername; } 48 | char const* password() const { return fPassword; } 49 | 50 | char const* computeDigestResponse(char const* cmd, char const* url) const; 51 | void reclaimDigestResponse(char const* responseStr) const; 52 | 53 | private: 54 | void resetRealmAndNonce(); 55 | void resetUsernameAndPassword(); 56 | void assignRealmAndNonce(char const* realm, char const* nonce); 57 | void assignUsernameAndPassword(char const* username, char const* password, 58 | bool passwordIsMD5); 59 | void assign(char const* realm, char const* nonce, 60 | char const* username, char const* password, bool passwordIsMD5); 61 | 62 | private: 63 | char* fRealm; char* fNonce; 64 | char* fUsername; char* fPassword; 65 | bool fPasswordIsMD5; 66 | }; 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /tests/rtspclient.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #ifdef WIN32 3 | #include 4 | #endif 5 | 6 | //#define RTSPCLIENT_DLL 7 | 8 | #ifdef LINUX 9 | #undef RTSPCLIENT_DLL 10 | #endif 11 | 12 | #ifdef RTSPCLIENT_DLL 13 | #pragma comment(lib, "RTSPClientDll.lib") 14 | #include "RTSPClientDll.h" 15 | #else 16 | #pragma comment(lib, "RTSPClientLib.lib") 17 | #include "RTSPClient.h" 18 | #include "RTSPCommonEnv.h" 19 | #endif 20 | 21 | #ifdef WIN32 22 | #include 23 | 24 | #ifdef _DEBUG 25 | #include 26 | #endif 27 | 28 | #define mygetch getch 29 | 30 | #elif defined(LINUX) 31 | #include 32 | #include 33 | #include 34 | 35 | int mygetch(void) 36 | { 37 | struct termios oldt, 38 | newt; 39 | int ch; 40 | tcgetattr( STDIN_FILENO, &oldt ); 41 | newt = oldt; 42 | newt.c_lflag &= ~( ICANON | ECHO ); 43 | tcsetattr( STDIN_FILENO, TCSANOW, &newt ); 44 | ch = getchar(); 45 | tcsetattr( STDIN_FILENO, TCSANOW, &oldt ); 46 | return ch; 47 | } 48 | #endif 49 | 50 | FILE *fp_dump = NULL; 51 | 52 | #ifdef RTSPCLIENT_DLL 53 | static void frameHandlerFunc(void *arg, DLL_RTP_FRAME_TYPE frame_type, __int64 timestamp, unsigned char *buf, int len) 54 | #else 55 | static void frameHandlerFunc(void *arg, RTP_FRAME_TYPE frame_type, int64_t timestamp, unsigned char *buf, int len) 56 | #endif 57 | { 58 | if (fp_dump) 59 | fwrite(buf, len, 1, fp_dump); 60 | } 61 | 62 | int main(int argc, char *argv[]) 63 | { 64 | #ifdef _DEBUG 65 | _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); 66 | #endif 67 | int retry = 1; 68 | 69 | #ifdef RTSPCLIENT_DLL 70 | rtspclient_set_debug_flag(DEBUG_FLAG_RTSP); 71 | #else 72 | RTSPCommonEnv::SetDebugFlag(DEBUG_FLAG_RTSP); 73 | #endif 74 | char *strURL = "rtsp://222.96.113.48:4554/AVStream1_2"; 75 | 76 | fp_dump = fopen("video.264", "wb"); 77 | 78 | #ifdef RTSPCLIENT_DLL 79 | void *rtspClient = rtspclient_new(); 80 | #else 81 | RTSPClient *rtspClient = new RTSPClient(); 82 | #endif 83 | 84 | again: 85 | #ifdef RTSPCLIENT_DLL 86 | if (rtspclient_open_url(rtspClient, strURL, 1, 2) == 0) 87 | #else 88 | if (rtspClient->openURL(strURL, 1, 2) == 0) 89 | #endif 90 | { 91 | #ifdef RTSPCLIENT_DLL 92 | if (rtspclient_play_url(rtspClient, frameHandlerFunc, rtspClient) == 0) 93 | #else 94 | if (rtspClient->playURL(frameHandlerFunc, rtspClient, NULL, NULL) == 0) 95 | #endif 96 | { 97 | char c; 98 | while (c = mygetch() != 'q') 99 | { 100 | #ifdef WIN32 101 | Sleep(10); 102 | #else 103 | usleep(10000); 104 | #endif 105 | } 106 | } 107 | } 108 | exit: 109 | #ifdef RTSPCLIENT_DLL 110 | rtspclient_close_url(rtspClient); 111 | #else 112 | rtspClient->closeURL(); 113 | #endif 114 | 115 | if (--retry > 0) 116 | goto again; 117 | 118 | #ifdef RTSPCLIENT_DLL 119 | rtspclient_delete(rtspClient); 120 | #else 121 | delete rtspClient; 122 | #endif 123 | 124 | if (fp_dump) fclose(fp_dump); 125 | 126 | return 0; 127 | } 128 | -------------------------------------------------------------------------------- /RTSPClient/RTCP/RTCPInstance.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTCP_INSTANCE_H__ 2 | #define __RTCP_INSTANCE_H__ 3 | 4 | #include "NetCommon.h" 5 | #include "RTSPCommon.h" 6 | #include "OutPacketBuffer.h" 7 | 8 | class RTPSource; 9 | class RTPReceptionStats; 10 | 11 | class SDESItem { 12 | public: 13 | SDESItem(unsigned char tag, unsigned char const* value); 14 | 15 | unsigned char const* data() const {return fData;} 16 | unsigned totalSize() const; 17 | 18 | private: 19 | unsigned char fData[2 + 0xFF]; // first 2 bytes are tag and length 20 | }; 21 | 22 | class RTCPMemberDatabase; // forward 23 | 24 | class RTCPInstance 25 | { 26 | public: 27 | RTCPInstance(unsigned totSessionBW, unsigned char const *cname, RTPSource *source); 28 | virtual ~RTCPInstance(); 29 | 30 | void rtcpPacketHandler(char *buf, int len); 31 | 32 | unsigned numMembers() const; 33 | 34 | static void onExpire(RTCPInstance* instance); 35 | 36 | private: 37 | void addRR(); 38 | void enqueueCommonReportPrefix(unsigned char packetType, u_int32_t SSRC, unsigned numExtraWords = 0); 39 | void enqueueCommonReportSuffix(); 40 | void enqueueReportBlock(RTPReceptionStats* receptionStats); 41 | void addSDES(); 42 | 43 | void sendBuiltPacket(); 44 | 45 | void onReceive(int typeOfPacket, int totPacketSize, u_int32_t ssrc); 46 | void onExpire1(); 47 | 48 | private: 49 | unsigned fTotSessionBW; 50 | RTPSource *fSource; 51 | OutPacketBuffer* fOutBuf; 52 | 53 | SDESItem fCNAME; 54 | RTCPMemberDatabase* fKnownMembers; 55 | unsigned fOutgoingReportCount; // used for SSRC member aging 56 | 57 | double fAveRTCPSize; 58 | int fIsInitial; 59 | double fPrevReportTime; 60 | double fNextReportTime; 61 | int fPrevNumMembers; 62 | 63 | int fLastSentSize; 64 | int fLastReceivedSize; 65 | u_int32_t fLastReceivedSSRC; 66 | int fTypeOfEvent; 67 | int fTypeOfPacket; 68 | bool fHaveJustSentPacket; 69 | unsigned fLastPacketSentSize; 70 | 71 | public: // because this stuff is used by an external "C" function 72 | void sendReport(); 73 | int typeOfEvent() {return fTypeOfEvent;} 74 | int sentPacketSize() {return fLastSentSize;} 75 | int packetType() {return fTypeOfPacket;} 76 | int receivedPacketSize() {return fLastReceivedSize;} 77 | int checkNewSSRC(); 78 | void removeLastReceivedSSRC(); 79 | void removeSSRC(u_int32_t ssrc, bool alsoRemoveStats); 80 | }; 81 | 82 | // RTCP packet types: 83 | const unsigned char RTCP_PT_SR = 200; 84 | const unsigned char RTCP_PT_RR = 201; 85 | const unsigned char RTCP_PT_SDES = 202; 86 | const unsigned char RTCP_PT_BYE = 203; 87 | const unsigned char RTCP_PT_APP = 204; 88 | 89 | // SDES tags: 90 | const unsigned char RTCP_SDES_END = 0; 91 | const unsigned char RTCP_SDES_CNAME = 1; 92 | const unsigned char RTCP_SDES_NAME = 2; 93 | const unsigned char RTCP_SDES_EMAIL = 3; 94 | const unsigned char RTCP_SDES_PHONE = 4; 95 | const unsigned char RTCP_SDES_LOC = 5; 96 | const unsigned char RTCP_SDES_TOOL = 6; 97 | const unsigned char RTCP_SDES_NOTE = 7; 98 | const unsigned char RTCP_SDES_PRIV = 8; 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /win32/RTSPClientTest/RTSPClientTest.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTSPClientTest", "RTSPClientTest.vcxproj", "{CE6CF4AD-B1DC-42E1-B0F3-E5CFF4452EC0}" 5 | ProjectSection(ProjectDependencies) = postProject 6 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12} = {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12} 7 | {69A347A8-7926-43BD-B91A-7DAE5BD3355D} = {69A347A8-7926-43BD-B91A-7DAE5BD3355D} 8 | EndProjectSection 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTSPClientLib", "..\RTSPClientLib\RTSPClientLib.vcxproj", "{4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}" 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTSPClientDll", "..\RTSPClientDll\RTSPClientDll.vcxproj", "{69A347A8-7926-43BD-B91A-7DAE5BD3355D}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Win32 = Debug|Win32 17 | Debug|x64 = Debug|x64 18 | Release|Win32 = Release|Win32 19 | Release|x64 = Release|x64 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {CE6CF4AD-B1DC-42E1-B0F3-E5CFF4452EC0}.Debug|Win32.ActiveCfg = Debug|Win32 23 | {CE6CF4AD-B1DC-42E1-B0F3-E5CFF4452EC0}.Debug|Win32.Build.0 = Debug|Win32 24 | {CE6CF4AD-B1DC-42E1-B0F3-E5CFF4452EC0}.Debug|x64.ActiveCfg = Debug|x64 25 | {CE6CF4AD-B1DC-42E1-B0F3-E5CFF4452EC0}.Debug|x64.Build.0 = Debug|x64 26 | {CE6CF4AD-B1DC-42E1-B0F3-E5CFF4452EC0}.Release|Win32.ActiveCfg = Release|Win32 27 | {CE6CF4AD-B1DC-42E1-B0F3-E5CFF4452EC0}.Release|Win32.Build.0 = Release|Win32 28 | {CE6CF4AD-B1DC-42E1-B0F3-E5CFF4452EC0}.Release|x64.ActiveCfg = Release|x64 29 | {CE6CF4AD-B1DC-42E1-B0F3-E5CFF4452EC0}.Release|x64.Build.0 = Release|x64 30 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Debug|Win32.ActiveCfg = Debug|Win32 31 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Debug|Win32.Build.0 = Debug|Win32 32 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Debug|x64.ActiveCfg = Debug|x64 33 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Debug|x64.Build.0 = Debug|x64 34 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Release|Win32.ActiveCfg = Release|Win32 35 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Release|Win32.Build.0 = Release|Win32 36 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Release|x64.ActiveCfg = Release|x64 37 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Release|x64.Build.0 = Release|x64 38 | {69A347A8-7926-43BD-B91A-7DAE5BD3355D}.Debug|Win32.ActiveCfg = Debug|Win32 39 | {69A347A8-7926-43BD-B91A-7DAE5BD3355D}.Debug|Win32.Build.0 = Debug|Win32 40 | {69A347A8-7926-43BD-B91A-7DAE5BD3355D}.Debug|x64.ActiveCfg = Debug|x64 41 | {69A347A8-7926-43BD-B91A-7DAE5BD3355D}.Debug|x64.Build.0 = Debug|x64 42 | {69A347A8-7926-43BD-B91A-7DAE5BD3355D}.Release|Win32.ActiveCfg = Release|Win32 43 | {69A347A8-7926-43BD-B91A-7DAE5BD3355D}.Release|Win32.Build.0 = Release|Win32 44 | {69A347A8-7926-43BD-B91A-7DAE5BD3355D}.Release|x64.ActiveCfg = Release|x64 45 | {69A347A8-7926-43BD-B91A-7DAE5BD3355D}.Release|x64.Build.0 = Release|x64 46 | EndGlobalSection 47 | GlobalSection(SolutionProperties) = preSolution 48 | HideSolutionNode = FALSE 49 | EndGlobalSection 50 | EndGlobal 51 | -------------------------------------------------------------------------------- /win32/RTSPServerTest/RTSPServerTest.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTSPServerTest", "RTSPServerTest.vcxproj", "{4D518CB4-A16A-4F2D-B9A5-BED375F5CDC4}" 5 | ProjectSection(ProjectDependencies) = postProject 6 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12} = {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12} 7 | {252D25BE-1744-42A9-9DCC-0596B975AC48} = {252D25BE-1744-42A9-9DCC-0596B975AC48} 8 | EndProjectSection 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTSPServerLib", "..\RTSPServerLib\RTSPServerLib.vcxproj", "{252D25BE-1744-42A9-9DCC-0596B975AC48}" 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTSPClientLib", "..\RTSPClientLib\RTSPClientLib.vcxproj", "{4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Win32 = Debug|Win32 17 | Debug|x64 = Debug|x64 18 | Release|Win32 = Release|Win32 19 | Release|x64 = Release|x64 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {4D518CB4-A16A-4F2D-B9A5-BED375F5CDC4}.Debug|Win32.ActiveCfg = Debug|Win32 23 | {4D518CB4-A16A-4F2D-B9A5-BED375F5CDC4}.Debug|Win32.Build.0 = Debug|Win32 24 | {4D518CB4-A16A-4F2D-B9A5-BED375F5CDC4}.Debug|x64.ActiveCfg = Debug|x64 25 | {4D518CB4-A16A-4F2D-B9A5-BED375F5CDC4}.Debug|x64.Build.0 = Debug|x64 26 | {4D518CB4-A16A-4F2D-B9A5-BED375F5CDC4}.Release|Win32.ActiveCfg = Release|Win32 27 | {4D518CB4-A16A-4F2D-B9A5-BED375F5CDC4}.Release|Win32.Build.0 = Release|Win32 28 | {4D518CB4-A16A-4F2D-B9A5-BED375F5CDC4}.Release|x64.ActiveCfg = Release|x64 29 | {4D518CB4-A16A-4F2D-B9A5-BED375F5CDC4}.Release|x64.Build.0 = Release|x64 30 | {252D25BE-1744-42A9-9DCC-0596B975AC48}.Debug|Win32.ActiveCfg = Debug|Win32 31 | {252D25BE-1744-42A9-9DCC-0596B975AC48}.Debug|Win32.Build.0 = Debug|Win32 32 | {252D25BE-1744-42A9-9DCC-0596B975AC48}.Debug|x64.ActiveCfg = Debug|x64 33 | {252D25BE-1744-42A9-9DCC-0596B975AC48}.Debug|x64.Build.0 = Debug|x64 34 | {252D25BE-1744-42A9-9DCC-0596B975AC48}.Release|Win32.ActiveCfg = Release|Win32 35 | {252D25BE-1744-42A9-9DCC-0596B975AC48}.Release|Win32.Build.0 = Release|Win32 36 | {252D25BE-1744-42A9-9DCC-0596B975AC48}.Release|x64.ActiveCfg = Release|x64 37 | {252D25BE-1744-42A9-9DCC-0596B975AC48}.Release|x64.Build.0 = Release|x64 38 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Debug|Win32.ActiveCfg = Debug|Win32 39 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Debug|Win32.Build.0 = Debug|Win32 40 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Debug|x64.ActiveCfg = Debug|x64 41 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Debug|x64.Build.0 = Debug|x64 42 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Release|Win32.ActiveCfg = Release|Win32 43 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Release|Win32.Build.0 = Release|Win32 44 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Release|x64.ActiveCfg = Release|x64 45 | {4C9E5E1A-FD1F-428F-B6E1-7711AFFD2A12}.Release|x64.Build.0 = Release|x64 46 | EndGlobalSection 47 | GlobalSection(SolutionProperties) = preSolution 48 | HideSolutionNode = FALSE 49 | EndGlobalSection 50 | EndGlobal 51 | -------------------------------------------------------------------------------- /RTSPClient/RTP/MPEG4ESRTPSource.cpp: -------------------------------------------------------------------------------- 1 | #include "MPEG4ESRTPSource.h" 2 | #include "MediaSession.h" 3 | 4 | unsigned char* parseGeneralConfigStr(char const* configStr, unsigned& configSize); 5 | 6 | MPEG4ESRTPSource::MPEG4ESRTPSource(int streamType, MediaSubsession &subsession, TaskScheduler &task) 7 | : RTPSource(streamType, subsession, task) 8 | { 9 | fExtraData = parseGeneralConfigStr((char const*)subsession.fmtp_config(), fExtraDataSize); 10 | } 11 | 12 | MPEG4ESRTPSource::~MPEG4ESRTPSource() 13 | { 14 | } 15 | 16 | void MPEG4ESRTPSource::processFrame(RTPPacketBuffer *packet) 17 | { 18 | uint8_t *buf = (uint8_t *)packet->payload(); 19 | int len = packet->payloadLen(); 20 | int64_t media_timestamp = packet->extTimestamp() == 0 ? getMediaTimestamp(packet->timestamp()) : packet->extTimestamp(); 21 | 22 | if (len >= 4) { 23 | if (buf[0] == 0 && buf[1] == 0 && buf[2] == 1) 24 | fBeginFrame = true; 25 | } 26 | 27 | if (fBeginFrame && !fIsStartFrame) { 28 | if (fExtraData) 29 | copyToFrameBuffer(fExtraData, fExtraDataSize); 30 | fIsStartFrame = true; 31 | } 32 | 33 | if (fBeginFrame) 34 | copyToFrameBuffer(buf, len); 35 | 36 | if (packet->markerBit()) { 37 | if (fFrameHandlerFunc) 38 | fFrameHandlerFunc(fFrameHandlerFuncData, fFrameType, media_timestamp, fFrameBuf, fFrameBufPos); 39 | resetFrameBuf(); 40 | fBeginFrame = false; 41 | } 42 | } 43 | 44 | static bool getNibble(char const*& configStr, 45 | unsigned char& resultNibble) 46 | { 47 | char c = configStr[0]; 48 | if (c == '\0') return false; // we've reached the end 49 | 50 | if (c >= '0' && c <= '9') { 51 | resultNibble = c - '0'; 52 | } else if (c >= 'A' && c <= 'F') { 53 | resultNibble = 10 + c - 'A'; 54 | } else if (c >= 'a' && c <= 'f') { 55 | resultNibble = 10 + c - 'a'; 56 | } else { 57 | return false; 58 | } 59 | 60 | ++configStr; // move to the next nibble 61 | return true; 62 | } 63 | 64 | static bool getByte(char const*& configStr, unsigned char& resultByte) 65 | { 66 | resultByte = 0; // by default, in case parsing fails 67 | 68 | unsigned char firstNibble; 69 | if (!getNibble(configStr, firstNibble)) return false; 70 | resultByte = firstNibble<<4; 71 | 72 | unsigned char secondNibble = 0; 73 | if (!getNibble(configStr, secondNibble) && configStr[0] != '\0') { 74 | // There's a second nibble, but it's malformed 75 | return false; 76 | } 77 | resultByte |= secondNibble; 78 | 79 | return true; 80 | } 81 | 82 | unsigned char* parseGeneralConfigStr(char const* configStr, 83 | // result parameter: 84 | unsigned& configSize) 85 | { 86 | unsigned char* config = NULL; 87 | do { 88 | if (configStr == NULL) break; 89 | configSize = (strlen(configStr)+1)/2; 90 | 91 | config = new unsigned char[configSize]; 92 | if (config == NULL) break; 93 | 94 | unsigned i; 95 | for (i = 0; i < configSize; ++i) { 96 | if (!getByte(configStr, config[i])) break; 97 | } 98 | if (i != configSize) break; // part of the string was bad 99 | 100 | return config; 101 | } while (0); 102 | 103 | configSize = 0; 104 | delete[] config; 105 | return NULL; 106 | } 107 | -------------------------------------------------------------------------------- /RTSPClient/RTP/MPEG4GenericRTPSource.cpp: -------------------------------------------------------------------------------- 1 | #include "MPEG4GenericRTPSource.h" 2 | #include "MediaSession.h" 3 | #include "RTSPCommonEnv.h" 4 | #include "BitVector.hh" 5 | 6 | ////////// AUHeader ////////// 7 | struct AUHeader { 8 | unsigned size; 9 | unsigned index; // indexDelta for the 2nd & subsequent headers 10 | }; 11 | 12 | MPEG4GenericRTPSource::MPEG4GenericRTPSource(int streamType, MediaSubsession &subsession, TaskScheduler &task, 13 | char const *mode, unsigned sizeLength, unsigned indexLength, unsigned indexDeltaLength) 14 | : RTPSource(streamType, subsession, task), fSizeLength(sizeLength), fIndexLength(indexLength), fIndexDeltaLength(indexDeltaLength), 15 | fNumAUHeaders(0), fNextAUHeader(0), fAUHeaders(NULL) 16 | { 17 | fMode = strDup(mode); 18 | // Check for a "mode" that we don't yet support: //##### 19 | if (mode == NULL || (strcmp(mode, "aac-hbr") != 0 && strcmp(mode, "generic") != 0)) { 20 | DPRINTF("MPEG4GenericRTPSource Warning: Unknown or unsupported \"mode\": %s\n", mode); 21 | } 22 | } 23 | 24 | MPEG4GenericRTPSource::~MPEG4GenericRTPSource() 25 | { 26 | DELETE_ARRAY(fAUHeaders); 27 | DELETE_ARRAY(fMode); 28 | } 29 | 30 | void MPEG4GenericRTPSource::processFrame(RTPPacketBuffer *packet) 31 | { 32 | uint8_t *buf = (uint8_t *)packet->payload(); 33 | int len = packet->payloadLen(); 34 | 35 | int64_t media_timestamp = packet->extTimestamp() == 0 ? getMediaTimestamp(packet->timestamp()) : packet->extTimestamp(); 36 | 37 | unsigned char* headerStart = buf; 38 | unsigned packetSize = len; 39 | 40 | // default values: 41 | unsigned resultSpecialHeaderSize = 0; 42 | fNumAUHeaders = 0; 43 | fNextAUHeader = 0; 44 | delete[] fAUHeaders; fAUHeaders = NULL; 45 | 46 | if (fSizeLength > 0) { 47 | // The packet begins with a "AU Header Section". Parse it, to 48 | // determine the "AU-header"s for each frame present in this packet: 49 | resultSpecialHeaderSize += 2; 50 | if (packetSize < resultSpecialHeaderSize) return; 51 | 52 | unsigned AU_headers_length = (headerStart[0]<<8)|headerStart[1]; 53 | unsigned AU_headers_length_bytes = (AU_headers_length+7)/8; 54 | if (packetSize 55 | < resultSpecialHeaderSize + AU_headers_length_bytes) return; 56 | resultSpecialHeaderSize += AU_headers_length_bytes; 57 | 58 | // Figure out how many AU-headers are present in the packet: 59 | int bitsAvail = AU_headers_length - (fSizeLength + fIndexLength); 60 | if (bitsAvail >= 0 && (fSizeLength + fIndexDeltaLength) > 0) { 61 | fNumAUHeaders = 1 + bitsAvail/(fSizeLength + fIndexDeltaLength); 62 | } 63 | if (fNumAUHeaders > 0) { 64 | fAUHeaders = new AUHeader[fNumAUHeaders]; 65 | // Fill in each header: 66 | BitVector bv(&headerStart[2], 0, AU_headers_length); 67 | fAUHeaders[0].size = bv.getBits(fSizeLength); 68 | fAUHeaders[0].index = bv.getBits(fIndexLength); 69 | 70 | for (unsigned i = 1; i < fNumAUHeaders; ++i) { 71 | fAUHeaders[i].size = bv.getBits(fSizeLength); 72 | fAUHeaders[i].index = bv.getBits(fIndexDeltaLength); 73 | } 74 | } 75 | } 76 | 77 | uint8_t *ptr = &buf[resultSpecialHeaderSize]; 78 | for (int i = 0; i < fNumAUHeaders; i++) { 79 | copyToFrameBuffer(ptr, fAUHeaders[i].size); 80 | ptr += fAUHeaders[i].size; 81 | 82 | if (fFrameHandlerFunc) 83 | fFrameHandlerFunc(fFrameHandlerFuncData, fFrameType, media_timestamp, fFrameBuf, fFrameBufPos); 84 | resetFrameBuf(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /RTSPClient/RTCP/BasicHashTable.hh: -------------------------------------------------------------------------------- 1 | /********** 2 | This library is free software; you can redistribute it and/or modify it under 3 | the terms of the GNU Lesser General Public License as published by the 4 | Free Software Foundation; either version 2.1 of the License, or (at your 5 | option) any later version. (See .) 6 | 7 | This library is distributed in the hope that it will be useful, but WITHOUT 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 10 | more details. 11 | 12 | You should have received a copy of the GNU Lesser General Public License 13 | along with this library; if not, write to the Free Software Foundation, Inc., 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 15 | **********/ 16 | // Copyright (c) 1996-2008 Live Networks, Inc. All rights reserved. 17 | // Basic Hash Table implementation 18 | // C++ header 19 | 20 | #ifndef _BASIC_HASH_TABLE_HH 21 | #define _BASIC_HASH_TABLE_HH 22 | 23 | #ifndef _HASH_TABLE_HH 24 | #include "HashTable.hh" 25 | #endif 26 | 27 | // A simple hash table implementation, inspired by the hash table 28 | // implementation used in Tcl 7.6: 29 | 30 | #define SMALL_HASH_TABLE_SIZE 4 31 | 32 | class BasicHashTable: public HashTable { 33 | private: 34 | class TableEntry; // forward 35 | 36 | public: 37 | BasicHashTable(int keyType); 38 | virtual ~BasicHashTable(); 39 | 40 | // Used to iterate through the members of the table: 41 | class Iterator; friend class Iterator; // to make Sun's C++ compiler happy 42 | class Iterator: public HashTable::Iterator { 43 | public: 44 | Iterator(BasicHashTable& table); 45 | 46 | private: // implementation of inherited pure virtual functions 47 | void* next(char const*& key); // returns 0 if none 48 | 49 | private: 50 | BasicHashTable& fTable; 51 | unsigned fNextIndex; // index of next bucket to be enumerated after this 52 | TableEntry* fNextEntry; // next entry in the current bucket 53 | }; 54 | 55 | private: // implementation of inherited pure virtual functions 56 | virtual void* Add(char const* key, void* value); 57 | // Returns the old value if different, otherwise 0 58 | virtual bool Remove(char const* key); 59 | virtual void* Lookup(char const* key) const; 60 | // Returns 0 if not found 61 | virtual unsigned numEntries() const; 62 | 63 | private: 64 | class TableEntry { 65 | public: 66 | TableEntry* fNext; 67 | char const* key; 68 | void* value; 69 | }; 70 | 71 | TableEntry* lookupKey(char const* key, unsigned& index) const; 72 | // returns entry matching "key", or NULL if none 73 | bool keyMatches(char const* key1, char const* key2) const; 74 | // used to implement "lookupKey()" 75 | 76 | TableEntry* insertNewEntry(unsigned index, char const* key); 77 | // creates a new entry, and inserts it in the table 78 | void assignKey(TableEntry* entry, char const* key); 79 | // used to implement "insertNewEntry()" 80 | 81 | void deleteEntry(unsigned index, TableEntry* entry); 82 | void deleteKey(TableEntry* entry); 83 | // used to implement "deleteEntry()" 84 | 85 | void rebuild(); // rebuilds the table as its size increases 86 | 87 | unsigned hashIndexFromKey(char const* key) const; 88 | // used to implement many of the routines above 89 | 90 | unsigned randomIndex(unsigned long i) const { 91 | return (((i*1103515245) >> fDownShift) & fMask); 92 | } 93 | 94 | private: 95 | TableEntry** fBuckets; // pointer to bucket array 96 | TableEntry* fStaticBuckets[SMALL_HASH_TABLE_SIZE];// used for small tables 97 | unsigned fNumBuckets, fNumEntries, fRebuildSize, fDownShift, fMask; 98 | int fKeyType; 99 | }; 100 | 101 | #endif 102 | -------------------------------------------------------------------------------- /Common/RTSPCommon.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTSP_COMMON_H__ 2 | #define __RTSP_COMMON_H__ 3 | 4 | typedef unsigned char uint8_t; 5 | typedef unsigned short uint16_t; 6 | typedef unsigned int uint32_t; 7 | 8 | typedef unsigned char u_int8_t; 9 | typedef unsigned short u_int16_t; 10 | typedef unsigned int u_int32_t; 11 | 12 | #ifdef WIN32 13 | typedef unsigned __int64 uint64_t; 14 | typedef unsigned __int64 u_int64_t; 15 | typedef __int64 int64_t; 16 | #else 17 | #include 18 | #endif 19 | 20 | #pragma pack(push, 1) 21 | 22 | typedef struct 23 | { 24 | uint16_t cc: 4; /* csrc count */ 25 | uint16_t ext: 1; /* header extension flag */ 26 | uint16_t pad: 1; /* padding flag - for encryption */ 27 | uint16_t ver: 2; /* protocal version */ 28 | uint16_t pt: 7; /* payload type */ 29 | uint16_t mk: 1; /* marker bit - for profile */ 30 | uint16_t seq; /* sequence number of this packet */ 31 | uint32_t ts; /* timestamp of this packet */ 32 | uint32_t ssrc; /* source of packet */ 33 | } RTP_HEADER; 34 | 35 | typedef struct 36 | { 37 | uint16_t rc: 5; 38 | uint16_t pad: 1; 39 | uint16_t ver: 2; 40 | uint16_t pt: 8; 41 | uint16_t length; 42 | } RTCP_HEADER; 43 | 44 | typedef struct 45 | { 46 | uint16_t profile; 47 | uint16_t length; 48 | int64_t timestamp; 49 | } EXT_HEADER; 50 | 51 | #pragma pack(pop) 52 | 53 | enum STREAM_TYPE { STREAM_TYPE_UDP = 0, STREAM_TYPE_TCP = 1, STREAM_TYPE_MULTICAST = 2 }; 54 | 55 | bool seqNumLT(u_int16_t s1, u_int16_t s2); 56 | 57 | #define RTSP_PARAM_STRING_MAX 200 58 | 59 | bool parseRTSPRequestString(char const *reqStr, unsigned reqStrSize, 60 | char *resultCmdName, 61 | unsigned resultCmdNameMaxSize, 62 | char* resultURLPreSuffix, 63 | unsigned resultURLPreSuffixMaxSize, 64 | char* resultURLSuffix, 65 | unsigned resultURLSuffixMaxSize, 66 | char* resultCSeq, 67 | unsigned resultCSeqMaxSize, 68 | char* resultSessionId, 69 | unsigned resultSessionIdMaxSize, 70 | unsigned& contentLength); 71 | 72 | bool parseRangeParam(char const* paramStr, double& rangeStart, double& rangeEnd, char*& absStartTime, char*& absEndTime, bool& startTimeIsNow); 73 | bool parseRangeHeader(char const* buf, double& rangeStart, double& rangeEnd, char*& absStartTime, char*& absEndTime, bool& startTimeIsNow); 74 | bool parseScaleHeader(char const* buf, float& scale); 75 | 76 | bool parseRTSPURL(char const *url, unsigned &address, unsigned short &port, char const **urlSuffix); 77 | bool parseRTSPURLUsernamePassword(char const* url, char*& username, char*& password); 78 | 79 | char const* dateHeader(); // A "Date:" header that can be used in a RTSP (or HTTP) response 80 | 81 | int trimStartCode(uint8_t *buf, int len); 82 | 83 | char* getLine(char* startOfLine); 84 | 85 | int checkEndian(); // 0: little endian, 1: big endian 86 | 87 | #define htonll(x) \ 88 | ((((x) & 0xff00000000000000LL) >> 56) | \ 89 | (((x) & 0x00ff000000000000LL) >> 40) | \ 90 | (((x) & 0x0000ff0000000000LL) >> 24) | \ 91 | (((x) & 0x000000ff00000000LL) >> 8) | \ 92 | (((x) & 0x00000000ff000000LL) << 8) | \ 93 | (((x) & 0x0000000000ff0000LL) << 24) | \ 94 | (((x) & 0x000000000000ff00LL) << 40) | \ 95 | (((x) & 0x00000000000000ffLL) << 56)) 96 | #define ntohll(x) \ 97 | ((((x) & 0x00000000000000FF) << 56) | \ 98 | (((x) & 0x000000000000FF00) << 40) | \ 99 | (((x) & 0x0000000000FF0000) << 24) | \ 100 | (((x) & 0x00000000FF000000) << 8) | \ 101 | (((x) & 0x000000FF00000000) >> 8) | \ 102 | (((x) & 0x0000FF0000000000) >> 24) | \ 103 | (((x) & 0x00FF000000000000) >> 40) | \ 104 | (((x) & 0xFF00000000000000) >> 56)) 105 | 106 | char* createSDPString(char *mediaType, unsigned char payloadType, char *codec, unsigned frequency, char *trackId); 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /RTSPClient/RTCP/OutPacketBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "OutPacketBuffer.h" 2 | #include "NetCommon.h" 3 | 4 | unsigned OutPacketBuffer::maxSize = 60000; // by default 5 | 6 | OutPacketBuffer::OutPacketBuffer(unsigned preferredPacketSize, 7 | unsigned maxPacketSize) 8 | : fPreferred(preferredPacketSize), fMax(maxPacketSize), 9 | fOverflowDataSize(0) { 10 | unsigned maxNumPackets = (maxSize + (maxPacketSize-1))/maxPacketSize; 11 | fLimit = maxNumPackets*maxPacketSize; 12 | fBuf = new unsigned char[fLimit]; 13 | resetPacketStart(); 14 | resetOffset(); 15 | resetOverflowData(); 16 | } 17 | 18 | OutPacketBuffer::~OutPacketBuffer() { 19 | delete[] fBuf; 20 | } 21 | 22 | void OutPacketBuffer::enqueue(unsigned char const* from, unsigned numBytes) { 23 | if (numBytes > totalBytesAvailable()) { 24 | #ifdef DEBUG 25 | fprintf(stderr, "OutPacketBuffer::enqueue() warning: %d > %d\n", numBytes, totalBytesAvailable()); 26 | #endif 27 | numBytes = totalBytesAvailable(); 28 | } 29 | 30 | if (curPtr() != from) memmove(curPtr(), from, numBytes); 31 | increment(numBytes); 32 | } 33 | 34 | void OutPacketBuffer::enqueueWord(unsigned word) { 35 | unsigned nWord = htonl(word); 36 | enqueue((unsigned char*)&nWord, 4); 37 | } 38 | 39 | void OutPacketBuffer::insert(unsigned char const* from, unsigned numBytes, 40 | unsigned toPosition) { 41 | unsigned realToPosition = fPacketStart + toPosition; 42 | if (realToPosition + numBytes > fLimit) { 43 | if (realToPosition > fLimit) return; // we can't do this 44 | numBytes = fLimit - realToPosition; 45 | } 46 | 47 | memmove(&fBuf[realToPosition], from, numBytes); 48 | if (toPosition + numBytes > fCurOffset) { 49 | fCurOffset = toPosition + numBytes; 50 | } 51 | } 52 | 53 | void OutPacketBuffer::insertWord(unsigned word, unsigned toPosition) { 54 | unsigned nWord = htonl(word); 55 | insert((unsigned char*)&nWord, 4, toPosition); 56 | } 57 | 58 | void OutPacketBuffer::extract(unsigned char* to, unsigned numBytes, 59 | unsigned fromPosition) { 60 | unsigned realFromPosition = fPacketStart + fromPosition; 61 | if (realFromPosition + numBytes > fLimit) { // sanity check 62 | if (realFromPosition > fLimit) return; // we can't do this 63 | numBytes = fLimit - realFromPosition; 64 | } 65 | 66 | memmove(to, &fBuf[realFromPosition], numBytes); 67 | } 68 | 69 | unsigned OutPacketBuffer::extractWord(unsigned fromPosition) { 70 | unsigned nWord; 71 | extract((unsigned char*)&nWord, 4, fromPosition); 72 | return ntohl(nWord); 73 | } 74 | 75 | void OutPacketBuffer::skipBytes(unsigned numBytes) { 76 | if (numBytes > totalBytesAvailable()) { 77 | numBytes = totalBytesAvailable(); 78 | } 79 | 80 | increment(numBytes); 81 | } 82 | 83 | void OutPacketBuffer 84 | ::setOverflowData(unsigned overflowDataOffset, 85 | unsigned overflowDataSize, 86 | struct timeval const& presentationTime, 87 | unsigned durationInMicroseconds) { 88 | fOverflowDataOffset = overflowDataOffset; 89 | fOverflowDataSize = overflowDataSize; 90 | fOverflowPresentationTime = presentationTime; 91 | fOverflowDurationInMicroseconds = durationInMicroseconds; 92 | } 93 | 94 | void OutPacketBuffer::useOverflowData() { 95 | enqueue(&fBuf[fPacketStart + fOverflowDataOffset], fOverflowDataSize); 96 | fCurOffset -= fOverflowDataSize; // undoes increment performed by "enqueue" 97 | resetOverflowData(); 98 | } 99 | 100 | void OutPacketBuffer::adjustPacketStart(unsigned numBytes) { 101 | fPacketStart += numBytes; 102 | if (fOverflowDataOffset >= numBytes) { 103 | fOverflowDataOffset -= numBytes; 104 | } else { 105 | fOverflowDataOffset = 0; 106 | fOverflowDataSize = 0; // an error otherwise 107 | } 108 | } 109 | 110 | void OutPacketBuffer::resetPacketStart() { 111 | if (fOverflowDataSize > 0) { 112 | fOverflowDataOffset += fPacketStart; 113 | } 114 | fPacketStart = 0; 115 | } 116 | -------------------------------------------------------------------------------- /android/jni/RTSPClientJNI.cpp: -------------------------------------------------------------------------------- 1 | #include "JNICommon.h" 2 | #include "RTSPClientJNI.h" 3 | #include 4 | 5 | #include "RTSPClient.h" 6 | #include "RTSPCommonEnv.h" 7 | 8 | static RTSPClient* g_rtspClient[MAX_CHANNELS] = {NULL}; 9 | static JavaVM* g_vm; 10 | static jobject g_obj[MAX_CHANNELS]; 11 | static jmethodID g_method_frameHandler[MAX_CHANNELS]; 12 | 13 | static void frameHandlerFunc(void *arg, RTP_FRAME_TYPE frame_type, int64_t timestamp, uint8_t *buf, int len) 14 | { 15 | int idx = (long)arg; 16 | //DPRINTF("[%d] %d, %d, %d\n", idx, frame_type, timestamp, len); 17 | 18 | JNIEnv *env; 19 | 20 | int getEnvStat = g_vm->GetEnv((void **)&env, JNI_VERSION_1_6); 21 | if (getEnvStat == JNI_EDETACHED) { 22 | //DPRINTF("GetEnv: not attached\n"); 23 | if (g_vm->AttachCurrentThread(&env, NULL) != 0) { 24 | DPRINTF("Failed to attach\n"); 25 | } 26 | } else if (getEnvStat == JNI_OK) { 27 | // 28 | } else if (getEnvStat == JNI_EVERSION) { 29 | DPRINTF("GetEnv: version not supported\n"); 30 | } 31 | 32 | jbyteArray jarr; 33 | jarr = env->NewByteArray(len); 34 | 35 | jboolean isCopy; 36 | jbyte* jbytes = env->GetByteArrayElements(jarr, &isCopy); 37 | 38 | memcpy(jbytes, buf, len); 39 | env->SetByteArrayRegion(jarr, 0, len, jbytes); 40 | 41 | env->CallVoidMethod(g_obj[idx], g_method_frameHandler[idx], frame_type, timestamp, jarr); 42 | 43 | env->ReleaseByteArrayElements(jarr, jbytes, JNI_ABORT); 44 | 45 | if (env->ExceptionCheck()) { 46 | env->ExceptionDescribe(); 47 | } 48 | 49 | g_vm->DetachCurrentThread(); 50 | } 51 | 52 | static bool JNI_Hanlder_Register(JNIEnv *env, jobject obj, jint idx) 53 | { 54 | bool returnValue = true; 55 | // convert local to global reference 56 | // (local will die after this method call) 57 | g_obj[idx] = env->NewGlobalRef(obj); 58 | 59 | // save refs for callback 60 | jclass cls = env->GetObjectClass(g_obj[idx]); 61 | if (cls == NULL) { 62 | DPRINTF("Failed to find class\n"); 63 | } 64 | 65 | g_method_frameHandler[idx] = env->GetMethodID(cls, "frameHandler", "(II[B)V"); 66 | if (g_method_frameHandler[idx] == NULL) { 67 | DPRINTF("Unable to get method ref\n"); 68 | } 69 | 70 | env->GetJavaVM(&g_vm); 71 | 72 | return returnValue; 73 | } 74 | 75 | JNIEXPORT jint JNICALL Java_com_example_rtspclienttestapp_RTSPClient_openURL(JNIEnv *env, jobject obj, jint idx, jstring strURL, jint streamType) 76 | { 77 | const char *url = env->GetStringUTFChars(strURL, 0); 78 | DPRINTF("openURL %d %s %d\n", idx, url, streamType); 79 | 80 | jint ret = 0; 81 | 82 | if (g_rtspClient[idx]) { 83 | DPRINTF("failed to openURL, rtspclient[%d] already exist\n", idx); 84 | ret = -1; 85 | goto exit; 86 | } 87 | 88 | if (!JNI_Hanlder_Register(env, obj, idx)) { 89 | DPRINTF("failed to openURL, cannot register jni handler functions\n"); 90 | ret = -1; 91 | goto exit; 92 | } 93 | 94 | g_rtspClient[idx] = new RTSPClient(); 95 | 96 | if (g_rtspClient[idx]->openURL(url, streamType, 3) < 0) { 97 | DPRINTF("failed to openURL, cannot connect to rtsp server\n"); 98 | ret = -1; 99 | goto exit; 100 | } 101 | 102 | exit: 103 | env->ReleaseStringUTFChars(strURL, url); 104 | return ret; 105 | } 106 | 107 | JNIEXPORT jint JNICALL Java_com_example_rtspclienttestapp_RTSPClient_playURL(JNIEnv *env, jobject obj, jint idx) 108 | { 109 | if (!g_rtspClient[idx]) { 110 | DPRINTF("failed to playURL, rtspclient[%d] not opened\n", idx); 111 | return -1; 112 | } 113 | 114 | return g_rtspClient[idx]->playURL(frameHandlerFunc, (void *)idx, NULL, NULL); 115 | } 116 | 117 | 118 | JNIEXPORT void JNICALL Java_com_example_rtspclienttestapp_RTSPClient_closeURL(JNIEnv *env, jobject obj, jint idx) 119 | { 120 | if (g_rtspClient[idx]) { 121 | g_rtspClient[idx]->closeURL(); 122 | delete g_rtspClient[idx]; 123 | g_rtspClient[idx] = NULL; 124 | 125 | env->DeleteGlobalRef(g_obj[idx]); 126 | } 127 | DPRINTF("closeURL\n"); 128 | } 129 | -------------------------------------------------------------------------------- /Sock/MySock.cpp: -------------------------------------------------------------------------------- 1 | #include "MySock.h" 2 | #ifdef LINUX 3 | #include 4 | #endif 5 | 6 | MySock::MySock() 7 | { 8 | fSock = -1; 9 | fPort = 0; 10 | memset(&fClientAddr, 0, sizeof(struct sockaddr_in)); 11 | fIsSSM = false; 12 | fGroupAddress = fSourceFilterAddr = 0; 13 | MUTEX_INIT(&fMutex); 14 | } 15 | 16 | MySock::~MySock() 17 | { 18 | closeSock(); 19 | MUTEX_DESTROY(&fMutex); 20 | } 21 | 22 | void MySock::closeSock() 23 | { 24 | if (fIsSSM) { 25 | if (!leaveGroupSSM(fGroupAddress, fSourceFilterAddr)) { 26 | leaveGroup(fGroupAddress); 27 | } 28 | } 29 | 30 | if (fSock >= 0) { 31 | closeSocket(fSock); 32 | fSock = -1; 33 | memset(&fClientAddr, 0, sizeof(struct sockaddr_in)); 34 | fGroupAddress = fSourceFilterAddr = 0; 35 | } 36 | } 37 | 38 | void MySock::shutdown() 39 | { 40 | ::shutdown(fSock); 41 | } 42 | 43 | int MySock::setupStreamSock(short port, int makeNonBlocking) 44 | { 45 | int sock = ::setupStreamSock(port, makeNonBlocking); 46 | if (sock > 0) { 47 | fSock = sock; 48 | fPort = port; 49 | } 50 | 51 | return sock; 52 | } 53 | 54 | int MySock::setupDatagramSock(short port, int makeNonBlocking) 55 | { 56 | int sock = ::setupDatagramSock(port, makeNonBlocking); 57 | if (sock > 0) { 58 | fSock = sock; 59 | fPort = port; 60 | } 61 | 62 | return sock; 63 | } 64 | 65 | int MySock::setupServerSock(short port, int makeNonBlocking) 66 | { 67 | int sock = ::setupServerSock(port, makeNonBlocking); 68 | if (sock > 0) { 69 | fSock = sock; 70 | fPort = port; 71 | } 72 | 73 | return sock; 74 | } 75 | 76 | int MySock::setupClientSock(int serverSock, int makeNonBlocking) 77 | { 78 | int sock = ::setupClientSock(serverSock, makeNonBlocking, fClientAddr); 79 | if (sock > 0) { 80 | fSock = sock; 81 | fPort = ntohs(fClientAddr.sin_port); 82 | } 83 | 84 | return sock; 85 | } 86 | 87 | int MySock::writeSocket(char *buffer, unsigned bufferSize) 88 | { 89 | MUTEX_LOCK(&fMutex); 90 | int err = ::writeSocket(fSock, buffer, bufferSize); 91 | MUTEX_UNLOCK(&fMutex); 92 | return err; 93 | } 94 | 95 | int MySock::writeSocket(char *buffer, unsigned bufferSize, struct sockaddr_in &toAddress) 96 | { 97 | MUTEX_LOCK(&fMutex); 98 | int err = ::writeSocket(fSock, buffer, bufferSize, toAddress); 99 | MUTEX_UNLOCK(&fMutex); 100 | return err; 101 | } 102 | 103 | int MySock::sendRTPOverTCP(char *buffer, int len, unsigned char streamChannelId) 104 | { 105 | MUTEX_LOCK(&fMutex); 106 | int err = ::sendRTPOverTCP(fSock, buffer, len, streamChannelId); 107 | MUTEX_UNLOCK(&fMutex); 108 | return err; 109 | } 110 | 111 | bool MySock::changePort(short port) 112 | { 113 | closeSocket(fSock); 114 | fSock = setupDatagramSock(port, true); 115 | return fSock >= 0; 116 | } 117 | 118 | void MySock::changeDestination(struct in_addr const& newDestAddr, short newDestPort) 119 | { 120 | if (newDestAddr.s_addr != 0) { 121 | if (newDestAddr.s_addr != fGroupAddress && isMulticastAddress(newDestAddr.s_addr)) { 122 | socketLeaveGroup(fSock, fGroupAddress); 123 | socketJoinGroup(fSock, newDestAddr.s_addr); 124 | } 125 | fGroupAddress = newDestAddr.s_addr; 126 | } 127 | 128 | if (newDestPort != 0) { 129 | if (newDestPort != fPort && isMulticastAddress(fGroupAddress)) { 130 | changePort(newDestPort); 131 | socketJoinGroup(fSock, fGroupAddress); 132 | } 133 | } 134 | } 135 | 136 | bool MySock::joinGroupSSM(unsigned int groupAddress, unsigned int sourceFilterAddr) 137 | { 138 | fGroupAddress = groupAddress; 139 | fSourceFilterAddr = sourceFilterAddr; 140 | fIsSSM = socketJoinGroupSSM(fSock, groupAddress, sourceFilterAddr); 141 | return fIsSSM; 142 | } 143 | 144 | bool MySock::leaveGroupSSM(unsigned int groupAddress, unsigned int sourceFilterAddr) 145 | { 146 | fIsSSM = !socketLeaveGroupSSM(fSock, groupAddress, sourceFilterAddr); 147 | return !fIsSSM; 148 | } 149 | 150 | bool MySock::joinGroup(unsigned int groupAddress) 151 | { 152 | fGroupAddress = groupAddress; 153 | fIsSSM = socketJoinGroup(fSock, groupAddress); 154 | return fIsSSM; 155 | } 156 | 157 | bool MySock::leaveGroup(unsigned int groupAddress) 158 | { 159 | fIsSSM = !socketLeaveGroup(fSock, groupAddress); 160 | return !fIsSSM; 161 | } 162 | -------------------------------------------------------------------------------- /android/jni/Android.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2009 The Android Open Source Project 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | LOCAL_PATH := $(call my-dir) 16 | 17 | include $(CLEAR_VARS) 18 | 19 | LOCAL_MODULE := RTSPStreamer 20 | LOCAL_SRC_FILES := RTSPClientJNI.cpp 21 | LOCAL_LDLIBS := -llog 22 | 23 | LOCAL_CFLAGS := -DANDROID 24 | LOCAL_CPPFLAGS := -DANDROID 25 | LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../OS_Common \ 26 | $(LOCAL_PATH)/../../Common \ 27 | $(LOCAL_PATH)/../../Util \ 28 | $(LOCAL_PATH)/../../OS_Common \ 29 | $(LOCAL_PATH)/../../Sock \ 30 | $(LOCAL_PATH)/../../RTSPClient/Common \ 31 | $(LOCAL_PATH)/../../RTSPClient/RTCP \ 32 | $(LOCAL_PATH)/../../RTSPClient/RTP \ 33 | $(LOCAL_PATH)/../../RTSPClient/RTSP \ 34 | $(LOCAL_PATH)/../../RTSPServer/Common \ 35 | $(LOCAL_PATH)/../../RTSPServer/RTSP 36 | 37 | OS_COMMON_SRC_FILES := $(LOCAL_PATH)/../../OS_Common/Mutex.cpp \ 38 | $(LOCAL_PATH)/../../OS_Common/Thread.cpp \ 39 | $(LOCAL_PATH)/../../OS_Common/Event.cpp \ 40 | $(LOCAL_PATH)/../../OS_Common/MySemaphore.cpp 41 | 42 | COMMON_SRC_FILES := $(LOCAL_PATH)/../../Common/RTSPCommon.cpp \ 43 | $(LOCAL_PATH)/../../Common/RTSPCommonEnv.cpp 44 | 45 | RTSPCLIENT_COMMON_SRC_FILES := $(LOCAL_PATH)/../../RTSPClient/Common/DigestAuthentication.cpp \ 46 | $(LOCAL_PATH)/../../RTSPClient/Common/BitVector.cpp 47 | 48 | RTSPSERVER_COMMON_SRC_FILES := $(LOCAL_PATH)/../../RTSPServer/Common/NetAddress.cpp 49 | 50 | UTIL_SRC_FILES := $(LOCAL_PATH)/../../Util/our_md5hl.c \ 51 | $(LOCAL_PATH)/../../Util/our_md5.c \ 52 | $(LOCAL_PATH)/../../Util/util.cpp \ 53 | $(LOCAL_PATH)/../../Util/Base64.cpp 54 | 55 | SOCK_SRC_FILES := $(LOCAL_PATH)/../../Sock/SockCommon.cpp \ 56 | $(LOCAL_PATH)/../../Sock/MySock.cpp \ 57 | $(LOCAL_PATH)/../../Sock/TaskScheduler.cpp 58 | 59 | RTCP_SRC_FILES := $(LOCAL_PATH)/../../RTSPClient/RTCP/HashTable.cpp \ 60 | $(LOCAL_PATH)/../../RTSPClient/RTCP/BasicHashTable.cpp \ 61 | $(LOCAL_PATH)/../../RTSPClient/RTCP/OutPacketBuffer.cpp \ 62 | $(LOCAL_PATH)/../../RTSPClient/RTCP/RTCP.cpp \ 63 | $(LOCAL_PATH)/../../RTSPClient/RTCP/rtcp_from_spec.c \ 64 | $(LOCAL_PATH)/../../RTSPClient/RTCP/RTCPInstance.cpp 65 | 66 | RTP_SRC_FILES := $(LOCAL_PATH)/../../RTSPClient/RTP/RTPPacketBuffer.cpp \ 67 | $(LOCAL_PATH)/../../RTSPClient/RTP/RTPSource.cpp \ 68 | $(LOCAL_PATH)/../../RTSPClient/RTP/H264RTPSource.cpp \ 69 | $(LOCAL_PATH)/../../RTSPClient/RTP/H265RTPSource.cpp \ 70 | $(LOCAL_PATH)/../../RTSPClient/RTP/MPEG4ESRTPSource.cpp \ 71 | $(LOCAL_PATH)/../../RTSPClient/RTP/JPEGRTPSource.cpp \ 72 | $(LOCAL_PATH)/../../RTSPClient/RTP/AC3RTPSource.cpp \ 73 | $(LOCAL_PATH)/../../RTSPClient/RTP/MPEG4GenericRTPSource.cpp 74 | 75 | RTSPCLIENT_SRC_FILES := $(LOCAL_PATH)/../../RTSPClient/RTSP/MediaSession.cpp \ 76 | $(LOCAL_PATH)/../../RTSPClient/RTSP/RTSPClient.cpp 77 | 78 | RTSPSERVER_SRC_FILES := $(LOCAL_PATH)/../../RTSPServer/RTSP/ClientSocket.cpp \ 79 | $(LOCAL_PATH)/../../RTSPServer/RTSP/LiveServerMediaSession.cpp \ 80 | $(LOCAL_PATH)/../../RTSPServer/RTSP/OnDemandServerMediaSession.cpp \ 81 | $(LOCAL_PATH)/../../RTSPServer/RTSP/RTSPServer.cpp \ 82 | $(LOCAL_PATH)/../../RTSPServer/RTSP/ServerMediaSession.cpp 83 | 84 | LOCAL_SRC_FILES += $(OS_COMMON_SRC_FILES) 85 | LOCAL_SRC_FILES += $(COMMON_SRC_FILES) 86 | LOCAL_SRC_FILES += $(RTSPCLIENT_COMMON_SRC_FILES) 87 | LOCAL_SRC_FILES += $(RTSPSERVER_COMMON_SRC_FILES) 88 | LOCAL_SRC_FILES += $(UTIL_SRC_FILES) 89 | LOCAL_SRC_FILES += $(SOCK_SRC_FILES) 90 | LOCAL_SRC_FILES += $(RTCP_SRC_FILES) 91 | LOCAL_SRC_FILES += $(RTP_SRC_FILES) 92 | LOCAL_SRC_FILES += $(RTSPCLIENT_SRC_FILES) 93 | LOCAL_SRC_FILES += $(RTSPSERVER_SRC_FILES) 94 | 95 | include $(BUILD_SHARED_LIBRARY) 96 | -------------------------------------------------------------------------------- /Util/Base64.cpp: -------------------------------------------------------------------------------- 1 | /********** 2 | This library is free software; you can redistribute it and/or modify it under 3 | the terms of the GNU Lesser General Public License as published by the 4 | Free Software Foundation; either version 2.1 of the License, or (at your 5 | option) any later version. (See .) 6 | 7 | This library is distributed in the hope that it will be useful, but WITHOUT 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 10 | more details. 11 | 12 | You should have received a copy of the GNU Lesser General Public License 13 | along with this library; if not, write to the Free Software Foundation, Inc., 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 15 | **********/ 16 | // "liveMedia" 17 | // Copyright (c) 1996-2008 Live Networks, Inc. All rights reserved. 18 | // Base64 encoding and decoding 19 | // implementation 20 | 21 | #include "Base64.hh" 22 | #include "util.h" 23 | #include 24 | 25 | static char base64DecodeTable[256]; 26 | 27 | static void initBase64DecodeTable() { 28 | int i; 29 | for (i = 0; i < 256; ++i) base64DecodeTable[i] = (char)0x80; 30 | // default value: invalid 31 | 32 | for (i = 'A'; i <= 'Z'; ++i) base64DecodeTable[i] = 0 + (i - 'A'); 33 | for (i = 'a'; i <= 'z'; ++i) base64DecodeTable[i] = 26 + (i - 'a'); 34 | for (i = '0'; i <= '9'; ++i) base64DecodeTable[i] = 52 + (i - '0'); 35 | base64DecodeTable[(unsigned char)'+'] = 62; 36 | base64DecodeTable[(unsigned char)'/'] = 63; 37 | base64DecodeTable[(unsigned char)'='] = 0; 38 | } 39 | 40 | unsigned char* base64Decode(char* in, unsigned& resultSize, 41 | bool trimTrailingZeros) { 42 | static bool haveInitedBase64DecodeTable = false; 43 | if (!haveInitedBase64DecodeTable) { 44 | initBase64DecodeTable(); 45 | haveInitedBase64DecodeTable = true; 46 | } 47 | 48 | unsigned char* out = (unsigned char*)strDupSize(in); // ensures we have enough space 49 | int k = 0; 50 | int const jMax = strlen(in) - 3; 51 | // in case "in" is not a multiple of 4 bytes (although it should be) 52 | for (int j = 0; j < jMax; j += 4) { 53 | char inTmp[4], outTmp[4]; 54 | for (int i = 0; i < 4; ++i) { 55 | inTmp[i] = in[i+j]; 56 | outTmp[i] = base64DecodeTable[(unsigned char)inTmp[i]]; 57 | if ((outTmp[i]&0x80) != 0) outTmp[i] = 0; // pretend the input was 'A' 58 | } 59 | 60 | out[k++] = (outTmp[0]<<2) | (outTmp[1]>>4); 61 | out[k++] = (outTmp[1]<<4) | (outTmp[2]>>2); 62 | out[k++] = (outTmp[2]<<6) | outTmp[3]; 63 | } 64 | 65 | if (trimTrailingZeros) { 66 | while (k > 0 && out[k-1] == '\0') --k; 67 | } 68 | resultSize = k; 69 | unsigned char* result = new unsigned char[resultSize]; 70 | memmove(result, out, resultSize); 71 | delete[] out; 72 | 73 | return result; 74 | } 75 | 76 | static const char base64Char[] = 77 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 78 | 79 | char* base64Encode(char const* origSigned, unsigned origLength) { 80 | unsigned char const* orig = (unsigned char const*)origSigned; // in case any input bytes have the MSB set 81 | if (orig == NULL) return NULL; 82 | 83 | unsigned const numOrig24BitValues = origLength/3; 84 | bool havePadding = origLength > numOrig24BitValues*3; 85 | bool havePadding2 = origLength == numOrig24BitValues*3 + 2; 86 | unsigned const numResultBytes = 4*(numOrig24BitValues + havePadding); 87 | char* result = new char[numResultBytes+1]; // allow for trailing '\0' 88 | 89 | // Map each full group of 3 input bytes into 4 output base-64 characters: 90 | unsigned i; 91 | for (i = 0; i < numOrig24BitValues; ++i) { 92 | result[4*i+0] = base64Char[(orig[3*i]>>2)&0x3F]; 93 | result[4*i+1] = base64Char[(((orig[3*i]&0x3)<<4) | (orig[3*i+1]>>4))&0x3F]; 94 | result[4*i+2] = base64Char[((orig[3*i+1]<<2) | (orig[3*i+2]>>6))&0x3F]; 95 | result[4*i+3] = base64Char[orig[3*i+2]&0x3F]; 96 | } 97 | 98 | // Now, take padding into account. (Note: i == numOrig24BitValues) 99 | if (havePadding) { 100 | result[4*i+0] = base64Char[(orig[3*i]>>2)&0x3F]; 101 | if (havePadding2) { 102 | result[4*i+1] = base64Char[(((orig[3*i]&0x3)<<4) | (orig[3*i+1]>>4))&0x3F]; 103 | result[4*i+2] = base64Char[(orig[3*i+1]<<2)&0x3F]; 104 | } else { 105 | result[4*i+1] = base64Char[((orig[3*i]&0x3)<<4)&0x3F]; 106 | result[4*i+2] = '='; 107 | } 108 | result[4*i+3] = '='; 109 | } 110 | 111 | result[numResultBytes] = '\0'; 112 | return result; 113 | } 114 | -------------------------------------------------------------------------------- /win32/RTSPServerLib/RTSPServerLib.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {ebe5b75e-8a47-4788-b9cf-5b2ab0027380} 6 | 7 | 8 | {61b78d35-8643-4aee-b67e-58f1a737b0f6} 9 | 10 | 11 | {69793a84-22d3-484c-9c3a-3b378df3f32a} 12 | 13 | 14 | {bdedba72-b46f-40d6-b2ea-d36fba1056bf} 15 | 16 | 17 | {c0b909b5-2ece-48d0-bb48-2c45cdc3e3db} 18 | 19 | 20 | 21 | 22 | Common 23 | 24 | 25 | Common 26 | 27 | 28 | Common 29 | 30 | 31 | Common 32 | 33 | 34 | Util 35 | 36 | 37 | Util 38 | 39 | 40 | Sock 41 | 42 | 43 | Sock 44 | 45 | 46 | Sock 47 | 48 | 49 | RTSP 50 | 51 | 52 | RTSP 53 | 54 | 55 | RTSP 56 | 57 | 58 | RTSP 59 | 60 | 61 | RTSP 62 | 63 | 64 | OS_Common 65 | 66 | 67 | 68 | 69 | Common 70 | 71 | 72 | Common 73 | 74 | 75 | Common 76 | 77 | 78 | Util 79 | 80 | 81 | Util 82 | 83 | 84 | Util 85 | 86 | 87 | Util 88 | 89 | 90 | Sock 91 | 92 | 93 | Sock 94 | 95 | 96 | Sock 97 | 98 | 99 | RTSP 100 | 101 | 102 | RTSP 103 | 104 | 105 | RTSP 106 | 107 | 108 | RTSP 109 | 110 | 111 | RTSP 112 | 113 | 114 | 115 | 116 | Util 117 | 118 | 119 | -------------------------------------------------------------------------------- /tests/RTSPLiveStreamer.cpp: -------------------------------------------------------------------------------- 1 | #include "RTSPLiveStreamer.h" 2 | #include "RTSPCommonEnv.h" 3 | #include "LiveServerMediaSession.h" 4 | 5 | RTSPLiveStreamer::RTSPLiveStreamer() : m_pServerSession(NULL), m_pSessionName(NULL) 6 | { 7 | m_pRtspClient = new RTSPClient(); 8 | m_pRtspServer = RTSPServer::instance(); 9 | m_nState = STREAMER_STATE_STOPPED; 10 | } 11 | 12 | RTSPLiveStreamer::~RTSPLiveStreamer() 13 | { 14 | delete[] m_pSessionName; 15 | delete m_pRtspClient; 16 | } 17 | 18 | int RTSPLiveStreamer::open(const char *url, int stream_type, const char *sessionName) 19 | { 20 | if (state() != STREAMER_STATE_STOPPED) 21 | return -1; 22 | 23 | if (m_pRtspServer->lookupServerMediaSession(sessionName) != NULL) { 24 | DPRINTF("failed to open server session, session %s already exists\n", sessionName); 25 | return -1; 26 | } 27 | 28 | int ret = m_pRtspClient->openURL(url, stream_type, 2, true); 29 | if (ret < 0) { 30 | DPRINTF("%s open failed\n", url); 31 | return ret; 32 | } 33 | 34 | delete[] m_pSessionName; 35 | m_pSessionName = strDup(sessionName); 36 | 37 | m_nState = STREAMER_STATE_OPENED; 38 | 39 | return 0; 40 | } 41 | 42 | int RTSPLiveStreamer::run() 43 | { 44 | if (state() != STREAMER_STATE_OPENED) 45 | return -1; 46 | 47 | if (m_pRtspClient->playURL(NULL, NULL, NULL, NULL, onRtpReceived, this, onRtcpReceived, this) < 0) 48 | return -1; 49 | 50 | m_pServerSession = new LiveServerMediaSession(m_pSessionName, "DXMediaPlayer", "Session streamed by \"DXMediaPlayer\"", false, NULL); 51 | 52 | MediaSubsessionIterator *iter = new MediaSubsessionIterator(m_pRtspClient->mediaSession()); 53 | MediaSubsession *subsession = NULL; 54 | while ((subsession=iter->next()) != NULL) { 55 | char *sdpLines; 56 | char *controlPath = checkControlPath(subsession->controlPath()); 57 | 58 | if (strcmp(controlPath, subsession->controlPath()) == 0) 59 | sdpLines = strDup(subsession->savedSDPLines()); 60 | else 61 | sdpLines = updateSdpLines(subsession->savedSDPLines(), subsession->controlPath(), controlPath); 62 | 63 | m_pServerSession->addSubsession( 64 | new LiveServerMediaSubsession( 65 | controlPath, 66 | sdpLines, 67 | subsession->codecName(), 68 | subsession->rtpPayloadFormat(), 69 | subsession->rtpTimestampFrequency()) 70 | ); 71 | 72 | if (controlPath) delete[] controlPath; 73 | if (sdpLines) delete[] sdpLines; 74 | } 75 | 76 | delete iter; 77 | 78 | m_pRtspServer->addServerMediaSession(m_pServerSession); 79 | 80 | m_nState = STREAMER_STATE_RUNNING; 81 | 82 | return 0; 83 | } 84 | 85 | void RTSPLiveStreamer::close() 86 | { 87 | m_pRtspClient->closeURL(); 88 | m_pRtspServer->deleteServerMediaSession(m_pServerSession); 89 | m_pServerSession = NULL; 90 | delete[] m_pSessionName; m_pSessionName = NULL; 91 | m_nState = STREAMER_STATE_STOPPED; 92 | } 93 | 94 | void RTSPLiveStreamer::onRtpReceived(void *arg, const char *trackId, char *buf, int len) 95 | { 96 | RTSPLiveStreamer *streamer = (RTSPLiveStreamer *)arg; 97 | streamer->onRtpReceived1(trackId, buf, len); 98 | } 99 | 100 | void RTSPLiveStreamer::onRtpReceived1(const char *trackId, char *buf, int len) 101 | { 102 | if (m_pServerSession) 103 | m_pServerSession->sendClientRtp(trackId, buf, len); 104 | } 105 | 106 | void RTSPLiveStreamer::onRtcpReceived(void *arg, const char *trackId, char *buf, int len) 107 | { 108 | RTSPLiveStreamer *streamer = (RTSPLiveStreamer *)arg; 109 | streamer->onRtcpReceived1(trackId, buf, len); 110 | } 111 | 112 | void RTSPLiveStreamer::onRtcpReceived1(const char *trackId, char *buf, int len) 113 | { 114 | if (m_pServerSession) 115 | m_pServerSession->sendClientRtcp(trackId, buf, len); 116 | } 117 | 118 | char* RTSPLiveStreamer::checkControlPath(const char *controlPath) 119 | { 120 | const char *ptr = &controlPath[strlen(controlPath)-1]; 121 | while (ptr >= controlPath) { 122 | if (*ptr == '/') 123 | break; 124 | ptr--; 125 | } 126 | 127 | char *newControlPath; 128 | 129 | if (*ptr == '/') 130 | newControlPath = strDup(ptr+1); 131 | else 132 | newControlPath = strDup(controlPath); 133 | 134 | return newControlPath; 135 | } 136 | 137 | char* RTSPLiveStreamer::updateSdpLines(const char *sdpLines, const char *orgControlPath, const char *newControlPath) 138 | { 139 | char* sdpLinesDup = strDup(sdpLines); 140 | 141 | int len = strlen(sdpLines) + strlen(newControlPath); 142 | char *newSdpLines = new char[len]; 143 | memset(newSdpLines, 0, len); 144 | char *nextLineStart = sdpLinesDup; 145 | char *lineStart; 146 | 147 | while (1) { 148 | lineStart = nextLineStart; 149 | if (lineStart == NULL) break; 150 | 151 | nextLineStart = getLine(lineStart); 152 | 153 | if (strstr(lineStart, orgControlPath)) { 154 | char tmp[256] = {0}; 155 | sprintf(tmp, "a=control:%s\r\n", newControlPath); 156 | strcat(newSdpLines, tmp); 157 | } else { 158 | strcat(newSdpLines, lineStart); 159 | strcat(newSdpLines, "\r\n"); 160 | } 161 | } 162 | 163 | delete[] sdpLinesDup; 164 | return newSdpLines; 165 | } 166 | -------------------------------------------------------------------------------- /RTSPServer/Common/MyList.h: -------------------------------------------------------------------------------- 1 | #ifndef __MY_LIST_H__ 2 | #define __MY_LIST_H__ 3 | 4 | #include "Mutex.h" 5 | 6 | template 7 | class MyList; 8 | 9 | template 10 | class MyListNode 11 | { 12 | private: 13 | MyListNode(DT *nodeData, MyListNode *nextPtr); 14 | 15 | DT *dataItem; 16 | MyListNode *next; 17 | MyListNode *prev; 18 | 19 | friend class MyList
; 20 | }; 21 | 22 | template 23 | MyListNode
::MyListNode(DT *nodeData, MyListNode
*nextPtr) : dataItem(nodeData) 24 | { 25 | next = nextPtr; 26 | prev = NULL; 27 | } 28 | 29 | template 30 | class MyList 31 | { 32 | public: 33 | MyList(); 34 | ~MyList(); 35 | 36 | void insert(DT *newData); 37 | void remove(); 38 | void remove(DT *node); 39 | DT* deleteCursor(); 40 | 41 | void clearList(); 42 | void clear(); 43 | 44 | void gotoBeginCursor(); 45 | DT* getNextCursor(); 46 | void getNext(); 47 | DT* getCursor(); 48 | int count() { return m_nCount; } 49 | 50 | void lock(); 51 | void unlock(); 52 | 53 | private: 54 | MyListNode
*m_pHead, *m_pTail; 55 | MyListNode
*m_pCursor; 56 | MUTEX m_hMutex; 57 | int m_nCount; 58 | }; 59 | 60 | template 61 | MyList
::MyList() 62 | { 63 | m_pHead = m_pTail = NULL; 64 | m_nCount = 0; 65 | MUTEX_INIT(&m_hMutex); 66 | } 67 | 68 | template 69 | MyList
::~MyList() 70 | { 71 | clear(); 72 | MUTEX_DESTROY(&m_hMutex); 73 | } 74 | 75 | template 76 | void MyList
::lock() 77 | { 78 | MUTEX_LOCK(&m_hMutex); 79 | } 80 | 81 | template 82 | void MyList
::unlock() 83 | { 84 | MUTEX_UNLOCK(&m_hMutex); 85 | } 86 | 87 | template 88 | void MyList
::insert(DT *newData) 89 | { 90 | MyListNode
* newNode = new MyListNode
(newData,NULL); 91 | 92 | if(m_pHead == NULL) 93 | { 94 | m_pHead = newNode; 95 | m_pTail = newNode; 96 | } 97 | else 98 | { 99 | newNode->prev = m_pTail; 100 | m_pTail->next = newNode; 101 | m_pTail = newNode; 102 | } 103 | 104 | m_nCount++; 105 | } 106 | 107 | template 108 | void MyList
::remove() 109 | { 110 | MyListNode
* tmp = NULL; 111 | DT *data; 112 | 113 | if(m_pCursor == NULL) return; 114 | 115 | tmp = m_pCursor; 116 | 117 | if(m_pCursor == m_pHead ) 118 | { 119 | if(m_pCursor->next == NULL) 120 | m_pHead = m_pTail = NULL; 121 | else 122 | m_pHead = m_pCursor->next; 123 | 124 | } 125 | else if(m_pCursor == m_pTail) 126 | { 127 | m_pTail = m_pTail->prev; 128 | m_pTail->next = NULL; 129 | } 130 | else 131 | { 132 | m_pCursor->prev->next = m_pCursor->next; 133 | m_pCursor->next->prev = m_pCursor->prev; 134 | } 135 | 136 | // destroy the node 137 | if(tmp->dataItem) 138 | { 139 | data = tmp->dataItem; 140 | delete data; 141 | data = NULL; 142 | } 143 | delete tmp; 144 | 145 | m_pCursor = NULL; 146 | m_nCount--; 147 | } 148 | 149 | template 150 | DT* MyList
::deleteCursor() 151 | { 152 | MyListNode
* tmp = NULL; 153 | DT *data = NULL; 154 | MyListNode
* tmp1= NULL; 155 | 156 | if(m_pCursor == NULL) 157 | return NULL; 158 | 159 | tmp1 = m_pCursor->next; 160 | 161 | tmp = m_pCursor; 162 | 163 | if(m_pCursor == m_pHead) 164 | { 165 | if(m_pCursor->next == NULL) 166 | m_pHead = m_pTail = NULL; 167 | else 168 | m_pHead = m_pCursor->next; 169 | 170 | } 171 | else if(m_pCursor == m_pTail) 172 | { 173 | m_pTail = m_pTail->prev; 174 | m_pTail->next = NULL; 175 | } 176 | else 177 | { 178 | m_pCursor->prev->next = m_pCursor->next; 179 | m_pCursor->next->prev = m_pCursor->prev; 180 | } 181 | 182 | // destroy the node 183 | if(tmp->dataItem) 184 | { 185 | data = tmp->dataItem; 186 | } 187 | delete tmp; 188 | 189 | m_pCursor = tmp1; 190 | 191 | m_nCount--; 192 | return data; 193 | } 194 | 195 | template 196 | void MyList
::clear() 197 | { 198 | MyListNode
* tmp; 199 | DT *data; 200 | 201 | m_pCursor = NULL; 202 | while (m_pHead != NULL){ 203 | tmp = m_pHead; 204 | m_pHead = m_pHead->next; 205 | data = tmp->dataItem; 206 | delete data; 207 | delete tmp; 208 | } 209 | 210 | m_pHead = m_pTail = m_pCursor= NULL; 211 | m_nCount = 0; 212 | } 213 | 214 | template 215 | void MyList
::clearList() 216 | { 217 | MyListNode
* tmp; 218 | 219 | m_pCursor = NULL; 220 | while (m_pHead != NULL){ 221 | tmp = m_pHead; 222 | m_pHead = m_pHead->next; 223 | delete tmp; 224 | } 225 | 226 | m_pHead = m_pTail = m_pCursor= NULL; 227 | m_nCount = 0; 228 | } 229 | 230 | template 231 | void MyList
::gotoBeginCursor() 232 | { 233 | m_pCursor = m_pHead; 234 | } 235 | 236 | template 237 | DT* MyList
::getNextCursor() 238 | { 239 | DT *data; 240 | 241 | if(m_pCursor != NULL) 242 | { 243 | data = m_pCursor->dataItem; 244 | m_pCursor = m_pCursor->next; 245 | return data; 246 | } 247 | else 248 | { 249 | return NULL; 250 | } 251 | } 252 | 253 | template 254 | void MyList
::getNext() 255 | { 256 | if(m_pCursor != NULL) 257 | m_pCursor = m_pCursor->next; 258 | } 259 | 260 | template 261 | DT* MyList
::getCursor() 262 | { 263 | DT *data; 264 | 265 | if(m_pCursor != NULL) 266 | { 267 | data = m_pCursor->dataItem; 268 | return data; 269 | } 270 | else 271 | { 272 | return NULL; 273 | } 274 | } 275 | 276 | #endif 277 | -------------------------------------------------------------------------------- /RTSPClient/RTCP/RTCP.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTCP_H__ 2 | #define __RTCP_H__ 3 | 4 | #include "HashTable.hh" 5 | #include "RTSPCommon.h" 6 | #include "util.h" 7 | 8 | class RTPReceptionStats; // forward 9 | 10 | class RTPReceptionStatsDB { 11 | public: 12 | unsigned totNumPacketsReceived() const { return fTotNumPacketsReceived; } 13 | unsigned numActiveSourcesSinceLastReset() const { 14 | return fNumActiveSourcesSinceLastReset; 15 | } 16 | 17 | void reset(); 18 | // resets periodic stats (called each time they're used to 19 | // generate a reception report) 20 | 21 | class Iterator { 22 | public: 23 | Iterator(RTPReceptionStatsDB& receptionStatsDB); 24 | virtual ~Iterator(); 25 | 26 | RTPReceptionStats* next(bool includeInactiveSources = false); 27 | // NULL if none 28 | 29 | private: 30 | HashTable::Iterator* fIter; 31 | }; 32 | 33 | // The following is called whenever a RTP packet is received: 34 | void noteIncomingPacket(u_int32_t SSRC, u_int16_t seqNum, 35 | u_int32_t rtpTimestamp, 36 | unsigned timestampFrequency, 37 | bool useForJitterCalculation, 38 | struct timeval& resultPresentationTime, 39 | bool& resultHasBeenSyncedUsingRTCP, 40 | unsigned packetSize /* payload only */); 41 | 42 | // The following is called whenever a RTCP SR packet is received: 43 | void noteIncomingSR(u_int32_t SSRC, 44 | u_int32_t ntpTimestampMSW, u_int32_t ntpTimestampLSW, 45 | u_int32_t rtpTimestamp); 46 | 47 | // The following is called when a RTCP BYE packet is received: 48 | void removeRecord(u_int32_t SSRC); 49 | 50 | RTPReceptionStats* lookup(u_int32_t SSRC) const; 51 | 52 | protected: // constructor and destructor, called only by RTPSource: 53 | friend class RTPSource; 54 | RTPReceptionStatsDB(); 55 | virtual ~RTPReceptionStatsDB(); 56 | 57 | protected: 58 | void add(u_int32_t SSRC, RTPReceptionStats* stats); 59 | 60 | protected: 61 | friend class Iterator; 62 | unsigned fNumActiveSourcesSinceLastReset; 63 | 64 | private: 65 | HashTable* fTable; 66 | unsigned fTotNumPacketsReceived; // for all SSRCs 67 | }; 68 | 69 | class RTPReceptionStats { 70 | public: 71 | u_int32_t SSRC() const { return fSSRC; } 72 | unsigned numPacketsReceivedSinceLastReset() const { 73 | return fNumPacketsReceivedSinceLastReset; 74 | } 75 | unsigned totNumPacketsReceived() const { return fTotNumPacketsReceived; } 76 | double totNumKBytesReceived() const; 77 | 78 | unsigned totNumPacketsExpected() const { 79 | return fHighestExtSeqNumReceived - fBaseExtSeqNumReceived; 80 | } 81 | 82 | unsigned baseExtSeqNumReceived() const { return fBaseExtSeqNumReceived; } 83 | unsigned lastResetExtSeqNumReceived() const { 84 | return fLastResetExtSeqNumReceived; 85 | } 86 | unsigned highestExtSeqNumReceived() const { 87 | return fHighestExtSeqNumReceived; 88 | } 89 | 90 | unsigned jitter() const; 91 | 92 | unsigned lastReceivedSR_NTPmsw() const { return fLastReceivedSR_NTPmsw; } 93 | unsigned lastReceivedSR_NTPlsw() const { return fLastReceivedSR_NTPlsw; } 94 | struct timeval const& lastReceivedSR_time() const { 95 | return fLastReceivedSR_time; 96 | } 97 | 98 | unsigned minInterPacketGapUS() const { return fMinInterPacketGapUS; } 99 | unsigned maxInterPacketGapUS() const { return fMaxInterPacketGapUS; } 100 | struct timeval const& totalInterPacketGaps() const { 101 | return fTotalInterPacketGaps; 102 | } 103 | 104 | protected: 105 | // called only by RTPReceptionStatsDB: 106 | friend class RTPReceptionStatsDB; 107 | RTPReceptionStats(u_int32_t SSRC, u_int16_t initialSeqNum); 108 | RTPReceptionStats(u_int32_t SSRC); 109 | virtual ~RTPReceptionStats(); 110 | 111 | private: 112 | void noteIncomingPacket(u_int16_t seqNum, u_int32_t rtpTimestamp, 113 | unsigned timestampFrequency, 114 | bool useForJitterCalculation, 115 | struct timeval& resultPresentationTime, 116 | bool& resultHasBeenSyncedUsingRTCP, 117 | unsigned packetSize /* payload only */); 118 | void noteIncomingSR(u_int32_t ntpTimestampMSW, u_int32_t ntpTimestampLSW, 119 | u_int32_t rtpTimestamp); 120 | void init(u_int32_t SSRC); 121 | void initSeqNum(u_int16_t initialSeqNum); 122 | void reset(); 123 | // resets periodic stats (called each time they're used to 124 | // generate a reception report) 125 | 126 | protected: 127 | u_int32_t fSSRC; 128 | unsigned fNumPacketsReceivedSinceLastReset; 129 | unsigned fTotNumPacketsReceived; 130 | u_int32_t fTotBytesReceived_hi, fTotBytesReceived_lo; 131 | bool fHaveSeenInitialSequenceNumber; 132 | unsigned fBaseExtSeqNumReceived; 133 | unsigned fLastResetExtSeqNumReceived; 134 | unsigned fHighestExtSeqNumReceived; 135 | int fLastTransit; // used in the jitter calculation 136 | u_int32_t fPreviousPacketRTPTimestamp; 137 | double fJitter; 138 | // The following are recorded whenever we receive a RTCP SR for this SSRC: 139 | unsigned fLastReceivedSR_NTPmsw; // NTP timestamp (from SR), most-signif 140 | unsigned fLastReceivedSR_NTPlsw; // NTP timestamp (from SR), least-signif 141 | struct timeval fLastReceivedSR_time; 142 | struct timeval fLastPacketReceptionTime; 143 | unsigned fMinInterPacketGapUS, fMaxInterPacketGapUS; 144 | struct timeval fTotalInterPacketGaps; 145 | 146 | private: 147 | // Used to convert from RTP timestamp to 'wall clock' time: 148 | bool fHasBeenSynchronized; 149 | u_int32_t fSyncTimestamp; 150 | struct timeval fSyncTime; 151 | }; 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /RTSPClient/Common/DigestAuthentication.cpp: -------------------------------------------------------------------------------- 1 | /********** 2 | This library is free software; you can redistribute it and/or modify it under 3 | the terms of the GNU Lesser General Public License as published by the 4 | Free Software Foundation; either version 2.1 of the License, or (at your 5 | option) any later version. (See .) 6 | 7 | This library is distributed in the hope that it will be useful, but WITHOUT 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 10 | more details. 11 | 12 | You should have received a copy of the GNU Lesser General Public License 13 | along with this library; if not, write to the Free Software Foundation, Inc., 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 15 | **********/ 16 | // "liveMedia" 17 | // Copyright (c) 1996-2008 Live Networks, Inc. All rights reserved. 18 | // A class used for digest authentication. 19 | // Implementation 20 | 21 | #include "DigestAuthentication.hh" 22 | #include "our_md5.h" 23 | #include "util.h" 24 | #include 25 | #include 26 | #include 27 | 28 | Authenticator::Authenticator() { 29 | assign(NULL, NULL, NULL, NULL, false); 30 | } 31 | 32 | Authenticator::Authenticator(const Authenticator& orig) { 33 | assign(orig.realm(), orig.nonce(), orig.username(), orig.password(), 34 | orig.fPasswordIsMD5); 35 | } 36 | 37 | Authenticator& Authenticator::operator=(const Authenticator& rightSide) { 38 | if (&rightSide != this) { 39 | reset(); 40 | assign(rightSide.realm(), rightSide.nonce(), 41 | rightSide.username(), rightSide.password(), rightSide.fPasswordIsMD5); 42 | } 43 | 44 | return *this; 45 | } 46 | 47 | Authenticator::~Authenticator() { 48 | reset(); 49 | } 50 | 51 | void Authenticator::reset() { 52 | resetRealmAndNonce(); 53 | resetUsernameAndPassword(); 54 | } 55 | 56 | void Authenticator::setRealmAndNonce(char const* realm, char const* nonce) { 57 | resetRealmAndNonce(); 58 | assignRealmAndNonce(realm, nonce); 59 | } 60 | 61 | void Authenticator::setRealmAndRandomNonce(char const* realm) { 62 | resetRealmAndNonce(); 63 | 64 | // Construct data to seed the random nonce: 65 | struct { 66 | struct timeval timestamp; 67 | unsigned counter; 68 | } seedData; 69 | gettimeofday(&seedData.timestamp, NULL); 70 | static unsigned counter = 0; 71 | seedData.counter = ++counter; 72 | 73 | // Use MD5 to compute a 'random' nonce from this seed data: 74 | char nonceBuf[33]; 75 | our_MD5Data((unsigned char*)(&seedData), sizeof seedData, nonceBuf); 76 | 77 | assignRealmAndNonce(realm, nonceBuf); 78 | } 79 | 80 | void Authenticator::setUsernameAndPassword(char const* username, 81 | char const* password, 82 | bool passwordIsMD5) { 83 | resetUsernameAndPassword(); 84 | assignUsernameAndPassword(username, password, passwordIsMD5); 85 | } 86 | 87 | char const* Authenticator::computeDigestResponse(char const* cmd, 88 | char const* url) const { 89 | // The "response" field is computed as: 90 | // md5(md5(::)::md5(:)) 91 | // or, if "fPasswordIsMD5" is true: 92 | // md5(::md5(:)) 93 | char ha1Buf[33]; 94 | if (fPasswordIsMD5) { 95 | strncpy(ha1Buf, password(), 32); 96 | ha1Buf[32] = '\0'; // just in case 97 | } else { 98 | unsigned const ha1DataLen = strlen(username()) + 1 99 | + strlen(realm()) + 1 + strlen(password()); 100 | unsigned char* ha1Data = new unsigned char[ha1DataLen+1]; 101 | sprintf((char*)ha1Data, "%s:%s:%s", username(), realm(), password()); 102 | our_MD5Data(ha1Data, ha1DataLen, ha1Buf); 103 | delete[] ha1Data; 104 | } 105 | 106 | unsigned const ha2DataLen = strlen(cmd) + 1 + strlen(url); 107 | unsigned char* ha2Data = new unsigned char[ha2DataLen+1]; 108 | sprintf((char*)ha2Data, "%s:%s", cmd, url); 109 | char ha2Buf[33]; 110 | our_MD5Data(ha2Data, ha2DataLen, ha2Buf); 111 | delete[] ha2Data; 112 | 113 | unsigned const digestDataLen 114 | = 32 + 1 + strlen(nonce()) + 1 + 32; 115 | unsigned char* digestData = new unsigned char[digestDataLen+1]; 116 | sprintf((char*)digestData, "%s:%s:%s", 117 | ha1Buf, nonce(), ha2Buf); 118 | char const* result = our_MD5Data(digestData, digestDataLen, NULL); 119 | delete[] digestData; 120 | return result; 121 | } 122 | 123 | void Authenticator::reclaimDigestResponse(char const* responseStr) const { 124 | free((char*)responseStr); // NOT delete, because it was malloc-allocated 125 | } 126 | 127 | void Authenticator::resetRealmAndNonce() { 128 | delete[] fRealm; fRealm = NULL; 129 | delete[] fNonce; fNonce = NULL; 130 | } 131 | 132 | void Authenticator::resetUsernameAndPassword() { 133 | delete[] fUsername; fUsername = NULL; 134 | delete[] fPassword; fPassword = NULL; 135 | fPasswordIsMD5 = false; 136 | } 137 | 138 | void Authenticator::assignRealmAndNonce(char const* realm, char const* nonce) { 139 | fRealm = strDup(realm); 140 | fNonce = strDup(nonce); 141 | } 142 | 143 | void Authenticator 144 | ::assignUsernameAndPassword(char const* username, char const* password, 145 | bool passwordIsMD5) { 146 | fUsername = strDup(username); 147 | fPassword = strDup(password); 148 | fPasswordIsMD5 = passwordIsMD5; 149 | } 150 | 151 | void Authenticator::assign(char const* realm, char const* nonce, 152 | char const* username, char const* password, 153 | bool passwordIsMD5) { 154 | assignRealmAndNonce(realm, nonce); 155 | assignUsernameAndPassword(username, password, passwordIsMD5); 156 | } 157 | -------------------------------------------------------------------------------- /RTSPClient/Common/BitVector.cpp: -------------------------------------------------------------------------------- 1 | /********** 2 | This library is free software; you can redistribute it and/or modify it under 3 | the terms of the GNU Lesser General Public License as published by the 4 | Free Software Foundation; either version 2.1 of the License, or (at your 5 | option) any later version. (See .) 6 | 7 | This library is distributed in the hope that it will be useful, but WITHOUT 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 10 | more details. 11 | 12 | You should have received a copy of the GNU Lesser General Public License 13 | along with this library; if not, write to the Free Software Foundation, Inc., 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 15 | **********/ 16 | // "liveMedia" 17 | // Copyright (c) 1996-2014 Live Networks, Inc. All rights reserved. 18 | // Bit Vector data structure 19 | // Implementation 20 | 21 | #include "BitVector.hh" 22 | 23 | BitVector::BitVector(unsigned char* baseBytePtr, 24 | unsigned baseBitOffset, 25 | unsigned totNumBits) { 26 | setup(baseBytePtr, baseBitOffset, totNumBits); 27 | } 28 | 29 | void BitVector::setup(unsigned char* baseBytePtr, 30 | unsigned baseBitOffset, 31 | unsigned totNumBits) { 32 | fBaseBytePtr = baseBytePtr; 33 | fBaseBitOffset = baseBitOffset; 34 | fTotNumBits = totNumBits; 35 | fCurBitIndex = 0; 36 | } 37 | 38 | static unsigned char const singleBitMask[8] 39 | = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; 40 | 41 | #define MAX_LENGTH 32 42 | 43 | void BitVector::putBits(unsigned from, unsigned numBits) { 44 | if (numBits == 0) return; 45 | 46 | unsigned char tmpBuf[4]; 47 | unsigned overflowingBits = 0; 48 | 49 | if (numBits > MAX_LENGTH) { 50 | numBits = MAX_LENGTH; 51 | } 52 | 53 | if (numBits > fTotNumBits - fCurBitIndex) { 54 | overflowingBits = numBits - (fTotNumBits - fCurBitIndex); 55 | } 56 | 57 | tmpBuf[0] = (unsigned char)(from>>24); 58 | tmpBuf[1] = (unsigned char)(from>>16); 59 | tmpBuf[2] = (unsigned char)(from>>8); 60 | tmpBuf[3] = (unsigned char)from; 61 | 62 | shiftBits(fBaseBytePtr, fBaseBitOffset + fCurBitIndex, /* to */ 63 | tmpBuf, MAX_LENGTH - numBits, /* from */ 64 | numBits - overflowingBits /* num bits */); 65 | fCurBitIndex += numBits - overflowingBits; 66 | } 67 | 68 | void BitVector::put1Bit(unsigned bit) { 69 | // The following is equivalent to "putBits(..., 1)", except faster: 70 | if (fCurBitIndex >= fTotNumBits) { /* overflow */ 71 | return; 72 | } else { 73 | unsigned totBitOffset = fBaseBitOffset + fCurBitIndex++; 74 | unsigned char mask = singleBitMask[totBitOffset%8]; 75 | if (bit) { 76 | fBaseBytePtr[totBitOffset/8] |= mask; 77 | } else { 78 | fBaseBytePtr[totBitOffset/8] &=~ mask; 79 | } 80 | } 81 | } 82 | 83 | unsigned BitVector::getBits(unsigned numBits) { 84 | if (numBits == 0) return 0; 85 | 86 | unsigned char tmpBuf[4]; 87 | unsigned overflowingBits = 0; 88 | 89 | if (numBits > MAX_LENGTH) { 90 | numBits = MAX_LENGTH; 91 | } 92 | 93 | if (numBits > fTotNumBits - fCurBitIndex) { 94 | overflowingBits = numBits - (fTotNumBits - fCurBitIndex); 95 | } 96 | 97 | shiftBits(tmpBuf, 0, /* to */ 98 | fBaseBytePtr, fBaseBitOffset + fCurBitIndex, /* from */ 99 | numBits - overflowingBits /* num bits */); 100 | fCurBitIndex += numBits - overflowingBits; 101 | 102 | unsigned result 103 | = (tmpBuf[0]<<24) | (tmpBuf[1]<<16) | (tmpBuf[2]<<8) | tmpBuf[3]; 104 | result >>= (MAX_LENGTH - numBits); // move into low-order part of word 105 | result &= (0xFFFFFFFF << overflowingBits); // so any overflow bits are 0 106 | return result; 107 | } 108 | 109 | unsigned BitVector::get1Bit() { 110 | // The following is equivalent to "getBits(1)", except faster: 111 | 112 | if (fCurBitIndex >= fTotNumBits) { /* overflow */ 113 | return 0; 114 | } else { 115 | unsigned totBitOffset = fBaseBitOffset + fCurBitIndex++; 116 | unsigned char curFromByte = fBaseBytePtr[totBitOffset/8]; 117 | unsigned result = (curFromByte >> (7-(totBitOffset%8))) & 0x01; 118 | return result; 119 | } 120 | } 121 | 122 | void BitVector::skipBits(unsigned numBits) { 123 | if (numBits > fTotNumBits - fCurBitIndex) { /* overflow */ 124 | fCurBitIndex = fTotNumBits; 125 | } else { 126 | fCurBitIndex += numBits; 127 | } 128 | } 129 | 130 | unsigned BitVector::get_expGolomb() { 131 | unsigned numLeadingZeroBits = 0; 132 | unsigned codeStart = 1; 133 | 134 | while (get1Bit() == 0 && fCurBitIndex < fTotNumBits) { 135 | ++numLeadingZeroBits; 136 | codeStart *= 2; 137 | } 138 | 139 | return codeStart - 1 + getBits(numLeadingZeroBits); 140 | } 141 | 142 | 143 | void shiftBits(unsigned char* toBasePtr, unsigned toBitOffset, 144 | unsigned char const* fromBasePtr, unsigned fromBitOffset, 145 | unsigned numBits) { 146 | if (numBits == 0) return; 147 | 148 | /* Note that from and to may overlap, if from>to */ 149 | unsigned char const* fromBytePtr = fromBasePtr + fromBitOffset/8; 150 | unsigned fromBitRem = fromBitOffset%8; 151 | unsigned char* toBytePtr = toBasePtr + toBitOffset/8; 152 | unsigned toBitRem = toBitOffset%8; 153 | 154 | while (numBits-- > 0) { 155 | unsigned char fromBitMask = singleBitMask[fromBitRem]; 156 | unsigned char fromBit = (*fromBytePtr)&fromBitMask; 157 | unsigned char toBitMask = singleBitMask[toBitRem]; 158 | 159 | if (fromBit != 0) { 160 | *toBytePtr |= toBitMask; 161 | } else { 162 | *toBytePtr &=~ toBitMask; 163 | } 164 | 165 | if (++fromBitRem == 8) { 166 | ++fromBytePtr; 167 | fromBitRem = 0; 168 | } 169 | if (++toBitRem == 8) { 170 | ++toBytePtr; 171 | toBitRem = 0; 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /RTSPClient/RTSP/RTSPClient.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTSP_CLIENT_H__ 2 | #define __RTSP_CLIENT_H__ 3 | 4 | #include "MySock.h" 5 | #include "TaskScheduler.h" 6 | #include "MediaSession.h" 7 | #include "DigestAuthentication.hh" 8 | 9 | #define RECV_BUF_SIZE (1024*1024) 10 | #define SEND_GET_PARAM_DURATION (50) 11 | 12 | typedef void (*OnCloseFunc)(void *arg, int err, int result); 13 | typedef void (*OnPacketReceiveFunc)(void *arg, const char *trackId, char *buf, int len); 14 | 15 | class RTPSource; 16 | 17 | class RTSPClient 18 | { 19 | public: 20 | RTSPClient(); 21 | virtual ~RTSPClient(); 22 | 23 | int openURL(const char *url, int streamType, int timeout = 2, bool rtpOnly = false); 24 | int playURL(FrameHandlerFunc func, void *funcData, 25 | OnCloseFunc onCloseFunc, void *onCloseFuncData, 26 | OnPacketReceiveFunc onRTPReceiveFunc = NULL, void *onRTPReceiveFuncData = NULL, 27 | OnPacketReceiveFunc onRTCPReceiveFunc = NULL, void *onRTCPReceiveFuncData = NULL); 28 | void closeURL(); 29 | void sendGetParam(); 30 | int sendPause(); 31 | int sendPlay(double start = 0.0f, double end = -1.0f, float scale = 1.0f); 32 | int sendSetParam(char *name, char *value); 33 | 34 | public: 35 | const char* videoCodec() { return fVideoCodec; } 36 | const char* audioCodec() { return fAudioCodec; } 37 | int audioChannel() { return fChannel; } 38 | int audioSampleRate() { return fAudioSampleRate; } 39 | int videoWidth() { return fVideoWidth; } 40 | int videoHeight() { return fVideoHeight; } 41 | int videoFPS() { return fVideoFps; } 42 | 43 | const uint8_t* videoExtraData() { return fVideoExtraData; } 44 | unsigned videoExtraDataSize() { return fVideoExtraDataSize; } 45 | const uint8_t* audioExtraData() { return fAudioExtraData; } 46 | unsigned audioExtraDataSize() { return fAudioExtraDataSize; } 47 | 48 | double playStartTime() { return fPlayStartTime; } 49 | double playEndTime() { return fPlayEndTime; } 50 | 51 | MediaSession& mediaSession() { return *fMediaSession; } // for rtsp server 52 | 53 | unsigned lastResponseCode() { return fLastResponseCode; } 54 | 55 | protected: 56 | char* sendOptionsCmd(const char *url, 57 | char *username = NULL, char *password = NULL, 58 | Authenticator *authenticator = NULL); 59 | 60 | char* describeURL(const char *url, 61 | Authenticator* authenticator = NULL, bool allowKasennaProtocol = false); 62 | 63 | char* describeWithPassword(char const* url, 64 | char const* username, char const* password, 65 | bool allowKasennaProtocol = false); 66 | 67 | bool setupMediaSubsession(MediaSubsession& subsession, 68 | bool streamOutgoing = false, 69 | bool streamUsingTCP = false, 70 | bool forceMulticastOnUnspecified = false); 71 | 72 | bool playMediaSession(MediaSession& session, bool response, 73 | double start = 0.0f, double end = -1.0f, float scale = 1.0f); 74 | 75 | bool pauseMediaSession(MediaSession& session); 76 | 77 | bool setMediaSessionParameter(MediaSession& session, 78 | char const* parameterName, 79 | char const* parameterValue); 80 | 81 | bool getMediaSessionParameter(MediaSession& session, 82 | char const* parameterName, 83 | char*& parameterValue); 84 | 85 | bool teardownMediaSession(MediaSession& session); 86 | 87 | protected: 88 | int connectToServer(char const *ip_addr, unsigned short port, int timeout); 89 | int sendRequest(char *str, char *tag); 90 | bool getResponse(char const* tag, 91 | unsigned& bytesRead, unsigned& responseCode, 92 | char*& firstLine, char*& nextLineStart, 93 | bool checkFor200Response = true); 94 | unsigned getResponse1(char*& responseBuffer, unsigned responseBufferSize); 95 | bool parseResponseCode(char const* line, unsigned& responseCode); 96 | bool parseTransportResponse(char const* line, 97 | char*& serverAddressStr, 98 | unsigned short& serverPortNum, 99 | unsigned char& rtpChannelId, 100 | unsigned char& rtcpChannelId); 101 | 102 | static void tcpReadHandler(void *instance, int); 103 | void tcpReadHandler1(); 104 | void tcpReadError(int result); 105 | 106 | bool lookupStreamChannelId(unsigned char channel); 107 | bool readRTSPMessage(); 108 | void readRTPOverTCP(); 109 | 110 | bool parseRTSPMessage(); 111 | void handleCmd_notSupported(char const* cseq); 112 | 113 | char const* sessionURL(MediaSession const& session) const; 114 | void constructSubsessionURL(MediaSubsession const& subsession, 115 | char const*& prefix, 116 | char const*& separator, 117 | char const*& suffix); 118 | 119 | bool parseRangeHeader(char const* buf, double& rangeStart, double& rangeEnd); 120 | bool parseRTPInfoHeader(char*& line, unsigned short& seqNum, unsigned int& timestamp); 121 | 122 | char* createAuthenticatorString(Authenticator const* authenticator, char const* cmd, char const* url); 123 | static void checkForAuthenticationFailure(unsigned responseCode, char*& nextLineStart, Authenticator* authenticator); 124 | 125 | void reset(); 126 | void resetResponseBuffer(); 127 | 128 | protected: 129 | static void rtpHandlerCallback(void *arg, char *trackId, char *buf, int len); 130 | static void rtcpHandlerCallback(void *arg, char *trackId, char *buf, int len); 131 | 132 | protected: 133 | enum { AWAITING_DOLLAR, AWAITING_STREAM_CHANNEL_ID, AWAITING_SIZE1, AWAITING_SIZE2, AWAITING_PACKET_DATA, 134 | AWAITING_RTSP_MESSAGE } fTCPReadingState; 135 | unsigned char fStreamChannelId, fSizeByte1; 136 | unsigned fTCPReadSize; 137 | RTPSource* fNextTCPSource; 138 | int fNextTCPSourceType; 139 | 140 | protected: 141 | MySock fRtspSock; 142 | TaskScheduler* fTask; 143 | MediaSession* fMediaSession; 144 | 145 | int m_nTimeoutSecond; 146 | 147 | char* fResponseBuffer; 148 | int fResponseBufferSize; 149 | int fResponseBufferIdx; 150 | 151 | char* fRtpBuffer; 152 | int fRtpBufferSize; 153 | int fRtpBufferIdx; 154 | 155 | char* fUserAgentHeaderStr; 156 | unsigned fUserAgentHeaderStrSize; 157 | char* fBaseURL; 158 | unsigned fCSeq; 159 | 160 | unsigned char fTCPStreamIdCount; 161 | 162 | char* fLastSessionId; 163 | char* fLastSessionIdStr; 164 | unsigned fSessionTimeoutParameter; 165 | 166 | Authenticator fCurrentAuthenticator; 167 | 168 | unsigned fLastResponseCode; 169 | 170 | OnCloseFunc fCloseFunc; 171 | void* fCloseFuncData; 172 | 173 | const char* fVideoCodec; 174 | const char* fAudioCodec; 175 | int fVideoWidth; 176 | int fVideoHeight; 177 | int fVideoFps; 178 | int fChannel; 179 | int fAudioSampleRate; 180 | uint8_t* fVideoExtraData; 181 | unsigned fVideoExtraDataSize; 182 | uint8_t* fAudioExtraData; 183 | unsigned fAudioExtraDataSize; 184 | double fPlayStartTime; 185 | double fPlayEndTime; 186 | 187 | bool fIsSendGetParam; 188 | time_t fLastSendGetParam; // GET_PARAMETER polling time 189 | 190 | // for rtsp server 191 | OnPacketReceiveFunc fRTPReceiveFunc; 192 | void* fRTPReceiveFuncData; 193 | OnPacketReceiveFunc fRTCPReceiveFunc; 194 | void* fRTCPReceiveFuncData; 195 | }; 196 | 197 | #endif 198 | -------------------------------------------------------------------------------- /RTSPServer/RTSP/ServerMediaSession.h: -------------------------------------------------------------------------------- 1 | #ifndef __SERVER_MEDIA_SESSION_H__ 2 | #define __SERVER_MEDIA_SESSION_H__ 3 | 4 | #include "ClientSocket.h" 5 | #include "MyList.h" 6 | 7 | #define STREAM_INFO "DXMediaPlayer" 8 | #define STREAM_DESCRIPTION "Session streamed by \"DXMediaPlayer\"" 9 | 10 | typedef enum { 11 | STREAM_STATE_STOPPED = 0, 12 | STREAM_STATE_OPENED = 1, 13 | STREAM_STATE_PAUSED = 2, 14 | STREAM_STATE_RUNNING = 3 15 | } STREAM_STATE; 16 | 17 | typedef int (*StartStreamCallback)(void *arg, double start_time); 18 | typedef void (*StopStreamCallback)(void *arg); 19 | typedef void (*ControlStreamCallback0)(void *arg); 20 | typedef void (*ControlStreamCallback1)(void *arg, int arg1); 21 | typedef void (*ControlStreamCallback2)(void *arg, float arg1); 22 | 23 | class StreamControl 24 | { 25 | public: 26 | StreamControl(void *arg, StartStreamCallback startFunc, StopStreamCallback stopFunc, 27 | ControlStreamCallback0 pauseFunc = NULL, ControlStreamCallback0 resumeFunc = NULL, 28 | ControlStreamCallback1 playDirFunc = NULL, 29 | ControlStreamCallback1 playNextFunc = NULL, ControlStreamCallback0 playContinueFunc = NULL, 30 | ControlStreamCallback1 seekFunc = NULL, 31 | ControlStreamCallback2 speedFunc = NULL); 32 | virtual ~StreamControl(); 33 | 34 | int startStream(double start_time); 35 | void stopStream(); 36 | void pauseStream(); 37 | void resumeStream(); 38 | void playDirStream(int dir); 39 | void playNextStream(int dir); 40 | void playContinueStream(); 41 | void seekStream(int timestamp); 42 | void speedStream(float speed); 43 | 44 | STREAM_STATE state() { return fStreamState; } 45 | 46 | protected: 47 | void* fThis; 48 | StartStreamCallback fStartStreamFunc; 49 | StopStreamCallback fStopStreamFunc; 50 | ControlStreamCallback0 fPauseStreamFunc; 51 | ControlStreamCallback0 fResumeStreamFunc; 52 | ControlStreamCallback1 fPlayDirStreamFunc; 53 | ControlStreamCallback1 fPlayNextStreamFunc; 54 | ControlStreamCallback0 fPlayContinueStreamFunc; 55 | ControlStreamCallback1 fSeekStreamFunc; 56 | ControlStreamCallback2 fSpeedStreamFunc; 57 | 58 | STREAM_STATE fStreamState; 59 | }; 60 | 61 | typedef enum { 62 | SESSION_LIVE, 63 | SESSION_ONDEMAND 64 | } SESSION_TYPE; 65 | 66 | class ServerMediaSubsession; 67 | 68 | class ServerMediaSession 69 | { 70 | public: 71 | ServerMediaSession( 72 | char const* streamName, 73 | char const* info, 74 | char const* description, 75 | bool isSSM, 76 | char const* miscSDPLines, 77 | StreamControl* streamControl); 78 | 79 | virtual ~ServerMediaSession(); 80 | 81 | char* generateSDPDescription(); 82 | 83 | char const* streamName() const { return fStreamName; } 84 | 85 | bool addSubsession(ServerMediaSubsession* subsession); 86 | unsigned numSubsessions() const { return fSubsessionCounter; } 87 | 88 | float duration() const; 89 | // a result == 0 means an unbounded session (the default) 90 | // a result < 0 means: subsession durations differ; the result is -(the largest). 91 | // a result > 0 means: this is the duration of a bounded session 92 | 93 | unsigned referenceCount() const { return fReferenceCount; } 94 | void incrementReferenceCount() { ++fReferenceCount; } 95 | void decrementReferenceCount() { if (fReferenceCount > 0) --fReferenceCount; } 96 | bool& deleteWhenUnreferenced() { return fDeleteWhenUnreferenced; } 97 | 98 | void deleteAllSubsessions(); 99 | 100 | // stream control 101 | int startStream(double start_time); 102 | void stopStream(); 103 | void pauseStream(); 104 | void resumeStream(); 105 | void forwardStream(); 106 | void backwardStream(); 107 | void forwardNextStream(); 108 | void backwardNextStream(); 109 | void playContinueStream(); 110 | void seekStream(int timestamp); 111 | void speedStream(float speed); 112 | STREAM_STATE streamState(); 113 | void closeStreamControl(); 114 | 115 | void removeClientSocket(ClientSocket *sock); 116 | int sendClientRtp(const char *trackId, char *buf, int len); 117 | int sendClientRtcp(const char *trackId, char *buf, int len); 118 | 119 | SESSION_TYPE sessionType() { return fSessionType; } 120 | 121 | protected: 122 | SESSION_TYPE fSessionType; 123 | 124 | private: 125 | bool fIsSSM; 126 | 127 | friend class ServerMediaSubsessionIterator; 128 | ServerMediaSubsession* fSubsessionsHead; 129 | ServerMediaSubsession* fSubsessionsTail; 130 | unsigned fSubsessionCounter; 131 | 132 | char* fStreamName; 133 | char* fInfoSDPString; 134 | char* fDescriptionSDPString; 135 | char* fMiscSDPLines; 136 | struct timeval fCreationTime; 137 | unsigned fReferenceCount; 138 | bool fDeleteWhenUnreferenced; 139 | 140 | StreamControl* fStreamControl; 141 | MUTEX fMutex; 142 | }; 143 | 144 | class ServerMediaSubsessionIterator 145 | { 146 | public: 147 | ServerMediaSubsessionIterator(ServerMediaSession& session); 148 | virtual ~ServerMediaSubsessionIterator(); 149 | 150 | ServerMediaSubsession* next(); // NULL if none 151 | void reset(); 152 | 153 | private: 154 | ServerMediaSession& fOurSession; 155 | ServerMediaSubsession* fNextPtr; 156 | }; 157 | 158 | class ServerMediaSubsession 159 | { 160 | public: 161 | unsigned trackNumber() const { return fTrackNumber; } 162 | char const* trackId(); 163 | 164 | virtual void getStreamParameters(unsigned clientSessionId, // in 165 | unsigned int clientAddress, // in 166 | unsigned short const& clientRTPPort, // in 167 | unsigned short const& clientRTCPPort, // in 168 | int tcpSocketNum, // in (-1 means use UDP, not TCP) 169 | unsigned char rtpChannelId, // in (used if TCP) 170 | unsigned char rtcpChannelId, // in (used if TCP) 171 | unsigned int& destinationAddress, // in out 172 | unsigned char& destinationTTL, // in out 173 | bool& isMulticast, // out 174 | unsigned short& serverRTPPort, // out 175 | unsigned short& serverRTCPPort // out 176 | ); 177 | 178 | virtual float getCurrentNPT(); 179 | virtual float duration() const; 180 | 181 | void addClientSock(ClientSocket *sock); 182 | bool removeClientSock(ClientSocket *sock); 183 | 184 | char const* codecName() { return fCodecName; } 185 | unsigned char rtpPayloadType() { return fRTPPayloadType; } 186 | unsigned timestampFrequency() { return fTimestampFrequency; } 187 | 188 | protected: 189 | ServerMediaSubsession(char const* trackId, char const* codec, unsigned char rtpPayload, unsigned timestampFreq); 190 | virtual ~ServerMediaSubsession(); 191 | 192 | char const* sdpLines(); 193 | 194 | int sendClientRtp(char *buf, int len); 195 | int sendClientRtcp(char *buf, int len); 196 | 197 | ServerMediaSession* fParentSession; 198 | 199 | MyList fClientSockList; 200 | 201 | private: 202 | friend class ServerMediaSession; 203 | friend class ServerMediaSubsessionIterator; 204 | ServerMediaSubsession* fNext; 205 | 206 | unsigned fTrackNumber; 207 | char const* fTrackId; 208 | 209 | protected: 210 | char* fSDPLines; 211 | const char* fCodecName; 212 | unsigned char fRTPPayloadType; 213 | unsigned fTimestampFrequency; 214 | }; 215 | 216 | #endif 217 | -------------------------------------------------------------------------------- /RTSPClient/RTP/H264RTPSource.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "H264RTPSource.h" 4 | #include "MediaSession.h" 5 | #include "RTSPCommonEnv.h" 6 | 7 | H264RTPSource::H264RTPSource(int connType, MediaSubsession &subsession, TaskScheduler &task) 8 | : RTPSource(connType, subsession, task) 9 | { 10 | parseSpropParameterSets((char *)subsession.fmtp_spropparametersets()); 11 | } 12 | 13 | H264RTPSource::~H264RTPSource() 14 | { 15 | } 16 | 17 | void H264RTPSource::putStartCode() 18 | { 19 | fFrameBuf[fFrameBufPos++] = 0x00; 20 | fFrameBuf[fFrameBufPos++] = 0x00; 21 | fFrameBuf[fFrameBufPos++] = 0x00; 22 | fFrameBuf[fFrameBufPos++] = 0x01; 23 | } 24 | 25 | void H264RTPSource::processFrame(RTPPacketBuffer *packet) 26 | { 27 | uint8_t *buf = (uint8_t *)packet->payload(); 28 | int len = packet->payloadLen(); 29 | 30 | int offset = trimStartCode(buf, len); 31 | buf = &buf[offset]; 32 | len -= offset; 33 | 34 | uint8_t *buf_ptr = buf; 35 | bool isCompleteFrame = false; 36 | 37 | int64_t media_timestamp = packet->extTimestamp() == 0 ? getMediaTimestamp(packet->timestamp()) : packet->extTimestamp(); 38 | 39 | uint8_t nalUnitType = (buf[0]&0x1F); 40 | 41 | if (RTSPCommonEnv::nDebugFlag&DEBUG_FLAG_RTP_PAYLOAD) 42 | DPRINTF("nal_type: %d, size: %d\n", nalUnitType, len); 43 | 44 | if (!fIsStartFrame) { 45 | if (fExtraData) { 46 | putStartCode(); 47 | offset = trimStartCode(fExtraData, fExtraDataSize); 48 | copyToFrameBuffer(&fExtraData[offset], fExtraDataSize - offset); 49 | } 50 | fIsStartFrame = true; 51 | } 52 | 53 | switch (nalUnitType) 54 | { 55 | case 28: { // FU-A 56 | uint8_t startBit = buf[1]&0x80; 57 | uint8_t endBit = buf[1]&0x40; 58 | 59 | if (startBit) { 60 | buf_ptr++; len--; 61 | buf[1] = (buf[0]&0xE0) + (buf[1]&0x1F); 62 | putStartCode(); 63 | } else { 64 | buf_ptr += 2; len -= 2; 65 | } 66 | 67 | copyToFrameBuffer(buf_ptr, len); 68 | isCompleteFrame = (endBit != 0); 69 | break; 70 | } 71 | case 5: { // IDR-Picture 72 | putStartCode(); 73 | copyToFrameBuffer(buf_ptr, len); 74 | isCompleteFrame = true; 75 | break; 76 | } 77 | case 7: { // SPS 78 | putStartCode(); 79 | copyToFrameBuffer(buf_ptr, len); 80 | isCompleteFrame = false; 81 | break; 82 | } 83 | case 8: { // PPS 84 | putStartCode(); 85 | copyToFrameBuffer(buf_ptr, len); 86 | isCompleteFrame = false; 87 | break; 88 | } 89 | case 24: { // STAP-A 90 | buf_ptr++; len--; 91 | while (len > 3) 92 | { 93 | uint16_t staplen = (buf_ptr[0]<<8) | (buf_ptr[1]); 94 | if (staplen > len) { 95 | DPRINTF("STAP-A process error, staplen: %d, len\n", staplen, len); 96 | break; 97 | } 98 | 99 | buf_ptr += 2; len -= 2; 100 | nalUnitType = buf_ptr[0]&0x1F; 101 | 102 | putStartCode(); 103 | copyToFrameBuffer(buf_ptr, staplen); 104 | 105 | buf_ptr += staplen; len -= staplen; 106 | 107 | if (fFrameHandlerFunc) 108 | fFrameHandlerFunc(fFrameHandlerFuncData, fFrameType, media_timestamp, fFrameBuf, fFrameBufPos); 109 | resetFrameBuf(); 110 | } 111 | break; 112 | } 113 | default: 114 | putStartCode(); 115 | copyToFrameBuffer(buf_ptr, len); 116 | isCompleteFrame = true; 117 | break; 118 | } 119 | 120 | if (isCompleteFrame) { 121 | if (fFrameHandlerFunc) 122 | fFrameHandlerFunc(fFrameHandlerFuncData, fFrameType, media_timestamp, fFrameBuf, fFrameBufPos); 123 | resetFrameBuf(); 124 | } 125 | } 126 | 127 | /*char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";*/ 128 | static int b64_decode( char *dest, char *src ) 129 | { 130 | const char *dest_start = dest; 131 | int i_level; 132 | int last = 0; 133 | int b64[256] = { 134 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */ 135 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */ 136 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */ 137 | 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */ 138 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */ 139 | 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */ 140 | -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */ 141 | 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */ 142 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */ 143 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */ 144 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */ 145 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */ 146 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */ 147 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */ 148 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */ 149 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */ 150 | }; 151 | 152 | for( i_level = 0; *src != '\0'; src++ ) 153 | { 154 | int c; 155 | 156 | c = b64[(unsigned int)*src]; 157 | if( c == -1 ) 158 | { 159 | continue; 160 | } 161 | 162 | switch( i_level ) 163 | { 164 | case 0: 165 | i_level++; 166 | break; 167 | case 1: 168 | *dest++ = ( last << 2 ) | ( ( c >> 4)&0x03 ); 169 | i_level++; 170 | break; 171 | case 2: 172 | *dest++ = ( ( last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f ); 173 | i_level++; 174 | break; 175 | case 3: 176 | *dest++ = ( ( last &0x03 ) << 6 ) | c; 177 | i_level = 0; 178 | } 179 | last = c; 180 | } 181 | 182 | *dest = '\0'; 183 | 184 | return dest - dest_start; 185 | } 186 | 187 | unsigned char* parseH264ConfigStr(char const* configStr, unsigned int& configSize, unsigned int& spsSize) 188 | { 189 | char *dup, *psz; 190 | int i, i_records = 1; 191 | 192 | if( configSize ) 193 | configSize = 0; 194 | 195 | if( spsSize ) 196 | spsSize = 0; 197 | 198 | if( configStr == NULL || *configStr == '\0' ) 199 | return NULL; 200 | 201 | dup = new char[strlen(configStr)+1]; 202 | memset(dup, 0, strlen(configStr)+1); 203 | memcpy(dup, configStr, strlen(configStr)+1); 204 | psz = dup; 205 | 206 | /* Count the number of comma's */ 207 | for( psz = dup; *psz != '\0'; ++psz ) 208 | { 209 | if( *psz == ',') 210 | { 211 | ++i_records; 212 | *psz = '\0'; 213 | } 214 | } 215 | 216 | int sz = 5 * strlen(dup); 217 | if (sz == 0) { 218 | delete[] dup; 219 | return NULL; 220 | } 221 | 222 | unsigned char *cfg = new unsigned char[sz]; 223 | memset(cfg, 0, sz); 224 | psz = dup; 225 | for( i = 0; i < i_records; i++ ) 226 | { 227 | cfg[configSize++] = 0x00; 228 | cfg[configSize++] = 0x00; 229 | cfg[configSize++] = 0x00; 230 | cfg[configSize++] = 0x01; 231 | 232 | configSize += b64_decode( (char*)&cfg[configSize], psz ); 233 | 234 | psz += strlen(psz)+1; 235 | if (i == 0) // SPS 236 | spsSize = configSize; 237 | } 238 | 239 | delete[] dup; 240 | return cfg; 241 | } 242 | 243 | int H264RTPSource::parseSpropParameterSets(char *spropParameterSets) 244 | { 245 | if (spropParameterSets == NULL) 246 | return -1; 247 | 248 | unsigned int config_size = 0, sps_size = 0; 249 | 250 | fExtraData = parseH264ConfigStr(spropParameterSets, fExtraDataSize, sps_size); 251 | 252 | return 0; 253 | } 254 | -------------------------------------------------------------------------------- /RTSPServer/RTSP/RTSPServer.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTSP_SERVER_H__ 2 | #define __RTSP_SERVER_H__ 3 | 4 | #include "MySock.h" 5 | #include "TaskScheduler.h" 6 | #include "MyList.h" 7 | #include "RTSPCommon.h" 8 | 9 | #define RTSP_BUFFER_SIZE (20000) 10 | 11 | typedef enum { OPEN_SERVER_SESSION, CLIENT_CONNECTED, CLIENT_DISCONNECTED } ServerCallbackType; 12 | 13 | class CallbackParam { 14 | public: 15 | CallbackParam(ServerCallbackType type); 16 | virtual ~CallbackParam() {} 17 | 18 | public: 19 | ServerCallbackType fType; 20 | }; 21 | 22 | class OpenServerSessionParam : public CallbackParam { 23 | public: 24 | OpenServerSessionParam(char *requestString); 25 | virtual ~OpenServerSessionParam() {} 26 | 27 | public: 28 | char fRequestString[256]; 29 | }; 30 | 31 | class ClientConnectedParam : public CallbackParam { 32 | public: 33 | ClientConnectedParam(const char *sessionName, int sock, struct sockaddr_in &sockAddr, int streamType); 34 | virtual ~ClientConnectedParam() {} 35 | 36 | public: 37 | char fSessionName[256]; 38 | int fSock; 39 | struct sockaddr_in fClientAddr; 40 | int fStreamType; 41 | }; 42 | 43 | class ClientDisconnectedParam : public CallbackParam { 44 | public: 45 | ClientDisconnectedParam(int sock); 46 | virtual ~ClientDisconnectedParam() {} 47 | 48 | public: 49 | int fSock; 50 | }; 51 | 52 | typedef int (*RTSPServerCallback)(void *arg, CallbackParam *param); 53 | 54 | class ServerMediaSession; 55 | class ServerMediaSubsession; 56 | class ClientSocket; 57 | 58 | class RTSPServer 59 | { 60 | public: 61 | static RTSPServer* instance(); 62 | static void destroy(); 63 | 64 | int startServer(unsigned short port = 554, RTSPServerCallback func = NULL, void *arg = NULL); 65 | void stopServer(); 66 | bool isServerRunning() { return fIsServerRunning; } 67 | int serverSessionCount() { return fServerMediaSessions.count(); } 68 | 69 | void addServerMediaSession(ServerMediaSession* serverMediaSession); 70 | ServerMediaSession* lookupServerMediaSession(char const* streamName); 71 | void removeServerMediaSession(ServerMediaSession* serverMediaSession); 72 | 73 | void closeAllClientSessionsForServerMediaSession(ServerMediaSession* serverMediaSession); 74 | void deleteServerMediaSession(ServerMediaSession* serverMediaSession); 75 | 76 | char* rtspURL(ServerMediaSession const* serverMediaSession, int clientSocket = -1); 77 | // returns a "rtsp://" URL that could be used to access the 78 | // specified session (which must already have been added to 79 | // us using "addServerMediaSession()". 80 | // This string is dynamically allocated; caller should delete[] 81 | // (If "clientSocket" is non-negative, then it is used (by calling "getsockname()") to determine 82 | // the IP address to be used in the URL.) 83 | char* rtspURLPrefix(int clientSocket = -1); 84 | // like "rtspURL()", except that it returns just the common prefix used by 85 | // each session's "rtsp://" URL. 86 | // This string is dynamically allocated; caller should delete[] 87 | 88 | protected: 89 | RTSPServer(); 90 | virtual ~RTSPServer(); 91 | 92 | static RTSPServer* fInstance; 93 | 94 | virtual char const* allowedCommandNames(); // used to implement "RTSPClientConnection::handleCmd_OPTIONS()" 95 | 96 | protected: 97 | static void incomingConnectionHandlerRTSP(void*, int); 98 | void incomingConnectionHandlerRTSP1(); 99 | void incomingConnectionHandler(int serverSocket); 100 | 101 | protected: 102 | class RTSPClientSession 103 | { 104 | public: 105 | RTSPClientSession(RTSPServer& ourServer, MySock& clientSock, unsigned int sessionId); 106 | virtual ~RTSPClientSession(); 107 | 108 | friend class RTSPServer; 109 | 110 | protected: 111 | static void incomingRequestHandler(void*, int); 112 | void incomingRequestHandler1(unsigned char requestByte); 113 | void handleRequestBytes(int newBytesRead); 114 | 115 | void resetRequestBuffer(); 116 | 117 | void handleCmd_OPTIONS(); 118 | void handleCmd_DESCRIBE(char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr); 119 | void handleCmd_SETUP(char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr); 120 | void handleCmd_PLAY(ServerMediaSubsession* subsession, char const* fullRequestStr); 121 | void handleCmd_TEARDOWN(ServerMediaSubsession* subsession); 122 | void handleCmd_PAUSE(ServerMediaSubsession* subsession); 123 | void handleCmd_GET_PARAMETER(ServerMediaSubsession* subsession, char const* fullRequestStr); 124 | void handleCmd_SET_PARAMETER(ServerMediaSubsession* subsession, char const* fullRequestStr); 125 | void handleCmd_withinSession(char const* cmdName, char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr); 126 | void handleCmd_bad(); 127 | void handleCmd_notSupported(); 128 | void handleCmd_notFound(); 129 | void handleCmd_sessionNotFound(); 130 | void handleCmd_unsupportedTransport(); 131 | 132 | void reclaimStreamStates(); 133 | void shutdown(); 134 | 135 | // Shortcuts for setting up a RTSP response (prior to sending it): 136 | void setRTSPResponse(char const* responseStr); 137 | void setRTSPResponse(char const* responseStr, unsigned int sessionId); 138 | void setRTSPResponse(char const* responseStr, char const* contentStr); 139 | void setRTSPResponse(char const* responseStr, u_int32_t sessionId, char const* contentStr); 140 | 141 | // tcp stream read fuctions 142 | void tcpReadHandler1(); 143 | bool lookupStreamChannelId(unsigned char channel); 144 | void readRTPOverTCP(); 145 | 146 | protected: 147 | enum { AWAITING_DOLLAR, AWAITING_STREAM_CHANNEL_ID, AWAITING_SIZE1, AWAITING_SIZE2, AWAITING_PACKET_DATA, 148 | } fTCPReadingState; 149 | unsigned char fStreamChannelId, fSizeByte1; 150 | unsigned fTCPReadSize; 151 | 152 | char* fRtpBuffer; 153 | int fRtpBufferSize; 154 | int fRtpBufferIdx; 155 | 156 | protected: 157 | RTSPServer& fOurServer; 158 | u_int32_t fOurSessionId; 159 | ServerMediaSession* fOurServerMediaSession; 160 | bool fIsActive; 161 | MySock* fClientSock; 162 | unsigned char fRequestBuffer[RTSP_BUFFER_SIZE]; 163 | unsigned fRequestBytesAlreadySeen, fRequestBufferBytesLeft; 164 | unsigned char* fLastCRLF; 165 | unsigned char fResponseBuffer[RTSP_BUFFER_SIZE]; 166 | char const* fCurrentCSeq; 167 | unsigned fBase64RemainderCount; // used for optional RTSP-over-HTTP tunneling (possible values: 0,1,2,3) 168 | 169 | bool fIsMulticast; 170 | unsigned char fTCPStreamIdCount; // used for (optional) RTP/TCP 171 | 172 | unsigned fNumStreamStates; 173 | struct streamState { 174 | ServerMediaSubsession* subsession; 175 | } * fStreamStates; 176 | 177 | MyList fClientSockList; 178 | }; 179 | 180 | RTSPClientSession* createNewClientSession(MySock& clientSock); 181 | void addClientSession(RTSPClientSession *clientSession); 182 | void removeClientSession(RTSPClientSession *clientSession); 183 | 184 | protected: 185 | friend class RTSPClientSession; 186 | 187 | protected: 188 | bool fIsServerRunning; 189 | unsigned short fServerPort; 190 | 191 | RTSPServerCallback fServerCallbackFunc; 192 | void* fServerCallbackArg; 193 | 194 | MySock fServerSock; 195 | TaskScheduler* fTask; 196 | 197 | MyList fServerMediaSessions; 198 | MyList fClientSessions; 199 | }; 200 | 201 | #endif 202 | -------------------------------------------------------------------------------- /Sock/TaskScheduler.cpp: -------------------------------------------------------------------------------- 1 | #include "TaskScheduler.h" 2 | #include "RTSPCommonEnv.h" 3 | #include 4 | 5 | THREAD_FUNC DoEventThread(void* lpParam) 6 | { 7 | TaskScheduler *scheduler = (TaskScheduler *)lpParam; 8 | scheduler->doEventLoop(); 9 | return 0; 10 | } 11 | 12 | TaskScheduler::TaskScheduler() 13 | { 14 | fTaskLoop = 0; 15 | MUTEX_INIT(&fMutex); 16 | FD_ZERO(&fReadSet); 17 | fMaxNumSockets = 0; 18 | fThread = NULL; 19 | fReadHandlers = new HandlerSet(); 20 | } 21 | 22 | TaskScheduler::~TaskScheduler() 23 | { 24 | stopEventLoop(); 25 | 26 | delete fReadHandlers; 27 | 28 | THREAD_DESTROY(&fThread); 29 | 30 | MUTEX_DESTROY(&fMutex); 31 | } 32 | 33 | void TaskScheduler::taskLock() 34 | { 35 | MUTEX_LOCK(&fMutex); 36 | } 37 | 38 | void TaskScheduler::taskUnlock() 39 | { 40 | MUTEX_UNLOCK(&fMutex); 41 | } 42 | 43 | void TaskScheduler::turnOnBackgroundReadHandling(int socketNum, BackgroundHandlerProc* handlerProc, void *clientData) 44 | { 45 | taskLock(); 46 | 47 | if (socketNum < 0) goto exit; 48 | 49 | FD_SET((unsigned)socketNum, &fReadSet); 50 | fReadHandlers->assignHandler(socketNum, handlerProc, clientData); 51 | 52 | if (socketNum+1 > fMaxNumSockets) { 53 | fMaxNumSockets = socketNum+1; 54 | } 55 | 56 | exit: 57 | taskUnlock(); 58 | } 59 | 60 | void TaskScheduler::turnOffBackgroundReadHandling(int socketNum) 61 | { 62 | taskLock(); 63 | 64 | if (socketNum < 0) goto exit; 65 | 66 | FD_CLR((unsigned)socketNum, &fReadSet); 67 | fReadHandlers->removeHandler(socketNum); 68 | 69 | if (socketNum+1 == fMaxNumSockets) { 70 | --fMaxNumSockets; 71 | } 72 | 73 | exit: 74 | taskUnlock(); 75 | } 76 | 77 | int TaskScheduler::startEventLoop() 78 | { 79 | if (fTaskLoop != 0) 80 | return -1; 81 | 82 | fTaskLoop = 1; 83 | THREAD_CREATE(&fThread, DoEventThread, this); 84 | if (!fThread) { 85 | DPRINTF("failed to create event loop thread\n"); 86 | fTaskLoop = 0; 87 | return -1; 88 | } 89 | 90 | return 0; 91 | } 92 | 93 | void TaskScheduler::stopEventLoop() 94 | { 95 | fTaskLoop = 0; 96 | 97 | THREAD_JOIN(&fThread); 98 | THREAD_DESTROY(&fThread); 99 | } 100 | 101 | void TaskScheduler::doEventLoop() 102 | { 103 | while (fTaskLoop) 104 | { 105 | SingleStep(); 106 | } 107 | } 108 | 109 | void TaskScheduler::SingleStep() 110 | { 111 | taskLock(); 112 | 113 | fd_set readSet = fReadSet; 114 | 115 | struct timeval timeout; 116 | timeout.tv_sec = 1; 117 | timeout.tv_usec = 0; 118 | 119 | int selectResult = select(fMaxNumSockets, &readSet, NULL, NULL, &timeout); 120 | if (selectResult < 0) { 121 | int err = WSAGetLastError(); 122 | #ifdef WIN32 123 | // For some unknown reason, select() in Windoze sometimes fails with WSAEINVAL if 124 | // it was called with no entries set in "readSet". If this happens, ignore it: 125 | if (err == WSAEINVAL && readSet.fd_count == 0) { 126 | err = 0; 127 | // To stop this from happening again, create a dummy readable socket: 128 | int dummySocketNum = socket(AF_INET, SOCK_DGRAM, 0); 129 | FD_SET((unsigned)dummySocketNum, &fReadSet); 130 | } 131 | #endif 132 | if (err != 0) { 133 | // Unexpected error - treat this as fatal: 134 | //DPRINTF("TaskScheduler::SingleStep(): select() fails"); 135 | // exit(0); 136 | } 137 | } 138 | 139 | // Call the handler function for one readable socket: 140 | HandlerIterator iter(*fReadHandlers); 141 | HandlerDescriptor* handler; 142 | // To ensure forward progress through the handlers, begin past the last 143 | // socket number that we handled: 144 | if (fLastHandledSocketNum >= 0) { 145 | while ((handler = iter.next()) != NULL) { 146 | if (handler->socketNum == fLastHandledSocketNum) break; 147 | } 148 | if (handler == NULL) { 149 | fLastHandledSocketNum = -1; 150 | iter.reset(); // start from the beginning instead 151 | } 152 | } 153 | 154 | while ((handler = iter.next()) != NULL) { 155 | if (FD_ISSET(handler->socketNum, &readSet) && 156 | FD_ISSET(handler->socketNum, &fReadSet) /* sanity check */ && 157 | handler->handlerProc != NULL) { 158 | fLastHandledSocketNum = handler->socketNum; 159 | // Note: we set "fLastHandledSocketNum" before calling the handler, 160 | // in case the handler calls "doEventLoop()" reentrantly. 161 | (*handler->handlerProc)(handler->clientData, SOCKET_READABLE); 162 | break; 163 | } 164 | } 165 | 166 | if (handler == NULL && fLastHandledSocketNum >= 0) { 167 | // We didn't call a handler, but we didn't get to check all of them, 168 | // so try again from the beginning: 169 | iter.reset(); 170 | while ((handler = iter.next()) != NULL) { 171 | if (FD_ISSET(handler->socketNum, &readSet) && 172 | FD_ISSET(handler->socketNum, &fReadSet) /* sanity check */ && 173 | handler->handlerProc != NULL) { 174 | fLastHandledSocketNum = handler->socketNum; 175 | // Note: we set "fLastHandledSocketNum" before calling the handler, 176 | // in case the handler calls "doEventLoop()" reentrantly. 177 | (*handler->handlerProc)(handler->clientData, SOCKET_READABLE); 178 | break; 179 | } 180 | } 181 | if (handler == NULL) fLastHandledSocketNum = -1;//because we didn't call a handler 182 | } 183 | 184 | taskUnlock(); 185 | #ifndef WIN32 186 | if (fLastHandledSocketNum == -1) usleep(1); 187 | #endif 188 | } 189 | 190 | 191 | HandlerDescriptor::HandlerDescriptor(HandlerDescriptor* nextHandler) 192 | : handlerProc(NULL) { 193 | // Link this descriptor into a doubly-linked list: 194 | if (nextHandler == this) { // initialization 195 | fNextHandler = fPrevHandler = this; 196 | } else { 197 | fNextHandler = nextHandler; 198 | fPrevHandler = nextHandler->fPrevHandler; 199 | nextHandler->fPrevHandler = this; 200 | fPrevHandler->fNextHandler = this; 201 | } 202 | } 203 | 204 | HandlerDescriptor::~HandlerDescriptor() { 205 | // Unlink this descriptor from a doubly-linked list: 206 | fNextHandler->fPrevHandler = fPrevHandler; 207 | fPrevHandler->fNextHandler = fNextHandler; 208 | } 209 | 210 | HandlerSet::HandlerSet() 211 | : fHandlers(&fHandlers) { 212 | fHandlers.socketNum = -1; // shouldn't ever get looked at, but in case... 213 | } 214 | 215 | HandlerSet::~HandlerSet() { 216 | // Delete each handler descriptor: 217 | while (fHandlers.fNextHandler != &fHandlers) { 218 | delete fHandlers.fNextHandler; // changes fHandlers->fNextHandler 219 | } 220 | } 221 | 222 | void HandlerSet 223 | ::assignHandler(int socketNum, TaskScheduler::BackgroundHandlerProc* handlerProc, void* clientData) { 224 | // First, see if there's already a handler for this socket: 225 | HandlerDescriptor* handler = lookupHandler(socketNum); 226 | if (handler == NULL) { // No existing handler, so create a new descr: 227 | handler = new HandlerDescriptor(fHandlers.fNextHandler); 228 | handler->socketNum = socketNum; 229 | } 230 | 231 | handler->handlerProc = handlerProc; 232 | handler->clientData = clientData; 233 | } 234 | 235 | void HandlerSet::removeHandler(int socketNum) { 236 | HandlerDescriptor* handler = lookupHandler(socketNum); 237 | delete handler; 238 | } 239 | 240 | void HandlerSet::moveHandler(int oldSocketNum, int newSocketNum) { 241 | HandlerDescriptor* handler = lookupHandler(oldSocketNum); 242 | if (handler != NULL) { 243 | handler->socketNum = newSocketNum; 244 | } 245 | } 246 | 247 | HandlerDescriptor* HandlerSet::lookupHandler(int socketNum) { 248 | HandlerDescriptor* handler; 249 | HandlerIterator iter(*this); 250 | while ((handler = iter.next()) != NULL) { 251 | if (handler->socketNum == socketNum) break; 252 | } 253 | return handler; 254 | } 255 | 256 | HandlerIterator::HandlerIterator(HandlerSet& handlerSet) 257 | : fOurSet(handlerSet) { 258 | reset(); 259 | } 260 | 261 | HandlerIterator::~HandlerIterator() { 262 | } 263 | 264 | void HandlerIterator::reset() { 265 | fNextPtr = fOurSet.fHandlers.fNextHandler; 266 | } 267 | 268 | HandlerDescriptor* HandlerIterator::next() { 269 | HandlerDescriptor* result = fNextPtr; 270 | if (result == &fOurSet.fHandlers) { // no more 271 | result = NULL; 272 | } else { 273 | fNextPtr = fNextPtr->fNextHandler; 274 | } 275 | 276 | return result; 277 | } 278 | -------------------------------------------------------------------------------- /win32/RTSPClientLib/RTSPClientLib.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {c568cc6c-d336-47ee-98b2-a6dc0e68c51c} 6 | 7 | 8 | {5a936772-0357-4d7a-bcf9-7c834afaa0c7} 9 | 10 | 11 | {62eb792f-ba46-459a-97de-ccd222625420} 12 | 13 | 14 | {ab8c8e4c-3286-4c3c-875c-8a05e5dabc90} 15 | 16 | 17 | {06d98b76-5bc3-424a-8d5f-9817ea7d5f0b} 18 | 19 | 20 | {5fb4e040-3635-4926-bcec-84c98dbef650} 21 | 22 | 23 | {b82dd8bc-7831-4ceb-aaa8-cae323c398a6} 24 | 25 | 26 | 27 | 28 | Common 29 | 30 | 31 | Common 32 | 33 | 34 | Common 35 | 36 | 37 | RTCP 38 | 39 | 40 | RTCP 41 | 42 | 43 | RTCP 44 | 45 | 46 | RTCP 47 | 48 | 49 | RTCP 50 | 51 | 52 | RTCP 53 | 54 | 55 | RTP 56 | 57 | 58 | RTP 59 | 60 | 61 | RTP 62 | 63 | 64 | RTP 65 | 66 | 67 | RTP 68 | 69 | 70 | RTP 71 | 72 | 73 | RTSP 74 | 75 | 76 | RTSP 77 | 78 | 79 | Sock 80 | 81 | 82 | Sock 83 | 84 | 85 | Sock 86 | 87 | 88 | Util 89 | 90 | 91 | Util 92 | 93 | 94 | Util 95 | 96 | 97 | Util 98 | 99 | 100 | OS_Common 101 | 102 | 103 | OS_Common 104 | 105 | 106 | OS_Common 107 | 108 | 109 | OS_Common 110 | 111 | 112 | RTP 113 | 114 | 115 | Common 116 | 117 | 118 | RTP 119 | 120 | 121 | 122 | 123 | Common 124 | 125 | 126 | RTCP 127 | 128 | 129 | RTCP 130 | 131 | 132 | Util 133 | 134 | 135 | 136 | 137 | Common 138 | 139 | 140 | Common 141 | 142 | 143 | RTCP 144 | 145 | 146 | RTCP 147 | 148 | 149 | RTCP 150 | 151 | 152 | RTCP 153 | 154 | 155 | RTP 156 | 157 | 158 | RTP 159 | 160 | 161 | RTP 162 | 163 | 164 | RTP 165 | 166 | 167 | RTP 168 | 169 | 170 | RTP 171 | 172 | 173 | RTSP 174 | 175 | 176 | RTSP 177 | 178 | 179 | Sock 180 | 181 | 182 | Sock 183 | 184 | 185 | Sock 186 | 187 | 188 | Util 189 | 190 | 191 | Util 192 | 193 | 194 | OS_Common 195 | 196 | 197 | OS_Common 198 | 199 | 200 | OS_Common 201 | 202 | 203 | OS_Common 204 | 205 | 206 | OS_Common 207 | 208 | 209 | RTP 210 | 211 | 212 | Common 213 | 214 | 215 | RTP 216 | 217 | 218 | -------------------------------------------------------------------------------- /RTSPClient/RTP/RTPPacketBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "RTPPacketBuffer.h" 2 | #include "RTSPCommonEnv.h" 3 | #include "util.h" 4 | 5 | RTPPacketBuffer::RTPPacketBuffer() : fBuf(NULL), fLength(0), fVersion(0), fPadding(0), fExtension(0), fCSRCCount(0), 6 | fMarkerBit(0), fPayloadType(0), fSequenceNum(0), fTimestamp(0), fSSRC(0), fNextPacket(NULL), fIsFirstPacket(false), fExtTimestamp(0) 7 | { 8 | fBuf = new uint8_t[MAX_RTP_PACKET_SIZE]; 9 | fCurPtr = fBuf; 10 | } 11 | 12 | RTPPacketBuffer::~RTPPacketBuffer() 13 | { 14 | DELETE_OBJECT(fNextPacket); 15 | DELETE_ARRAY(fBuf); 16 | } 17 | 18 | uint8_t* RTPPacketBuffer::payload() 19 | { 20 | return fCurPtr; 21 | } 22 | 23 | int RTPPacketBuffer::payloadLen() 24 | { 25 | uint8_t *ptrLast = &fBuf[fLength-1]; 26 | return ptrLast-fCurPtr+1; 27 | } 28 | 29 | bool RTPPacketBuffer::packetHandler(uint8_t *buf, int len) 30 | { 31 | if (len < sizeof(RTP_HEADER) || len > MAX_RTP_PACKET_SIZE) { 32 | DPRINTF("invalid rtp length %u\n", len); 33 | return false; 34 | } 35 | 36 | memcpy(fBuf, buf, len); 37 | fCurPtr = fBuf; 38 | fLength = len; 39 | 40 | RTP_HEADER *p = (RTP_HEADER *)fBuf; 41 | fCSRCCount = p->cc; 42 | fExtension = p->ext; 43 | fPadding = p->pad; 44 | fVersion = p->ver; 45 | fPayloadType = p->pt; 46 | fMarkerBit = p->mk; 47 | fSequenceNum = ntohs(p->seq); 48 | fTimestamp = ntohl(p->ts); 49 | fSSRC = ntohl(p->ssrc); 50 | 51 | fCurPtr += sizeof(RTP_HEADER); 52 | 53 | // check RTP version (it must be 2) 54 | if (fVersion != 2) 55 | DPRINTF("invalid rtp version %u\n", fVersion); 56 | 57 | // skip CSRC 58 | if (fCSRCCount > 0) { 59 | if (payloadLen() <= fCSRCCount*4) { 60 | DPRINTF("invalid rtp header, CSRC count error %u\n", fCSRCCount); 61 | return false; 62 | } else { 63 | fCurPtr += (fCSRCCount*4); 64 | } 65 | } 66 | 67 | // skip Extension field 68 | if (fExtension) { 69 | if (payloadLen() <= 4) { 70 | DPRINTF("invalid rtp header, extension length error\n"); 71 | return false; 72 | } else { 73 | EXT_HEADER *dxmHdr = (EXT_HEADER *)fCurPtr; 74 | unsigned extHdr = ntohl(*(unsigned *)fCurPtr); fCurPtr += 4; 75 | unsigned remExtSize = 4*(extHdr&0xFFFF); 76 | if (payloadLen() <= remExtSize) { 77 | DPRINTF("invalid rtp header, extension size error %u\n", remExtSize); 78 | return false; 79 | } else { 80 | // process dxm extension header; 81 | if (dxmHdr->profile == 0x8110) { 82 | dxmHdr->length = ntohs(dxmHdr->length); 83 | dxmHdr->timestamp = checkEndian() == 0 ? ntohll(dxmHdr->timestamp) : dxmHdr->timestamp; 84 | //DPRINTF("%d ext : %d, %lld\n", fPayloadType, dxmHdr->length, dxmHdr->timestamp); 85 | fExtTimestamp = dxmHdr->timestamp; 86 | } 87 | fCurPtr += remExtSize; 88 | } 89 | } 90 | } 91 | 92 | // remove padding 93 | if (fPadding) { 94 | if (payloadLen() <= 0) { 95 | DPRINTF("invalid rtp header, padding error\n"); 96 | return false; 97 | } else { 98 | unsigned numPaddingBytes = (unsigned)fBuf[fLength-1]; 99 | if (payloadLen() <= numPaddingBytes) { 100 | DPRINTF("invalid rtp header, padding length error\n"); 101 | return false; 102 | } else { 103 | fLength -= numPaddingBytes; 104 | fPadding = p->pad = 0; 105 | } 106 | } 107 | } 108 | 109 | gettimeofday(&fTimeReceived, NULL); 110 | 111 | return true; 112 | } 113 | 114 | void RTPPacketBuffer::reset() 115 | { 116 | fCurPtr = fBuf; 117 | fLength = 0; 118 | fIsFirstPacket = false; 119 | } 120 | 121 | ReorderingPacketBuffer::ReorderingPacketBuffer() : fThresholdTime(100000), fHaveSeenFirstPacket(false), fHeadPacket(NULL), fTailPacket(NULL), 122 | fSavedPacket(NULL), fSavedPacketFree(true) 123 | { 124 | } 125 | 126 | ReorderingPacketBuffer::~ReorderingPacketBuffer() 127 | { 128 | reset(); 129 | } 130 | 131 | void ReorderingPacketBuffer::reset() 132 | { 133 | if (fSavedPacketFree) { 134 | DELETE_OBJECT(fSavedPacket); 135 | fSavedPacketFree = false; 136 | } 137 | delete fHeadPacket; 138 | fHaveSeenFirstPacket = false; 139 | fHeadPacket = fTailPacket = NULL; 140 | } 141 | 142 | RTPPacketBuffer* ReorderingPacketBuffer::getFreePacket() 143 | { 144 | if (fSavedPacket == NULL) { 145 | fSavedPacket = new RTPPacketBuffer(); 146 | fSavedPacketFree = true; 147 | } 148 | 149 | if (fSavedPacketFree == true) { 150 | fSavedPacketFree = false; 151 | return fSavedPacket; 152 | } else { 153 | return new RTPPacketBuffer; 154 | } 155 | } 156 | 157 | void ReorderingPacketBuffer::freePacket(RTPPacketBuffer *packet) 158 | { 159 | if (packet != fSavedPacket) { 160 | delete packet; 161 | } else { 162 | fSavedPacketFree = true; 163 | } 164 | } 165 | 166 | bool ReorderingPacketBuffer::storePacket(RTPPacketBuffer* packet) 167 | { 168 | unsigned short rtpSeqNo = packet->sequenceNum(); 169 | 170 | if (!fHaveSeenFirstPacket) { 171 | fNextExpectedSeqNo = rtpSeqNo; // initialization 172 | packet->isFirstPacket() = true; 173 | fHaveSeenFirstPacket = true; 174 | } 175 | 176 | // Ignore this packet if its sequence number is less than the one 177 | // that we're looking for (in this case, it's been excessively delayed). 178 | if (seqNumLT(rtpSeqNo, fNextExpectedSeqNo)) return false; 179 | 180 | if (fTailPacket == NULL) { 181 | // Common case: There are no packets in the queue; this will be the first one: 182 | packet->nextPacket() = NULL; 183 | fHeadPacket = fTailPacket = packet; 184 | return true; 185 | } 186 | 187 | if (seqNumLT(fTailPacket->sequenceNum(), rtpSeqNo)) { 188 | // The next-most common case: There are packets already in the queue; this packet arrived in order => put it at the tail: 189 | packet->nextPacket() = NULL; 190 | fTailPacket->nextPacket() = packet; 191 | fTailPacket = packet; 192 | return true; 193 | } 194 | 195 | if (rtpSeqNo == fTailPacket->sequenceNum()) { 196 | // This is a duplicate packet - ignore it 197 | return false; 198 | } 199 | 200 | // Rare case: This packet is out-of-order. Run through the list (from the head), to figure out where it belongs: 201 | RTPPacketBuffer* beforePtr = NULL; 202 | RTPPacketBuffer* afterPtr = fHeadPacket; 203 | while (afterPtr != NULL) { 204 | if (seqNumLT(rtpSeqNo, afterPtr->sequenceNum())) break; // it comes here 205 | if (rtpSeqNo == afterPtr->sequenceNum()) { 206 | // This is a duplicate packet - ignore it 207 | return false; 208 | } 209 | 210 | beforePtr = afterPtr; 211 | afterPtr = afterPtr->nextPacket(); 212 | } 213 | 214 | // Link our new packet between "beforePtr" and "afterPtr": 215 | packet->nextPacket() = afterPtr; 216 | if (beforePtr == NULL) { 217 | fHeadPacket = packet; 218 | } else { 219 | beforePtr->nextPacket() = packet; 220 | } 221 | 222 | return true; 223 | } 224 | 225 | void ReorderingPacketBuffer::releaseUsedPacket(RTPPacketBuffer* packet) 226 | { 227 | // ASSERT: packet == fHeadPacket 228 | // ASSERT: fNextExpectedSeqNo == packet->rtpSeqNo() 229 | ++fNextExpectedSeqNo; // because we're finished with this packet now 230 | 231 | fHeadPacket = fHeadPacket->nextPacket(); 232 | if (!fHeadPacket) { 233 | fTailPacket = NULL; 234 | } 235 | packet->nextPacket() = NULL; 236 | 237 | freePacket(packet); 238 | } 239 | 240 | RTPPacketBuffer* ReorderingPacketBuffer::getNextCompletedPacket(bool& packetLossPreceded) 241 | { 242 | if (fHeadPacket == NULL) 243 | return NULL; 244 | 245 | // Check whether the next packet we want is already at the head 246 | // of the queue: 247 | // ASSERT: fHeadPacket->rtpSeqNo() >= fNextExpectedSeqNo 248 | if (fHeadPacket->sequenceNum() == fNextExpectedSeqNo) { 249 | packetLossPreceded = fHeadPacket->isFirstPacket(); 250 | // (The very first packet is treated as if there was packet loss beforehand.) 251 | return fHeadPacket; 252 | } 253 | 254 | // We're still waiting for our desired packet to arrive. However, if 255 | // our time threshold has been exceeded, then forget it, and return 256 | // the head packet instead: 257 | bool timeThresholdHasBeenExceeded; 258 | if (fThresholdTime == 0) { 259 | timeThresholdHasBeenExceeded = true; // optimization 260 | } else { 261 | struct timeval timeNow; 262 | gettimeofday(&timeNow, NULL); 263 | unsigned uSecondsSinceReceived 264 | = (timeNow.tv_sec - fHeadPacket->timeReceived().tv_sec)*1000000 265 | + (timeNow.tv_usec - fHeadPacket->timeReceived().tv_usec); 266 | timeThresholdHasBeenExceeded = uSecondsSinceReceived > fThresholdTime; 267 | } 268 | if (timeThresholdHasBeenExceeded) { 269 | fNextExpectedSeqNo = fHeadPacket->sequenceNum(); 270 | // we've given up on earlier packets now 271 | packetLossPreceded = true; 272 | return fHeadPacket; 273 | } 274 | 275 | // Otherwise, keep waiting for our desired packet to arrive: 276 | return NULL; 277 | } 278 | -------------------------------------------------------------------------------- /RTSPClient/RTCP/BasicHashTable.cpp: -------------------------------------------------------------------------------- 1 | /********** 2 | This library is free software; you can redistribute it and/or modify it under 3 | the terms of the GNU Lesser General Public License as published by the 4 | Free Software Foundation; either version 2.1 of the License, or (at your 5 | option) any later version. (See .) 6 | 7 | This library is distributed in the hope that it will be useful, but WITHOUT 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 10 | more details. 11 | 12 | You should have received a copy of the GNU Lesser General Public License 13 | along with this library; if not, write to the Free Software Foundation, Inc., 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 15 | **********/ 16 | // Copyright (c) 1996-2008 Live Networks, Inc. All rights reserved. 17 | // Basic Hash Table implementation 18 | // Implementation 19 | 20 | #include "BasicHashTable.hh" 21 | #include "util.h" 22 | 23 | 24 | #if defined(__WIN32__) || defined(_WIN32) 25 | #else 26 | #include 27 | #endif 28 | #include 29 | #include 30 | 31 | // When there are this many entries per bucket, on average, rebuild 32 | // the table to increase the number of buckets 33 | #define REBUILD_MULTIPLIER 3 34 | 35 | BasicHashTable::BasicHashTable(int keyType) 36 | : fBuckets(fStaticBuckets), fNumBuckets(SMALL_HASH_TABLE_SIZE), 37 | fNumEntries(0), fRebuildSize(SMALL_HASH_TABLE_SIZE*REBUILD_MULTIPLIER), 38 | fDownShift(28), fMask(0x3), fKeyType(keyType) { 39 | for (unsigned i = 0; i < SMALL_HASH_TABLE_SIZE; ++i) { 40 | fStaticBuckets[i] = NULL; 41 | } 42 | } 43 | 44 | BasicHashTable::~BasicHashTable() { 45 | // Free all the entries in the table: 46 | for (unsigned i = 0; i < fNumBuckets; ++i) { 47 | TableEntry* entry; 48 | while ((entry = fBuckets[i]) != NULL) { 49 | deleteEntry(i, entry); 50 | } 51 | } 52 | 53 | // Also free the bucket array, if it was dynamically allocated: 54 | if (fBuckets != fStaticBuckets) delete[] fBuckets; 55 | } 56 | 57 | void* BasicHashTable::Add(char const* key, void* value) { 58 | void* oldValue; 59 | unsigned index; 60 | TableEntry* entry = lookupKey(key, index); 61 | if (entry != NULL) { 62 | // There's already an item with this key 63 | oldValue = entry->value; 64 | } else { 65 | // There's no existing entry; create a new one: 66 | entry = insertNewEntry(index, key); 67 | oldValue = NULL; 68 | } 69 | entry->value = value; 70 | 71 | // If the table has become too large, rebuild it with more buckets: 72 | if (fNumEntries >= fRebuildSize) rebuild(); 73 | 74 | return oldValue; 75 | } 76 | 77 | bool BasicHashTable::Remove(char const* key) { 78 | unsigned index; 79 | TableEntry* entry = lookupKey(key, index); 80 | if (entry == NULL) return false; // no such entry 81 | 82 | deleteEntry(index, entry); 83 | 84 | return true; 85 | } 86 | 87 | void* BasicHashTable::Lookup(char const* key) const { 88 | unsigned index; 89 | TableEntry* entry = lookupKey(key, index); 90 | if (entry == NULL) return NULL; // no such entry 91 | 92 | return entry->value; 93 | } 94 | 95 | unsigned BasicHashTable::numEntries() const { 96 | return fNumEntries; 97 | } 98 | 99 | BasicHashTable::Iterator::Iterator(BasicHashTable& table) 100 | : fTable(table), fNextIndex(0), fNextEntry(NULL) { 101 | } 102 | 103 | void* BasicHashTable::Iterator::next(char const*& key) { 104 | while (fNextEntry == NULL) { 105 | if (fNextIndex >= fTable.fNumBuckets) return NULL; 106 | 107 | fNextEntry = fTable.fBuckets[fNextIndex++]; 108 | } 109 | 110 | BasicHashTable::TableEntry* entry = fNextEntry; 111 | fNextEntry = entry->fNext; 112 | 113 | key = entry->key; 114 | return entry->value; 115 | } 116 | 117 | ////////// Implementation of HashTable creation functions ////////// 118 | 119 | HashTable* HashTable::create(int keyType) { 120 | return new BasicHashTable(keyType); 121 | } 122 | 123 | HashTable::Iterator* HashTable::Iterator::create(HashTable& hashTable) { 124 | // "hashTable" is assumed to be a BasicHashTable 125 | return new BasicHashTable::Iterator((BasicHashTable&)hashTable); 126 | } 127 | 128 | ////////// Implementation of internal member functions ////////// 129 | 130 | BasicHashTable::TableEntry* BasicHashTable 131 | ::lookupKey(char const* key, unsigned& index) const { 132 | TableEntry* entry; 133 | index = hashIndexFromKey(key); 134 | 135 | for (entry = fBuckets[index]; entry != NULL; entry = entry->fNext) { 136 | if (keyMatches(key, entry->key)) break; 137 | } 138 | 139 | return entry; 140 | } 141 | 142 | bool BasicHashTable 143 | ::keyMatches(char const* key1, char const* key2) const { 144 | // The way we check the keys for a match depends upon their type: 145 | if (fKeyType == STRING_HASH_KEYS) { 146 | return (strcmp(key1, key2) == 0); 147 | } else if (fKeyType == ONE_WORD_HASH_KEYS) { 148 | return (key1 == key2); 149 | } else { 150 | unsigned* k1 = (unsigned*)key1; 151 | unsigned* k2 = (unsigned*)key2; 152 | 153 | for (int i = 0; i < fKeyType; ++i) { 154 | if (k1[i] != k2[i]) return false; // keys differ 155 | } 156 | return true; 157 | } 158 | } 159 | 160 | BasicHashTable::TableEntry* BasicHashTable 161 | ::insertNewEntry(unsigned index, char const* key) { 162 | TableEntry* entry = new TableEntry(); 163 | entry->fNext = fBuckets[index]; 164 | fBuckets[index] = entry; 165 | 166 | ++fNumEntries; 167 | assignKey(entry, key); 168 | 169 | return entry; 170 | } 171 | 172 | void BasicHashTable::assignKey(TableEntry* entry, char const* key) { 173 | // The way we assign the key depends upon its type: 174 | if (fKeyType == STRING_HASH_KEYS) { 175 | entry->key = strDup(key); 176 | } else if (fKeyType == ONE_WORD_HASH_KEYS) { 177 | entry->key = key; 178 | } else if (fKeyType > 0) { 179 | unsigned* keyFrom = (unsigned*)key; 180 | unsigned* keyTo = new unsigned[fKeyType]; 181 | for (int i = 0; i < fKeyType; ++i) keyTo[i] = keyFrom[i]; 182 | 183 | entry->key = (char const*)keyTo; 184 | } 185 | } 186 | 187 | void BasicHashTable::deleteEntry(unsigned index, TableEntry* entry) { 188 | TableEntry** ep = &fBuckets[index]; 189 | 190 | bool foundIt = false; 191 | while (*ep != NULL) { 192 | if (*ep == entry) { 193 | foundIt = true; 194 | *ep = entry->fNext; 195 | break; 196 | } 197 | ep = &((*ep)->fNext); 198 | } 199 | 200 | if (!foundIt) { // shouldn't happen 201 | #ifdef DEBUG 202 | fprintf(stderr, "BasicHashTable[%p]::deleteEntry(%d,%p): internal error - not found (first entry %p", this, index, entry, fBuckets[index]); 203 | if (fBuckets[index] != NULL) fprintf(stderr, ", next entry %p", fBuckets[index]->fNext); 204 | fprintf(stderr, ")\n"); 205 | #endif 206 | } 207 | 208 | --fNumEntries; 209 | deleteKey(entry); 210 | delete entry; 211 | } 212 | 213 | void BasicHashTable::deleteKey(TableEntry* entry) { 214 | // The way we delete the key depends upon its type: 215 | if (fKeyType == ONE_WORD_HASH_KEYS) { 216 | entry->key = NULL; 217 | } else { 218 | delete[] (char*)entry->key; 219 | entry->key = NULL; 220 | } 221 | } 222 | 223 | void BasicHashTable::rebuild() { 224 | // Remember the existing table size: 225 | unsigned oldSize = fNumBuckets; 226 | TableEntry** oldBuckets = fBuckets; 227 | 228 | // Create the new sized table: 229 | fNumBuckets *= 4; 230 | fBuckets = new TableEntry*[fNumBuckets]; 231 | for (unsigned i = 0; i < fNumBuckets; ++i) { 232 | fBuckets[i] = NULL; 233 | } 234 | fRebuildSize *= 4; 235 | fDownShift -= 2; 236 | fMask = (fMask<<2)|0x3; 237 | 238 | // Rehash the existing entries into the new table: 239 | for (TableEntry** oldChainPtr = oldBuckets; oldSize > 0; 240 | --oldSize, ++oldChainPtr) { 241 | for (TableEntry* hPtr = *oldChainPtr; hPtr != NULL; 242 | hPtr = *oldChainPtr) { 243 | *oldChainPtr = hPtr->fNext; 244 | 245 | unsigned index = hashIndexFromKey(hPtr->key); 246 | 247 | hPtr->fNext = fBuckets[index]; 248 | fBuckets[index] = hPtr; 249 | } 250 | } 251 | 252 | // Free the old bucket array, if it was dynamically allocated: 253 | if (oldBuckets != fStaticBuckets) delete[] oldBuckets; 254 | } 255 | 256 | unsigned BasicHashTable::hashIndexFromKey(char const* key) const { 257 | unsigned result = 0; 258 | 259 | if (fKeyType == STRING_HASH_KEYS) { 260 | while (1) { 261 | char c = *key++; 262 | if (c == 0) break; 263 | result += (result<<3) + (unsigned)c; 264 | } 265 | result &= fMask; 266 | } else if (fKeyType == ONE_WORD_HASH_KEYS) { 267 | result = randomIndex((unsigned long)key); 268 | } else { 269 | unsigned* k = (unsigned*)key; 270 | unsigned long sum = 0; 271 | for (int i = 0; i < fKeyType; ++i) { 272 | sum += k[i]; 273 | } 274 | result = randomIndex(sum); 275 | } 276 | 277 | return result; 278 | } 279 | 280 | -------------------------------------------------------------------------------- /win32/RTSPClientTest/RTSPClientTest.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {CE6CF4AD-B1DC-42E1-B0F3-E5CFF4452EC0} 23 | Win32Proj 24 | RTSPClientTest 25 | 10.0.17763.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v140 32 | MultiByte 33 | 34 | 35 | Application 36 | true 37 | v140 38 | Unicode 39 | 40 | 41 | Application 42 | false 43 | v140 44 | true 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v140 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | true 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | false 81 | 82 | 83 | 84 | 85 | 86 | Level3 87 | Disabled 88 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 89 | ..\..\OS_Common;..\..\Sock;..\..\RTSPClient\RTSP;..\..\RTSPClient\RTP;..\..\RTSPClient\Common;..\..\RTSPClient\RTCP;..\..\Common;..\..\Util;..\RTSPClientDll;%(AdditionalIncludeDirectories) 90 | 91 | 92 | Console 93 | true 94 | $(TargetDir);%(AdditionalLibraryDirectories) 95 | 96 | 97 | 98 | 99 | 100 | 101 | Level3 102 | Disabled 103 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 104 | ..\..\OS_Common;..\..\Sock;..\..\RTSPClient\RTSP;..\..\RTSPClient\RTP;..\..\RTSPClient\Common;..\..\RTSPClient\RTCP;..\..\Common;..\..\Util;..\RTSPClientDll;%(AdditionalIncludeDirectories) 105 | 106 | 107 | Console 108 | true 109 | $(TargetDir);%(AdditionalLibraryDirectories) 110 | 111 | 112 | 113 | 114 | Level3 115 | 116 | 117 | MaxSpeed 118 | true 119 | true 120 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | ..\..\OS_Common;..\..\Sock;..\..\RTSPClient\RTSP;..\..\RTSPClient\RTP;..\..\RTSPClient\Common;..\..\RTSPClient\RTCP;..\..\Common;..\..\Util;..\RTSPClientDll;%(AdditionalIncludeDirectories) 122 | 123 | 124 | Console 125 | true 126 | true 127 | true 128 | $(TargetDir) 129 | 130 | 131 | 132 | 133 | Level3 134 | 135 | 136 | MaxSpeed 137 | true 138 | true 139 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 140 | ..\..\OS_Common;..\..\Sock;..\..\RTSPClient\RTSP;..\..\RTSPClient\RTP;..\..\RTSPClient\Common;..\..\RTSPClient\RTCP;..\..\Common;..\..\Util;..\RTSPClientDll;%(AdditionalIncludeDirectories) 141 | 142 | 143 | Console 144 | true 145 | true 146 | true 147 | $(TargetDir) 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | --------------------------------------------------------------------------------