├── README.md └── rtspsvr ├── main.cpp ├── makefile ├── media.h ├── tool.h ├── mediactrl.h ├── tool.cpp ├── h264 ├── h264_slice.h ├── base64.h ├── vlc_bits.h └── h264_sps.h ├── mediasub.h ├── media.cpp ├── mediasource.h ├── rtsp.h ├── mediactrl.cpp ├── mediasub.cpp ├── mediasource.cpp └── rtsp.cpp /README.md: -------------------------------------------------------------------------------- 1 | # rtspsvr 2 | 简单rtsp服务器,支持264 aac 3 | 编译需要将 https://github.com/shengang1006/libserver 这个库下载下来,编译里面的watcher-workers/makefile 4 | -------------------------------------------------------------------------------- /rtspsvr/main.cpp: -------------------------------------------------------------------------------- 1 | #include "watcher.h" 2 | #include "rtsp.h" 3 | #include "log.h" 4 | 5 | int main(){ 6 | 7 | debug_log("mysvr init %d\n", sizeof(int64)); 8 | srand((unsigned)time( NULL )); 9 | watcher * s = watcher::instance(); 10 | s->init(); 11 | s->create_tcp_server(554); 12 | log::instance()->init("./log", "rtspsvr"); 13 | 14 | for(int k = 0; k< 4; k++){ 15 | rtsp * svr = new rtsp(); 16 | s->reg_worker(svr); 17 | } 18 | return s->loop(); 19 | } -------------------------------------------------------------------------------- /rtspsvr/makefile: -------------------------------------------------------------------------------- 1 | #������ָ��������·�� 2 | CC := g++ 3 | 4 | #������ָ����Ҫ�Ŀ��ļ� -L 5 | LIBS := -lrt -ldl -lpthread -lserver2 6 | 7 | #������ָ��������Ҫ��ͷ�ļ� 8 | INCLUDE := -I./ -I../include -I./h264 9 | #������lib·�� 10 | LIBPATH := -L../lib 11 | 12 | 13 | #������Դ�ļ� 14 | SRCS := *.cpp 15 | 16 | #������ָ��Ŀ���ļ� ���е�.cpp�ļ�����.o�ļ� 17 | OBJS := $(SRCS:.cpp=.o) 18 | 19 | 20 | #�����DZ���ѡ�� 21 | CFLAGS := -g -Wall -O $(INCLUDE) $(LIBPATH) 22 | CFLAGS += -DLINUX -Wno-unused-function 23 | 24 | #���������ɿ�ִ���ļ� 25 | TARGET := rtspsvr 26 | 27 | 28 | #1������ 2����ѡ�� 3���� 4���ɵĿ�ִ���ļ� 5��Ҫ��Դ�ļ� 6��Ҫ�����ļ� 29 | all: 30 | $(CC) $(CFLAGS) -o $(TARGET) $(SRCS) $(LIBS) 31 | 32 | #make clean ɾ�����е�.o�ļ� 33 | clean: 34 | rm -f ./*.o 35 | -------------------------------------------------------------------------------- /rtspsvr/media.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mediasub.h" 4 | 5 | class MediaSession 6 | { 7 | public: 8 | MediaSession(const std::string & streamName); 9 | 10 | virtual ~MediaSession(); 11 | 12 | void AddSubSession(MediaSubSession * pMediastream); 13 | 14 | void DelSubSession(MediaSubSession * pMediastream); 15 | 16 | MediaSubSession* Lookup(std::string & trackId); 17 | 18 | int SubSessionCount(); 19 | 20 | MediaSubSession * GetSubSession(int index); 21 | 22 | const std::string & StreamName(); 23 | 24 | std::string GenerateSDPDescription(const ipaddr & local); 25 | 26 | uint increaseRef(){return 0;} 27 | 28 | protected: 29 | std::string m_streamName; 30 | uint m_createTime; 31 | std::vector m_vecSubSession; 32 | }; 33 | 34 | -------------------------------------------------------------------------------- /rtspsvr/tool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | #include "utility.h" 10 | typedef unsigned char uchar; 11 | typedef unsigned char uint8; 12 | typedef unsigned short uint16; 13 | 14 | typedef std::string::size_type size_type; 15 | 16 | #define safe_del(x) if(x){delete x; x= NULL;} 17 | 18 | int append(std::string & str, const char* lpszFormat, ...); 19 | 20 | uint random_32(); 21 | 22 | int createUdpSocket(ushort port, int reuse = 0); 23 | 24 | int64 GetTickCount64U(); 25 | 26 | class IStreamCtrl{ 27 | public: 28 | virtual int TransferStream(uchar * data, int len, bool end_of_frame) = 0;; 29 | }; 30 | 31 | class ITimerTask{ 32 | public: 33 | virtual int add_delay_task(int id, int delay, void * context = NULL) = 0; 34 | }; 35 | 36 | class globTimerId{ 37 | public: 38 | static int GetId(); 39 | }; -------------------------------------------------------------------------------- /rtspsvr/mediactrl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mediasource.h" 3 | #include "tool.h" 4 | #include 5 | 6 | class mediaCtrl{ 7 | 8 | public: 9 | mediaCtrl(mediaSource * ms, bool reuse); 10 | virtual ~mediaCtrl(); 11 | 12 | int Prepare(); 13 | int Close(); 14 | 15 | int StartPlay(IStreamCtrl * mss, ITimerTask * task); 16 | int StopPlay(IStreamCtrl * mss); 17 | int Playing(ITimerTask* task); 18 | 19 | uint Timestamp_Inc(); 20 | void setPayloadType(uint type); 21 | int getSdp(std::string & sdp); 22 | 23 | void IncreaseRefernce(); 24 | void DecreaseRefernce(); 25 | int ReferncCount(); 26 | uint TransferInterval(); 27 | 28 | bool IsReuse(); 29 | 30 | const std::string & streamName(); 31 | 32 | protected: 33 | mediaSource * m_mediaSource; 34 | bool m_playing; 35 | bool m_reuse; 36 | bool m_parsed; 37 | std::map m_streamCtrlMap; 38 | int m_refernce; 39 | uint m_timerId; 40 | int64 m_nextTimestamp; 41 | }; 42 | 43 | class mediaCtrlHub{ 44 | public: 45 | static mediaCtrlHub * instance(); 46 | private: 47 | mediaCtrlHub(); 48 | mediaCtrlHub(const mediaCtrlHub &); 49 | mediaCtrlHub & operator = (const mediaCtrlHub &); 50 | mediaCtrl* createMediaCtrl(const std::string & streamName, bool resue); 51 | public: 52 | 53 | mediaCtrl* getMediaCtrl(const std::string & streamName, bool resue); 54 | 55 | void destoryMediaCtrl(mediaCtrl * mc); 56 | 57 | public: 58 | std::map m_mediaCtrlHub; 59 | }; -------------------------------------------------------------------------------- /rtspsvr/tool.cpp: -------------------------------------------------------------------------------- 1 | #include "tool.h" 2 | 3 | int append(std::string & str, const char* lpszFormat, ...){ 4 | char buf[1024 * 64] = {0}; 5 | va_list argList; 6 | va_start(argList, lpszFormat); 7 | int nRet = vsnprintf(buf, sizeof(buf), lpszFormat, argList); 8 | va_end(argList); 9 | str.append(buf); 10 | 11 | return nRet; 12 | } 13 | 14 | uint random_32(){ 15 | return (uint)(rand() * 0x1313131); 16 | } 17 | 18 | int createUdpSocket(ushort port, int reuse /*= 0*/){ 19 | 20 | int sock = socket(AF_INET, SOCK_DGRAM, 0); 21 | if(sock == -1){ 22 | return -1; 23 | } 24 | 25 | if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse))){ 26 | close(sock); 27 | printf("setsockopt SO_REUSEADDR %d\n", errno); 28 | return -1; 29 | } 30 | 31 | int i_val = 1024 * 128; 32 | if (-1 == setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&i_val, sizeof(i_val))){ 33 | close(sock); 34 | printf("setsockopt SO_SNDBUF %d\n",sock); 35 | return -1; 36 | } 37 | 38 | make_no_block(sock); 39 | 40 | sockaddr_in sin ; 41 | sin.sin_family = AF_INET; 42 | sin.sin_addr.s_addr = htonl(INADDR_ANY); 43 | sin.sin_port = htons(port); 44 | 45 | if (-1 == bind(sock, (struct sockaddr*)&sin, sizeof(sin))) { 46 | close(sock); 47 | printf("Create bind port %d error\n",port); 48 | return -1; 49 | } 50 | 51 | return sock; 52 | } 53 | 54 | int64 GetTickCount64U(){ 55 | struct timeval tv = {0}; 56 | gettimeofday(&tv, NULL); 57 | return ((int64)tv.tv_sec * 1000000) + tv.tv_usec; 58 | } 59 | 60 | 61 | 62 | int globTimerId::GetId(){ 63 | static int idint = ev_sys_user + 11; 64 | return __sync_fetch_and_add(&idint, 1); 65 | } -------------------------------------------------------------------------------- /rtspsvr/h264/h264_slice.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "vlc_bits.h" 4 | #include "h264_sps.h" 5 | 6 | typedef struct h264_slice_t 7 | { 8 | int i_slice_type; 9 | int i_pic_parameter_set_id; 10 | int i_frame_num; 11 | int i_field_pic_flag; 12 | int i_bottom_field_flag; 13 | int i_idr_pic_id; 14 | int i_pic_order_cnt_lsb; 15 | }h264_slice_t; 16 | 17 | static void h264_decode_slice(h264_slice_t* p_slice, 18 | uint8* p_nal, int n_nal_size, int i_nal_type, 19 | const h264_sps_t* p_sps) 20 | { 21 | bs_t s; 22 | bs_init(&s, p_nal, n_nal_size); 23 | 24 | bs_skip(&s, 8); 25 | 26 | bs_read_ue( &s ); // first_mb_in_slice 27 | p_slice->i_slice_type = bs_read_ue( &s ); // slice type 28 | p_slice->i_pic_parameter_set_id = bs_read_ue( &s ); 29 | 30 | if (p_sps->residual_color_transform_flag) 31 | { 32 | /*colour_plane_id*/ 33 | bs_skip(&s, 2); 34 | } 35 | 36 | p_slice->i_frame_num = bs_read( &s, p_sps->log2_max_frame_num); 37 | 38 | if( !p_sps->frame_mbs_only_flag) 39 | { 40 | /* field_pic_flag */ 41 | p_slice->i_field_pic_flag = bs_read( &s, 1 ); 42 | if( p_slice->i_field_pic_flag ) 43 | p_slice->i_bottom_field_flag = bs_read( &s, 1 ); 44 | } 45 | 46 | //int i_idr_pic_id; 47 | if( i_nal_type == 5/*NAL_SLICE_IDR*/ ) 48 | p_slice->i_idr_pic_id = bs_read_ue( &s ); 49 | 50 | //int i_delta_pic_order_cnt_bottom = -1; 51 | int i_delta_pic_order_cnt0 = 0; 52 | // int i_delta_pic_order_cnt1 = 0; 53 | 54 | p_slice->i_pic_order_cnt_lsb = 0; 55 | 56 | if( p_sps->poc_type == 0 ) 57 | { 58 | p_slice->i_pic_order_cnt_lsb = bs_read( &s, p_sps->log2_max_poc_lsb + 4 ); 59 | // if( g_pic_order_present_flag && !i_field_pic_flag ) 60 | // i_delta_pic_order_cnt_bottom = bs_read_se( &s ); 61 | } 62 | else if( (p_sps->poc_type == 1) && 63 | (!p_sps->delta_pic_order_always_zero_flag) ) 64 | { 65 | i_delta_pic_order_cnt0 = bs_read_se( &s ); 66 | // if( g_pic_order_present_flag && !i_field_pic_flag ) 67 | // i_delta_pic_order_cnt1 = bs_read_se( &s ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /rtspsvr/mediasub.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "mediactrl.h" 6 | 7 | #define RTP_TCP_EXTRA_HEADER 4 8 | #define RTP_MTU 1400 9 | enum{RTP_UDP, RTP_TCP, RAW_UDP}; 10 | 11 | class MediaSubSession:public IStreamCtrl{ 12 | 13 | public: 14 | MediaSubSession(mediaCtrl * mc); 15 | 16 | virtual ~MediaSubSession(); 17 | void SetTrackId(uint trackID); 18 | const std::string & GetTrackId(); 19 | void SetPayloadType(uint8 number); 20 | virtual int GetSdpLines(std::string & sdpLines); 21 | 22 | //set up 23 | virtual int GetUdpParam(uint clientRtpPort, 24 | uint clientRtcpPort, 25 | uint dstIp, 26 | uint & serverRtpPort, 27 | uint & serverRtcpPort); 28 | 29 | virtual int GetTcpParam( 30 | void * tcpConnection, 31 | uint8 rtpChannelId, 32 | uint8 rtcpChannelId, 33 | uint8 &dstTTL); 34 | 35 | virtual int StartStream(ITimerTask* task); //play 36 | virtual int PauseStream(); 37 | virtual int SeekStream(); 38 | 39 | //tear down 40 | virtual int StopStream(); 41 | virtual uint RtpTimestamp(); 42 | virtual uint SeqNo(); 43 | 44 | int SendPacket(uint8 * data, int len); 45 | int SendRtpOverUdp(uint8 * data, int len); 46 | int SendRtpOverTcp(uint8 * data, int len); 47 | 48 | protected: 49 | 50 | std::string m_trackIdStr; 51 | 52 | uint8 m_payLoadType; 53 | uint m_timestamp; 54 | int m_proto; 55 | 56 | mediaCtrl * m_mediaCtrl; 57 | 58 | uint16 m_seqNO; 59 | uint m_ssrc; 60 | socket_pair m_socket_pair; 61 | }; 62 | 63 | 64 | class H264MediaSubSession : public MediaSubSession{ 65 | public: 66 | H264MediaSubSession(mediaCtrl * mc); 67 | virtual ~H264MediaSubSession(); 68 | int GetSdpLines(std::string & sdpLines); 69 | int TransferStream(uint8 * data, int len, bool end_of_frame); 70 | }; 71 | 72 | 73 | class Mp4AMediaSubSession : public MediaSubSession{ 74 | public: 75 | Mp4AMediaSubSession(mediaCtrl * mc); 76 | virtual ~Mp4AMediaSubSession(); 77 | int GetSdpLines(std::string & sdpLines); 78 | int TransferStream(uint8 * data, int len, bool end_of_frame); 79 | }; 80 | -------------------------------------------------------------------------------- /rtspsvr/h264/base64.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #define char64(c) ((c > 127) ? (char) 0xff : index_64[(c)]) 5 | 6 | static uint load_block(const char * in, uint size, uint pos, char * out){ 7 | uint i, len; 8 | uint c; 9 | len = i = 0; 10 | while ((len<4) && ((pos+i)='A') && (c<='Z')) 13 | || ((c>='a') && (c<='z')) 14 | || ((c>='0') && (c<='9')) 15 | || (c=='=') || (c=='+') || (c=='/') 16 | ) { 17 | out[len] = c; 18 | len++; 19 | } 20 | i++; 21 | } 22 | while (len<4) { out[len] = (char) 0xFF; len++; } 23 | return pos+i; 24 | }; 25 | 26 | 27 | /*! 28 | *\brief base64 encoder 29 | * 30 | *Encodes a data buffer to Base64 31 | *\param pData input data buffer 32 | *\param dataSize input data buffer size 33 | *\param base64String output Base64 buffer 34 | *\return size of the encoded Base64 buffer 35 | *\note the encoded data buffer is not NULL-terminated. 36 | */ 37 | inline static uint Base64Encode(uint8 * pData, uint dataSize, std::string & base64){ 38 | const char base_64[128] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 39 | 40 | int padding; 41 | uint i = 0, j = 0; 42 | 43 | uint8 * in; 44 | uint outSize; 45 | uint8 * out; 46 | 47 | uint iOut = ((dataSize + 2) / 3) * 4; 48 | outSize = iOut += 2 * ((iOut / 60) + 1); 49 | out = new uint8 [outSize]; 50 | 51 | in = pData; 52 | 53 | if (outSize < (dataSize * 4 / 3)) return 0; 54 | 55 | while (i < dataSize) { 56 | padding = 3 - (dataSize - i); 57 | if (padding == 2) { 58 | out[j] = base_64[in[i]>>2]; 59 | out[j+1] = base_64[(in[i] & 0x03) << 4]; 60 | out[j+2] = '='; 61 | out[j+3] = '='; 62 | } else if (padding == 1) { 63 | out[j] = base_64[in[i]>>2]; 64 | out[j+1] = base_64[((in[i] & 0x03) << 4) | ((in[i+1] & 0xf0) >> 4)]; 65 | out[j+2] = base_64[(in[i+1] & 0x0f) << 2]; 66 | out[j+3] = '='; 67 | } else{ 68 | out[j] = base_64[in[i]>>2]; 69 | out[j+1] = base_64[((in[i] & 0x03) << 4) | ((in[i+1] & 0xf0) >> 4)]; 70 | out[j+2] = base_64[((in[i+1] & 0x0f) << 2) | ((in[i+2] & 0xc0) >> 6)]; 71 | out[j+3] = base_64[in[i+2] & 0x3f]; 72 | } 73 | i += 3; 74 | j += 4; 75 | } 76 | out[j] = '\0'; 77 | base64 = (char*)out; 78 | delete[] out; 79 | return j; 80 | } 81 | -------------------------------------------------------------------------------- /rtspsvr/media.cpp: -------------------------------------------------------------------------------- 1 | #include "media.h" 2 | 3 | 4 | /*--------------------------------------- 5 | * 6 | * 7 | *-------------------------------------*/ 8 | MediaSession::MediaSession(const std::string & streamName) 9 | :m_streamName(streamName){ 10 | m_vecSubSession.clear(); 11 | } 12 | 13 | MediaSession::~MediaSession(){ 14 | for(std::vector ::iterator it = m_vecSubSession.begin(); 15 | it != m_vecSubSession.end(); it++){ 16 | (*it)->StopStream(); 17 | delete *it; 18 | } 19 | m_vecSubSession.clear(); 20 | } 21 | 22 | void MediaSession::AddSubSession(MediaSubSession * pMediastream) 23 | { 24 | pMediastream->SetPayloadType(m_vecSubSession.size()); 25 | m_vecSubSession.push_back(pMediastream); 26 | } 27 | 28 | void MediaSession::DelSubSession(MediaSubSession * pMediastream) 29 | { 30 | for(std::vector ::iterator it = m_vecSubSession.begin(); 31 | it != m_vecSubSession.end(); it++){ 32 | if ((*it) == pMediastream){ 33 | m_vecSubSession.erase(it); 34 | break; 35 | } 36 | } 37 | } 38 | 39 | MediaSubSession* MediaSession::Lookup(std::string & trackId) 40 | { 41 | for(std::vector ::iterator it = m_vecSubSession.begin(); 42 | it != m_vecSubSession.end(); it++){ 43 | if ((*it)->GetTrackId() == trackId){ 44 | return *it; 45 | } 46 | } 47 | return NULL; 48 | } 49 | 50 | int MediaSession::SubSessionCount(){ 51 | return m_vecSubSession.size(); 52 | } 53 | 54 | MediaSubSession * MediaSession::GetSubSession(int index){ 55 | return m_vecSubSession[index]; 56 | } 57 | 58 | 59 | const std::string & MediaSession::StreamName(){ 60 | return m_streamName; 61 | } 62 | 63 | 64 | std::string MediaSession::GenerateSDPDescription(const ipaddr & local){ 65 | //v = SDP version 66 | std::string sdp("v=0\r\n"); 67 | 68 | //o= 69 | append(sdp, "o=- %u %u IN IP4 %s:%d\r\n", m_createTime, m_createTime, local.ip, local.port); 70 | 71 | 72 | // v = session name 73 | sdp.append("s=RTSP SERVER 2014.6.27\r\n"); 74 | 75 | //i = sdp information 76 | sdp.append("i=An Example of RTSP Session Usage\r\n"); 77 | 78 | //ʱ����Ϣ���ֱ���ʾ��ʼ��ʱ���ͽ�����ʱ�䣬һ������ý����ֱ����ʱ���м��ıȽ϶ࡣ 79 | sdp.append("t=0 0\r\n"); 80 | 81 | sdp.append("a=type:broadcast\r\n"); 82 | 83 | sdp.append("a=control:*\r\n"); 84 | 85 | //get duration here,������ʾý�����ij��� 86 | float duration = 0.0; 87 | append(sdp, "a=range:npt=0-%.3f\r\n", duration); 88 | 89 | //get media strem sdp 90 | for(std::vector ::iterator it = m_vecSubSession.begin(); 91 | it != m_vecSubSession.end(); it++) 92 | { 93 | std::string subSdp; 94 | (*it)->GetSdpLines(subSdp); 95 | sdp.append(subSdp); 96 | } 97 | 98 | return sdp; 99 | } 100 | -------------------------------------------------------------------------------- /rtspsvr/mediasource.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "tool.h" 4 | #include "h264_sps.h" 5 | #include "h264_slice.h" 6 | #include "base64.h" 7 | #include 8 | 9 | #define MaxBufSize (1024 * 1024 ) 10 | 11 | struct framebuffer{ 12 | uchar * buf; 13 | int len; 14 | int rpos; 15 | int wpos; 16 | }; 17 | 18 | struct socket_pair{ 19 | 20 | int rtp_socket; 21 | ushort rtp_port; 22 | uint dst_rtpIp; 23 | ushort dst_rtpPort; 24 | 25 | int rtcp_socket; 26 | ushort rtcp_port; 27 | uint dst_rtcpIp; 28 | ushort dst_rtcpPort; 29 | 30 | void* tcp_connection; 31 | uchar rtp_channel; 32 | uchar rtcp_channel; 33 | }; 34 | 35 | 36 | class mediaSource{ 37 | 38 | public: 39 | mediaSource(const std::string & streamName); 40 | virtual ~mediaSource(); 41 | 42 | virtual int parseMedia()= 0; 43 | virtual int NextFrame(uchar ** payload, int & payload_size, bool & end_of_frame)= 0; 44 | virtual uint Timestamp_Inc()= 0; 45 | virtual uint uDuration()= 0; 46 | virtual void SetPayloadType(uint type)= 0; 47 | virtual int closeMedia() = 0; 48 | virtual int getSdp(std::string & sdp) = 0; 49 | const std::string & GetstreamName(); 50 | protected: 51 | 52 | std::string m_streamName; 53 | }; 54 | 55 | /*---------------------------------------*/ 56 | class h264FileSource:public mediaSource{ 57 | 58 | public: 59 | h264FileSource(const std::string & fileName); 60 | ~h264FileSource(); 61 | 62 | int parseMedia(); 63 | int getSdp(std::string & sdp); 64 | int closeMedia(); 65 | 66 | int NextFrame(uchar ** payload, int & payload_size, bool & access_unit_end); 67 | uint Timestamp_Inc(); 68 | uint uDuration(); 69 | void SetPayloadType(uint type); 70 | 71 | protected: 72 | void h264_decode_annexb(uchar *dst, int *dstlen, const uchar *src, const int srclen); 73 | int h264_split_nal(uchar * p_data, uint buf_size, uchar ** payload, 74 | int & payload_size, int & consume); 75 | int get_naul(uchar ** payload, int & payload_size); 76 | int get_next_naul_bytes(uint8 * data, int bytes); 77 | protected: 78 | FILE * m_fFid; 79 | uint m_payloadType; 80 | framebuffer m_frameBuf; 81 | float m_frameRate; 82 | h264_sps_t m_sps; 83 | std::string m_sps_base64; 84 | std::string m_pps_base64; 85 | uint m_profile_level_id; 86 | }; 87 | 88 | 89 | /*---------------------------------------*/ 90 | class aacFileSource:public mediaSource{ 91 | public: 92 | aacFileSource(const std::string & fileName); 93 | virtual ~aacFileSource(); 94 | int parseMedia(); 95 | int getSdp(std::string & sdp); 96 | int closeMedia(); 97 | 98 | int NextFrame(uchar ** payload, int & payload_size, bool & access_unit_end); 99 | void SetPayloadType(uint type); 100 | uint Timestamp_Inc(); 101 | uint uDuration(); 102 | 103 | protected: 104 | int get_frame(uchar * p_data, uint buf_size, uchar ** payload, int & payload_size, int & consume); 105 | private: 106 | FILE * m_fFid; 107 | uint m_samplingFrequency; 108 | uint m_channels; 109 | uint m_payloadType; 110 | framebuffer m_frameBuf; 111 | uint8 m_cfg0; 112 | uint8 m_cfg1; 113 | }; 114 | -------------------------------------------------------------------------------- /rtspsvr/rtsp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "worker.h" 5 | #include "media.h" 6 | 7 | class rtsp; 8 | class RtspClientSession; 9 | 10 | class RtspClientConnection 11 | { 12 | public: 13 | RtspClientConnection(connection * n, rtsp * r); 14 | virtual ~RtspClientConnection(); 15 | 16 | int handle_options(); 17 | 18 | int handle_describle( 19 | std::string & urlPreSuffix, 20 | std::string & urlSuffix, 21 | std::string & fullRequestStr); 22 | 23 | int handle_getparameter(std::string & fullRequestStr); 24 | 25 | int handle_setparameter(std::string & fullRequestStr); 26 | 27 | int handleCmd_bad(){return setRtspResponse("400 Bad Request");} 28 | 29 | int handleCmd_notSupported(){return setRtspResponse("405 Method Not Allowed");} 30 | 31 | int handleCmd_notFound(){return setRtspResponse("404 stream not find");} 32 | 33 | int handleCmd_sessionNotFound(){return setRtspResponse("454 Session Not Found");} 34 | 35 | int handleCmd_unsupportedTransport(){return setRtspResponse("461 Unsupported Transport");} 36 | 37 | int setRtspResponse(const char * responseStr); 38 | int setRtspResponse(const char * responseStr, const char * contentStr); 39 | int setRtspResponseSession(const char * responseStr, const char * seseionId); 40 | int setRtspResponse(const char * responseStr, const char * seseionId, const char * contentStr); 41 | 42 | const ipaddr & get_localaddr(); 43 | const ipaddr & get_peeraddr(); 44 | 45 | std::string &getSeq(); 46 | void SetSeq(std::string & seqNo); 47 | int post_send(const char * data, int len); 48 | rtsp* get_rtsp(); 49 | 50 | RtspClientSession * createNewRtspClientSession(); 51 | RtspClientSession * lookupRtspClientSession(const std::string & sessionId); 52 | protected: 53 | ipaddr m_serveAddr; 54 | connection * m_client; 55 | rtsp * m_rtsp; 56 | std::string m_seqNo; 57 | std::map m_clientSessionMap; 58 | }; 59 | 60 | class RtspClientSession{ 61 | public: 62 | RtspClientSession(std::string & sessionId); 63 | ~RtspClientSession(); 64 | 65 | int handle_setup( 66 | RtspClientConnection * rcc, 67 | std::string & urlPreSuffix, 68 | std::string & urlSuffix, 69 | std::string & fullRequestStr); 70 | 71 | int handle_insession( 72 | RtspClientConnection * rcc, 73 | std::string & cmd, 74 | std::string & urlPreSuffix, 75 | std::string & urlSuffix, 76 | std::string & fullRequestStr); 77 | 78 | int handle_play( 79 | RtspClientConnection * rcc, 80 | MediaSubSession * subSession, 81 | std::string & fullRequestStr); 82 | 83 | int handle_pause( 84 | RtspClientConnection * rcc, 85 | MediaSubSession * subSession); 86 | 87 | int handle_teardown( 88 | RtspClientConnection * rcc, 89 | MediaSubSession * subSession, 90 | std::string & fullRequestStr); 91 | 92 | int handle_getparameter( 93 | RtspClientConnection * rcc, 94 | MediaSubSession * subSession, 95 | std::string & fullRequestStr); 96 | 97 | int handle_setparameter( 98 | RtspClientConnection * rcc, 99 | MediaSubSession * subSession, 100 | std::string & fullRequestStr); 101 | 102 | protected: 103 | MediaSession * m_mediaSession; 104 | uint8 m_tcpStreamCount; 105 | std::string m_sessionId; 106 | }; 107 | 108 | 109 | class rtsp : public worker, ITimerTask{ 110 | public: 111 | virtual ~rtsp(); 112 | rtsp(); 113 | 114 | int on_initialize(); 115 | int on_accept(connection * n) ; 116 | int on_recv(connection * n, char * data, int len) ; 117 | int on_close(connection * n, int reason) ; 118 | int on_connect(connection * n) ; 119 | int on_timer(int event, int interval, void * ptr) ; 120 | int on_unpack(char * data, int len, int& packlen, char *&packet); 121 | 122 | int rtsp_msg(connection * n, char * data, int len); 123 | int rtp_msg(connection * n, char * data, int len); 124 | 125 | int add_delay_task(int id, int delay, void * context = NULL); 126 | 127 | virtual MediaSession* createAttachMediaSession(std::string & streamName); 128 | virtual MediaSession* getAndDetachMediaSession(std::string & streamName); 129 | 130 | friend class RtspClientSession; 131 | protected: 132 | virtual MediaSession* createMediaSession(std::string & streamName); 133 | 134 | private: 135 | std::map m_mediaSessionMap; 136 | }; -------------------------------------------------------------------------------- /rtspsvr/mediactrl.cpp: -------------------------------------------------------------------------------- 1 | #include "mediactrl.h" 2 | 3 | mediaCtrl::mediaCtrl(mediaSource * ms, bool reuse){ 4 | m_playing = false; 5 | m_parsed = false; 6 | m_refernce = 0; 7 | m_mediaSource = ms; 8 | m_nextTimestamp = 0; 9 | m_reuse = reuse; 10 | m_timerId = globTimerId::GetId(); 11 | } 12 | 13 | mediaCtrl:: ~mediaCtrl(){ 14 | printf("~mediaCtrl\n"); 15 | safe_del(m_mediaSource); 16 | } 17 | 18 | int mediaCtrl::StartPlay(IStreamCtrl * mss, ITimerTask* task){ 19 | if (!m_playing){ 20 | m_playing = true; 21 | m_nextTimestamp = 0; 22 | IncreaseRefernce(); 23 | task->add_delay_task(m_timerId, 0, this); 24 | } 25 | m_streamCtrlMap[mss] = true; 26 | return 0; 27 | } 28 | 29 | int mediaCtrl::StopPlay(IStreamCtrl * mss){ 30 | m_streamCtrlMap.erase(mss); 31 | return 0; 32 | } 33 | 34 | int mediaCtrl::Prepare(){ 35 | if(!m_parsed){ 36 | m_parsed = true; 37 | return m_mediaSource->parseMedia(); 38 | } 39 | return 0; 40 | } 41 | 42 | int mediaCtrl::Close(){ 43 | if(m_reuse){ 44 | return 0; 45 | } 46 | m_parsed = false; 47 | m_playing = false; 48 | return m_mediaSource->closeMedia(); 49 | } 50 | 51 | bool mediaCtrl::IsReuse(){ 52 | return m_reuse; 53 | } 54 | 55 | uint mediaCtrl::Timestamp_Inc(){ 56 | return m_mediaSource->Timestamp_Inc(); 57 | } 58 | 59 | int mediaCtrl::getSdp(std::string & sdp){ 60 | return m_mediaSource->getSdp(sdp); 61 | } 62 | 63 | void mediaCtrl::setPayloadType(uint type){ 64 | m_mediaSource->SetPayloadType(type); 65 | } 66 | 67 | const std::string & mediaCtrl::streamName(){ 68 | return m_mediaSource->GetstreamName(); 69 | } 70 | 71 | int mediaCtrl::Playing(ITimerTask * task){ 72 | 73 | DecreaseRefernce(); 74 | 75 | uchar* payload = NULL; 76 | int payload_size = 0; 77 | bool end_of_frame = false; 78 | while(!end_of_frame){ 79 | 80 | int ret = m_mediaSource->NextFrame(&payload, payload_size, end_of_frame); 81 | if (ret < 0){ 82 | printf("debug:Playing fail or end\n"); 83 | m_streamCtrlMap.clear(); 84 | m_mediaSource->closeMedia(); 85 | return -1; 86 | } 87 | std::map::iterator it = m_streamCtrlMap.begin(); 88 | for(; it != m_streamCtrlMap.end(); it++){ 89 | it->first->TransferStream(payload, payload_size,end_of_frame); 90 | } 91 | } 92 | 93 | IncreaseRefernce(); 94 | task->add_delay_task(m_timerId, TransferInterval(), this); 95 | return 0; 96 | } 97 | 98 | void mediaCtrl::IncreaseRefernce(){ 99 | m_refernce++; 100 | } 101 | 102 | void mediaCtrl::DecreaseRefernce(){ 103 | m_refernce--; 104 | } 105 | 106 | int mediaCtrl::ReferncCount(){ 107 | return m_refernce; 108 | } 109 | 110 | uint mediaCtrl::TransferInterval(){ 111 | 112 | int64 nowTimestamp = GetTickCount64U(); 113 | 114 | uint duration = m_mediaSource->uDuration();//us 115 | int interval = 0; 116 | 117 | if (!m_nextTimestamp){ 118 | m_nextTimestamp = nowTimestamp + duration; 119 | interval = duration; 120 | } 121 | else{ 122 | m_nextTimestamp += duration; 123 | interval = (int)(m_nextTimestamp - nowTimestamp); 124 | } 125 | if (interval < 0){ 126 | interval = 0; 127 | } 128 | return interval/1000; 129 | } 130 | 131 | //////////////////////////////////////////////////////// 132 | 133 | mediaCtrlHub::mediaCtrlHub(){ 134 | 135 | } 136 | 137 | mediaCtrlHub * mediaCtrlHub::instance(){ 138 | static mediaCtrlHub mch; 139 | return &mch; 140 | } 141 | 142 | mediaCtrl* mediaCtrlHub::getMediaCtrl(const std::string & streamName, bool resue){ 143 | 144 | mediaCtrl * ms = NULL; 145 | if(!resue){ 146 | ms = createMediaCtrl(streamName, resue); 147 | } 148 | else{ 149 | std::map::iterator it = m_mediaCtrlHub.find(streamName); 150 | if (it == m_mediaCtrlHub.end()){ 151 | ms = createMediaCtrl(streamName, resue); 152 | } 153 | else{ 154 | ms = it->second; 155 | } 156 | } 157 | 158 | if(!ms){ 159 | return ms; 160 | } 161 | 162 | ms->IncreaseRefernce(); 163 | if(resue){ 164 | m_mediaCtrlHub[streamName] = ms; 165 | } 166 | 167 | return ms; 168 | } 169 | 170 | void mediaCtrlHub::destoryMediaCtrl(mediaCtrl * mc){ 171 | if(mc->ReferncCount()){ 172 | mc->DecreaseRefernce(); 173 | } 174 | printf("destoryMediaCtrl %d\n", mc->ReferncCount()); 175 | if(!mc->ReferncCount()){ 176 | if(mc->IsReuse()){ 177 | m_mediaCtrlHub.erase(mc->streamName()); 178 | } 179 | delete mc; 180 | } 181 | } 182 | 183 | mediaCtrl* mediaCtrlHub::createMediaCtrl(const std::string & streamName, bool resue){ 184 | size_type pos = streamName.rfind('.'); 185 | if (pos == std::string::npos){ 186 | return NULL; 187 | } 188 | std::string extension = streamName.substr(pos , streamName.length() - pos); 189 | mediaCtrl * mc = NULL; 190 | if (extension == ".264" || extension == ".h264"){ 191 | mc =new mediaCtrl(new h264FileSource(streamName), resue); 192 | } 193 | else if(extension == ".aac"){ 194 | mc = new mediaCtrl(new aacFileSource(streamName), resue); 195 | } 196 | 197 | return mc; 198 | } 199 | 200 | -------------------------------------------------------------------------------- /rtspsvr/h264/vlc_bits.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * bits.h : Bit handling helpers 3 | ***************************************************************************** 4 | * Copyright (C) 2003 the VideoLAN team 5 | * $Id$ 6 | * 7 | * Authors: Laurent Aimar 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. 22 | *****************************************************************************/ 23 | 24 | #ifndef VLC_BITS_H 25 | #define VLC_BITS_H 1 26 | 27 | /** 28 | * \file 29 | * This file defines functions, structures for handling streams of bits in vlc 30 | */ 31 | 32 | typedef struct bs_s 33 | { 34 | uchar *p_start; 35 | uchar *p; 36 | uchar *p_end; 37 | 38 | int i_left; /* i_count number of available bits */ 39 | } bs_t; 40 | 41 | static inline void bs_init( bs_t *s, void *p_data, int i_data ) 42 | { 43 | s->p_start = (uchar*)p_data; 44 | s->p = (uchar*)p_data; 45 | s->p_end = s->p + i_data; 46 | s->i_left = 8; 47 | } 48 | 49 | static inline int bs_pos( bs_t *s ) 50 | { 51 | return( 8 * ( s->p - s->p_start ) + 8 - s->i_left ); 52 | } 53 | 54 | static inline int bs_eof( bs_t *s ) 55 | { 56 | return( s->p >= s->p_end ? 1: 0 ); 57 | } 58 | 59 | static inline uint bs_read( bs_t *s, int i_count ) 60 | { 61 | static const uint i_mask[33] = 62 | { 0x00, 63 | 0x01, 0x03, 0x07, 0x0f, 64 | 0x1f, 0x3f, 0x7f, 0xff, 65 | 0x1ff, 0x3ff, 0x7ff, 0xfff, 66 | 0x1fff, 0x3fff, 0x7fff, 0xffff, 67 | 0x1ffff, 0x3ffff, 0x7ffff, 0xfffff, 68 | 0x1fffff, 0x3fffff, 0x7fffff, 0xffffff, 69 | 0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff, 70 | 0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff}; 71 | int i_shr; 72 | uint i_result = 0; 73 | 74 | while( i_count > 0 ) 75 | { 76 | if( s->p >= s->p_end ) 77 | { 78 | break; 79 | } 80 | 81 | if( ( i_shr = s->i_left - i_count ) >= 0 ) 82 | { 83 | /* more in the buffer than requested */ 84 | i_result |= ( *s->p >> i_shr )&i_mask[i_count]; 85 | s->i_left -= i_count; 86 | if( s->i_left == 0 ) 87 | { 88 | s->p++; 89 | s->i_left = 8; 90 | } 91 | return( i_result ); 92 | } 93 | else 94 | { 95 | /* less in the buffer than requested */ 96 | i_result |= (*s->p&i_mask[s->i_left]) << -i_shr; 97 | i_count -= s->i_left; 98 | s->p++; 99 | s->i_left = 8; 100 | } 101 | } 102 | 103 | return( i_result ); 104 | } 105 | 106 | static inline uint bs_read1( bs_t *s ) 107 | { 108 | if( s->p < s->p_end ) 109 | { 110 | unsigned int i_result; 111 | 112 | s->i_left--; 113 | i_result = ( *s->p >> s->i_left )&0x01; 114 | if( s->i_left == 0 ) 115 | { 116 | s->p++; 117 | s->i_left = 8; 118 | } 119 | return i_result; 120 | } 121 | 122 | return 0; 123 | } 124 | 125 | static inline uint bs_show( bs_t *s, int i_count ) 126 | { 127 | bs_t s_tmp = *s; 128 | return bs_read( &s_tmp, i_count ); 129 | } 130 | 131 | static inline void bs_skip( bs_t *s, int i_count ) 132 | { 133 | s->i_left -= i_count; 134 | 135 | while( s->i_left <= 0 ) 136 | { 137 | s->p++; 138 | s->i_left += 8; 139 | } 140 | } 141 | 142 | static inline void bs_write( bs_t *s, int i_count, uint i_bits ) 143 | { 144 | while( i_count > 0 ) 145 | { 146 | if( s->p >= s->p_end ) 147 | { 148 | break; 149 | } 150 | 151 | i_count--; 152 | 153 | if( ( i_bits >> i_count )&0x01 ) 154 | { 155 | *s->p |= 1 << ( s->i_left - 1 ); 156 | } 157 | else 158 | { 159 | *s->p &= ~( 1 << ( s->i_left - 1 ) ); 160 | } 161 | s->i_left--; 162 | if( s->i_left == 0 ) 163 | { 164 | s->p++; 165 | s->i_left = 8; 166 | } 167 | } 168 | } 169 | 170 | static inline void bs_align( bs_t *s ) 171 | { 172 | if( s->i_left != 8 ) 173 | { 174 | s->i_left = 8; 175 | s->p++; 176 | } 177 | } 178 | 179 | static inline void bs_align_0( bs_t *s ) 180 | { 181 | if( s->i_left != 8 ) 182 | { 183 | bs_write( s, s->i_left, 0 ); 184 | } 185 | } 186 | 187 | static inline void bs_align_1( bs_t *s ) 188 | { 189 | while( s->i_left != 8 ) 190 | { 191 | bs_write( s, 1, 1 ); 192 | } 193 | } 194 | 195 | static inline int bs_read_ue( bs_t *s ) 196 | { 197 | int i = 0; 198 | 199 | while( bs_read1( s ) == 0 && s->p < s->p_end && i < 32 ) 200 | { 201 | i++; 202 | } 203 | return( ( 1 << i) - 1 + bs_read( s, i ) ); 204 | } 205 | 206 | static inline int bs_read_se( bs_t *s ) 207 | { 208 | int val = bs_read_ue( s ); 209 | 210 | return val&0x01 ? (val+1)/2 : -(val/2); 211 | } 212 | #endif 213 | -------------------------------------------------------------------------------- /rtspsvr/h264/h264_sps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "vlc_bits.h" 4 | 5 | /** 6 | * Rational number num/den. 7 | */ 8 | typedef struct AVRational_t{ 9 | int num; ///< numerator 10 | int den; ///< denominator 11 | } AVRational_t; 12 | 13 | /** 14 | * Sequence parameter set 15 | */ 16 | typedef struct h264_sps_t{ 17 | 18 | int profile_idc; 19 | int level_idc; 20 | int transform_bypass; ///< qpprime_y_zero_transform_bypass_flag 21 | int log2_max_frame_num; ///< log2_max_frame_num_minus4 + 4 22 | int poc_type; ///< pic_order_cnt_type 23 | int log2_max_poc_lsb; ///< log2_max_pic_order_cnt_lsb_minus4 24 | int delta_pic_order_always_zero_flag; 25 | int offset_for_non_ref_pic; 26 | int offset_for_top_to_bottom_field; 27 | int poc_cycle_length; ///< num_ref_frames_in_pic_order_cnt_cycle 28 | int ref_frame_count; ///< num_ref_frames 29 | int gaps_in_frame_num_allowed_flag; 30 | int mb_width; ///< frame_width_in_mbs_minus1 + 1 31 | int mb_height; ///< frame_height_in_mbs_minus1 + 1 32 | int frame_mbs_only_flag; 33 | int mb_aff; ///profile_idc = bs_read( &s, 8); 90 | 91 | /* constraint_set012, reserver(5), level(8) */ 92 | bs_skip( &s, 8 + 8 ); 93 | 94 | /* sps id */ 95 | i_sps_id = bs_read_ue( &s ); 96 | if( i_sps_id >= 32/*SPS_MAX*/ ) 97 | { 98 | printf("invalid SPS (sps_id=%d)", i_sps_id ); 99 | return false; 100 | } 101 | 102 | p_sps->scaling_matrix_present = 0; 103 | if(p_sps->profile_idc >= 100) //high profile 104 | { 105 | if(bs_read_ue(&s) == 3) //chroma_format_idc 106 | p_sps->residual_color_transform_flag = bs_read(&s, 1);//residual_color_transform_flag 107 | bs_read_ue(&s); //bit_depth_luma_minus8 108 | bs_read_ue(&s); //bit_depth_chroma_minus8 109 | p_sps->transform_bypass = bs_read(&s, 1); 110 | bs_skip(&s, 1); //decode_scaling_matrices(h, sps, NULL, 1, sps->scaling_matrix4, sps->scaling_matrix8); 111 | } 112 | 113 | /* Skip i_log2_max_frame_num */ 114 | p_sps->log2_max_frame_num = bs_read_ue( &s ) + 4; 115 | if( p_sps->log2_max_frame_num > 12) 116 | p_sps->log2_max_frame_num = 12; 117 | /* Read poc_type */ 118 | p_sps->poc_type/*->i_pic_order_cnt_type*/ = bs_read_ue( &s ); 119 | if( p_sps->poc_type == 0 ) 120 | { 121 | /* skip i_log2_max_poc_lsb */ 122 | p_sps->log2_max_poc_lsb/*->i_log2_max_pic_order_cnt_lsb*/ = bs_read_ue( &s ); 123 | if( p_sps->log2_max_poc_lsb > 12 ) 124 | p_sps->log2_max_poc_lsb = 12; 125 | } 126 | else if( p_sps->poc_type/*p_sys->i_pic_order_cnt_type*/ == 1 ) 127 | { 128 | int i_cycle; 129 | /* skip b_delta_pic_order_always_zero */ 130 | p_sps->delta_pic_order_always_zero_flag/*->i_delta_pic_order_always_zero_flag*/ = bs_read( &s, 1 ); 131 | /* skip i_offset_for_non_ref_pic */ 132 | bs_read_se( &s ); 133 | /* skip i_offset_for_top_to_bottom_field */ 134 | bs_read_se( &s ); 135 | /* read i_num_ref_frames_in_poc_cycle */ 136 | i_cycle = bs_read_ue( &s ); 137 | if( i_cycle > 256 ) i_cycle = 256; 138 | while( i_cycle > 0 ) 139 | { 140 | /* skip i_offset_for_ref_frame */ 141 | bs_read_se(&s ); 142 | i_cycle--; 143 | } 144 | } 145 | /* i_num_ref_frames */ 146 | bs_read_ue( &s ); 147 | /* b_gaps_in_frame_num_value_allowed */ 148 | bs_skip( &s, 1 ); 149 | 150 | /* Read size */ 151 | p_sps->mb_width/*->fmt_out.video.i_width*/ = 16 * ( bs_read_ue( &s ) + 1 ); 152 | p_sps->mb_height/*fmt_out.video.i_height*/ = 16 * ( bs_read_ue( &s ) + 1 ); 153 | 154 | /* b_frame_mbs_only */ 155 | p_sps->frame_mbs_only_flag/*->b_frame_mbs_only*/ = bs_read( &s, 1 ); 156 | if( p_sps->frame_mbs_only_flag == 0 ) 157 | { 158 | bs_skip( &s, 1 ); 159 | } 160 | /* b_direct8x8_inference */ 161 | bs_skip( &s, 1 ); 162 | 163 | /* crop */ 164 | p_sps->crop = bs_read( &s, 1 ); 165 | if( p_sps->crop ) 166 | { 167 | /* left */ 168 | bs_read_ue( &s ); 169 | /* right */ 170 | bs_read_ue( &s ); 171 | /* top */ 172 | bs_read_ue( &s ); 173 | /* bottom */ 174 | bs_read_ue( &s ); 175 | } 176 | 177 | /* vui */ 178 | p_sps->vui_parameters_present_flag = bs_read( &s, 1 ); 179 | if( p_sps->vui_parameters_present_flag ) 180 | { 181 | int aspect_ratio_info_present_flag = bs_read( &s, 1 ); 182 | if( aspect_ratio_info_present_flag ) 183 | { 184 | static const struct { int num, den; } sar[17] = 185 | { 186 | { 0, 0 }, { 1, 1 }, { 12, 11 }, { 10, 11 }, 187 | { 16, 11 }, { 40, 33 }, { 24, 11 }, { 20, 11 }, 188 | { 32, 11 }, { 80, 33 }, { 18, 11 }, { 15, 11 }, 189 | { 64, 33 }, { 160,99 }, { 4, 3 }, { 3, 2 }, 190 | { 2, 1 }, 191 | }; 192 | 193 | int i_sar = bs_read( &s, 8 ); 194 | 195 | if( i_sar < 17 ) 196 | { 197 | p_sps->sar.num = sar[i_sar].num; 198 | p_sps->sar.den = sar[i_sar].den; 199 | } 200 | else if( i_sar == 255 ) 201 | { 202 | p_sps->sar.num = bs_read( &s, 16 ); 203 | p_sps->sar.den = bs_read( &s, 16 ); 204 | } 205 | else 206 | { 207 | p_sps->sar.num = 0; 208 | p_sps->sar.den = 0; 209 | } 210 | 211 | //if( den != 0 ) 212 | // p_dec->fmt_out.video.i_aspect = (int64_t)VOUT_ASPECT_FACTOR * 213 | // ( num * p_dec->fmt_out.video.i_width ) / 214 | // ( den * p_dec->fmt_out.video.i_height); 215 | //else 216 | // p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR; 217 | } 218 | else 219 | { 220 | p_sps->sar.num = 0; 221 | p_sps->sar.den = 0; 222 | } 223 | 224 | if(bs_read(&s, 1)) /* overscan_info_present_flag */ 225 | { 226 | bs_read(&s, 1); /* overscan_appropriate_flag */ 227 | } 228 | 229 | if(bs_read(&s, 1)) /* video_signal_type_present_flag */ 230 | { 231 | bs_read(&s, 3); /* video_format */ 232 | bs_read(&s, 1); /* video_full_range_flag */ 233 | 234 | if(bs_read(&s, 1)) /* colour_description_present_flag */ 235 | { 236 | bs_read(&s, 8); /* colour_primaries */ 237 | bs_read(&s, 8); /* transfer_characteristics */ 238 | bs_read(&s, 8); /* matrix_coefficients */ 239 | } 240 | } 241 | 242 | if(bs_read(&s, 1)) /* chroma_location_info_present_flag */ 243 | { 244 | bs_read_ue(&s); /* chroma_sample_location_type_top_field */ 245 | bs_read_ue(&s); /* chroma_sample_location_type_bottom_field */ 246 | } 247 | 248 | p_sps->timing_info_present_flag = bs_read(&s, 1); 249 | if(p_sps->timing_info_present_flag) 250 | { 251 | p_sps->num_units_in_tick = bs_read(&s, 32); 252 | p_sps->time_scale = bs_read(&s, 32); 253 | p_sps->fixed_frame_rate_flag = bs_read(&s, 1); 254 | } 255 | 256 | nal_hrd_parameters_present_flag = bs_read(&s, 1); 257 | if(nal_hrd_parameters_present_flag) 258 | h264_decode_hrd_parameters(s, p_sps); 259 | vcl_hrd_parameters_present_flag = bs_read(&s, 1); 260 | if(vcl_hrd_parameters_present_flag) 261 | h264_decode_hrd_parameters(s, p_sps); 262 | if(nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) 263 | bs_read(&s, 1); /* low_delay_hrd_flag */ 264 | bs_read(&s, 1); /* pic_struct_present_flag */ 265 | 266 | p_sps->bitstream_restriction_flag = bs_read(&s, 1); 267 | if(p_sps->bitstream_restriction_flag) 268 | { 269 | unsigned int num_reorder_frames; 270 | bs_read(&s, 1); /* motion_vectors_over_pic_boundaries_flag */ 271 | bs_read_ue(&s); /* max_bytes_per_pic_denom */ 272 | bs_read_ue(&s); /* max_bits_per_mb_denom */ 273 | bs_read_ue(&s); /* log2_max_mv_length_horizontal */ 274 | bs_read_ue(&s); /* log2_max_mv_length_vertical */ 275 | num_reorder_frames= bs_read_ue(&s); 276 | bs_read_ue(&s); /*max_dec_frame_buffering*/ 277 | 278 | if(num_reorder_frames > 16 /*max_dec_frame_buffering || max_dec_frame_buffering > 16*/){ 279 | printf("illegal num_reorder_frames %d\n", num_reorder_frames); 280 | return false; 281 | } 282 | 283 | p_sps->num_reorder_frames= num_reorder_frames; 284 | } 285 | } 286 | 287 | return true; 288 | } 289 | 290 | -------------------------------------------------------------------------------- /rtspsvr/mediasub.cpp: -------------------------------------------------------------------------------- 1 | #include "mediasub.h" 2 | #include "mediactrl.h" 3 | #include "rtsp.h" 4 | 5 | void InitRtpHeader(uint8 * header, uint8 payloadType, uint16 seqNO, 6 | uint time_stamp, uint ssrc, int market){ 7 | header[0] = 0x80; 8 | header[1] = payloadType; 9 | 10 | header[2] = (seqNO >> 8 )&0xff;; 11 | header[3] = seqNO & 0xff; 12 | 13 | header[4] = (uint8)(time_stamp >> 24 )&0xff; 14 | header[5] = (uint8)(time_stamp >> 16 )&0xff; 15 | header[6] = (uint8)(time_stamp >> 8 )&0xff; 16 | header[7] = (uint8)(time_stamp & 0xff); 17 | 18 | header[ 8] = (uint8)(ssrc >> 24 )&0xff; 19 | header[ 9] = (uint8)(ssrc >> 16 )&0xff; 20 | header[10] = (uint8)(ssrc >> 8 )&0xff; 21 | header[11] = (uint8)(ssrc & 0xff); 22 | 23 | if (market){ 24 | header[1] = (uint8)(header[1]|0x80); //set market bit 25 | } 26 | } 27 | 28 | void init_socket_pair(socket_pair & sp){ 29 | memset(&sp, 0, sizeof(sp)); 30 | sp.rtcp_socket = -1; 31 | sp.rtp_socket = -1; 32 | } 33 | 34 | void clear_socket_pair(socket_pair & sp){ 35 | if(sp.rtp_socket > 0){ 36 | close(sp.rtp_socket); 37 | sp.rtp_socket = -1; 38 | } 39 | 40 | if(sp.rtcp_socket > 0){ 41 | close(sp.rtcp_socket); 42 | sp.rtcp_socket = -1; 43 | } 44 | 45 | sp.rtcp_channel = NULL; 46 | } 47 | 48 | MediaSubSession::MediaSubSession(mediaCtrl * mc){ 49 | 50 | m_payLoadType = 96; 51 | m_seqNO = 0; 52 | m_proto = RTP_UDP; 53 | m_ssrc = random_32(); 54 | m_mediaCtrl = mc; 55 | m_timestamp = 0; 56 | init_socket_pair(m_socket_pair); 57 | } 58 | 59 | MediaSubSession::~MediaSubSession(){ 60 | 61 | printf("~MediaSubSession\n"); 62 | mediaCtrlHub::instance()->destoryMediaCtrl(m_mediaCtrl); 63 | clear_socket_pair(m_socket_pair); 64 | } 65 | 66 | int MediaSubSession::GetSdpLines(std::string & sdpLines){ 67 | return -1; 68 | } 69 | 70 | void MediaSubSession::SetTrackId(uint trackID){ 71 | append(m_trackIdStr, "track%d", trackID); 72 | } 73 | 74 | const std::string & MediaSubSession::GetTrackId(){ 75 | return m_trackIdStr; 76 | } 77 | 78 | void MediaSubSession::SetPayloadType(uint8 number){ 79 | m_payLoadType = 96 + number; 80 | } 81 | 82 | int MediaSubSession::GetUdpParam(uint clientRtpPort, 83 | uint clientRtcpPort, 84 | uint dstIp, 85 | uint & serverRtpPort, 86 | uint & serverRtcpPort){ 87 | 88 | m_proto = RTP_UDP; 89 | 90 | uint16 start_port = 3210 + random_32() % 60000; 91 | 92 | for (uint16 serverPort = start_port; serverPort < 65535; serverPort += 2){ 93 | 94 | int rtpfd = createUdpSocket(serverPort); 95 | if(rtpfd == -1){ 96 | continue; 97 | } 98 | 99 | int rtcpfd = createUdpSocket(serverPort + 1); 100 | if(rtcpfd == -1){ 101 | close(rtpfd); 102 | continue; 103 | } 104 | 105 | serverRtpPort = serverPort; 106 | serverRtcpPort = serverPort + 1; 107 | 108 | m_socket_pair.rtp_socket = rtpfd; 109 | m_socket_pair.rtcp_socket = rtcpfd; 110 | 111 | m_socket_pair.dst_rtpIp = dstIp; 112 | m_socket_pair.dst_rtpPort = clientRtpPort; 113 | 114 | m_socket_pair.dst_rtcpIp = dstIp; 115 | m_socket_pair.dst_rtcpPort = clientRtcpPort; 116 | break; 117 | } 118 | 119 | return 0; 120 | } 121 | 122 | int MediaSubSession::GetTcpParam(void * tcpConnection, 123 | uint8 rtpChannelId, uint8 rtcpChannelId, 124 | uint8 &dstTTL){ 125 | 126 | m_proto = RTP_TCP; 127 | m_socket_pair.tcp_connection = tcpConnection; 128 | m_socket_pair.rtp_channel = rtpChannelId; 129 | m_socket_pair.rtcp_channel = rtcpChannelId; 130 | 131 | printf("GetTcpParam rtpChannelId %d\n", rtpChannelId); 132 | return 0; 133 | } 134 | 135 | int MediaSubSession::SendPacket(uint8 * data, int len){ 136 | if(m_proto == RTP_UDP){ 137 | return SendRtpOverUdp(data, len); 138 | } 139 | else{ 140 | return SendRtpOverTcp(data, len); 141 | } 142 | } 143 | 144 | int MediaSubSession::SendRtpOverUdp(uint8 * data, int len){ 145 | 146 | sockaddr_in sin ; 147 | sin.sin_family = AF_INET; 148 | sin.sin_addr.s_addr = htonl(m_socket_pair.dst_rtpIp); 149 | sin.sin_port = htons(m_socket_pair.dst_rtpPort); 150 | 151 | int sent = sendto(m_socket_pair.rtp_socket, (char*)data, 152 | len, 0, (struct sockaddr*)&sin, sizeof(sin)); 153 | 154 | if(sent != len){ 155 | return -1; 156 | } 157 | return 0; 158 | } 159 | 160 | int MediaSubSession::SendRtpOverTcp(uint8 * data, int len){ 161 | 162 | int rtpSize = len - RTP_TCP_EXTRA_HEADER; 163 | data[0] = '$'; 164 | data[1] = m_socket_pair.rtp_channel; 165 | data[2] = (uint8) ((rtpSize & 0xFF00) >> 8); 166 | data[3] = (uint8) (rtpSize & 0xFF); 167 | 168 | RtspClientConnection * n = (RtspClientConnection *)m_socket_pair.tcp_connection; 169 | if(n->post_send((char*)data, len) < 0){ 170 | return -1; 171 | } 172 | 173 | return 0; 174 | } 175 | 176 | 177 | int MediaSubSession::PauseStream(){ 178 | return 0; 179 | } 180 | 181 | int MediaSubSession::StartStream(ITimerTask* task){ 182 | 183 | m_mediaCtrl->Prepare(); 184 | m_timestamp = 0; 185 | return m_mediaCtrl->StartPlay(this, task); 186 | } 187 | 188 | int MediaSubSession::SeekStream(){ 189 | return 0; 190 | } 191 | 192 | int MediaSubSession::StopStream(){ 193 | 194 | m_mediaCtrl->Close(); 195 | m_timestamp = 0; 196 | return m_mediaCtrl->StopPlay(this); 197 | } 198 | 199 | uint MediaSubSession::RtpTimestamp(){ 200 | return m_timestamp; 201 | } 202 | 203 | uint MediaSubSession::SeqNo(){ 204 | return m_seqNO; 205 | } 206 | 207 | 208 | 209 | /*--------------------------------------- 210 | * 211 | * 212 | *-------------------------------------*/ 213 | H264MediaSubSession::H264MediaSubSession(mediaCtrl * mc) 214 | :MediaSubSession(mc){ 215 | 216 | } 217 | 218 | H264MediaSubSession::~H264MediaSubSession(){ 219 | } 220 | 221 | int H264MediaSubSession::GetSdpLines(std::string & sdpLines){ 222 | 223 | if(m_mediaCtrl->Prepare() < 0){ 224 | return -1; 225 | } 226 | 227 | std::string mediaSdp; 228 | if(m_mediaCtrl->getSdp(mediaSdp) < 0){ 229 | return -1; 230 | } 231 | m_mediaCtrl->setPayloadType(m_payLoadType); 232 | int estBitrate = 500; 233 | 234 | append(sdpLines, 235 | "m=video 0 RTP/AVP %u\r\n" 236 | "b=AS:%u\r\n" // b=AS: 237 | "c=IN IP4 0.0.0.0\r\n" 238 | "%s" 239 | "a=control:%s\r\n\r\n", 240 | m_payLoadType, 241 | estBitrate, 242 | mediaSdp.c_str(), 243 | GetTrackId().c_str()); 244 | return 0; 245 | } 246 | 247 | int H264MediaSubSession::TransferStream(uint8 * data, int len, bool end_of_frame){ 248 | 249 | uint8 sendbuf[RTP_MTU + 64]; 250 | int offset = m_proto == RTP_UDP ? 0: RTP_TCP_EXTRA_HEADER; 251 | uint8 * rtp_buf = sendbuf + offset; 252 | 253 | int packCount = len / RTP_MTU; 254 | int lastBytes = len % RTP_MTU; 255 | 256 | if(lastBytes){ 257 | packCount++; 258 | } 259 | else{ 260 | lastBytes = RTP_MTU; 261 | } 262 | 263 | uint timestamp = m_timestamp; 264 | if (end_of_frame){ 265 | m_timestamp += m_mediaCtrl->Timestamp_Inc(); 266 | } 267 | 268 | sockaddr_in sin ; 269 | sin.sin_family = AF_INET; 270 | sin.sin_addr.s_addr = htonl(m_socket_pair.dst_rtpIp); 271 | sin.sin_port = htons(m_socket_pair.dst_rtpPort); 272 | 273 | if (packCount == 1){ 274 | InitRtpHeader(rtp_buf, m_payLoadType, m_seqNO++, timestamp, m_ssrc, end_of_frame); 275 | memcpy(rtp_buf + 12, data, len); 276 | return SendPacket(sendbuf, len + 12 + offset); 277 | } 278 | 279 | int s = 1, e = 0, m = 0, bytes = 0; 280 | int nal_type = data[0]; 281 | 282 | for (int k = 0; k < packCount; k++){ 283 | 284 | bytes = RTP_MTU; 285 | // FU indicator F|NRI|Type 286 | if (k + 1 == packCount){ 287 | s = 0; 288 | e = 1; 289 | m = 1; 290 | bytes = lastBytes - 1; //skip naul_header 291 | } 292 | 293 | InitRtpHeader(rtp_buf, m_payLoadType, m_seqNO++, timestamp, m_ssrc, m); 294 | rtp_buf[12] = (nal_type & 0xe0 ) | 28 ; 295 | rtp_buf[13] = (s << 7)|(e << 6)|(nal_type & 0x1f); 296 | 297 | s = e = m = 0; 298 | memcpy(rtp_buf + 14, data + k * RTP_MTU + 1, bytes); 299 | if(SendPacket(sendbuf, bytes + 14 + offset) < 0){ 300 | return -1; 301 | } 302 | } 303 | 304 | return 0; 305 | } 306 | 307 | 308 | 309 | /*--------------------------------------- 310 | * 311 | * 312 | *-------------------------------------*/ 313 | Mp4AMediaSubSession::Mp4AMediaSubSession(mediaCtrl * mc) 314 | :MediaSubSession(mc){ 315 | } 316 | 317 | Mp4AMediaSubSession::~Mp4AMediaSubSession(){ 318 | } 319 | 320 | int Mp4AMediaSubSession::GetSdpLines(std::string & sdpLines){ 321 | if(m_mediaCtrl->Prepare() < 0){ 322 | return -1; 323 | } 324 | 325 | std::string mediaSdp; 326 | if(m_mediaCtrl->getSdp(mediaSdp) < 0){ 327 | return -1; 328 | } 329 | 330 | int estBitrate = 96; 331 | m_mediaCtrl->setPayloadType(m_payLoadType); 332 | append(sdpLines, 333 | "m=audio 0 RTP/AVP %u\r\n" 334 | "b=AS:%u\r\n" // b=AS: 335 | "c=IN IP4 0.0.0.0\r\n" 336 | "%s" 337 | "a=control:%s\r\n\r\n", 338 | m_payLoadType, 339 | estBitrate, 340 | mediaSdp.c_str(), 341 | GetTrackId().c_str()); 342 | return -1; 343 | } 344 | 345 | 346 | int Mp4AMediaSubSession::TransferStream(uint8 * data, int len, bool end_of_frame){ 347 | 348 | int offset = m_proto == RTP_UDP ? 0: RTP_TCP_EXTRA_HEADER; 349 | uint8 sendbuf[RTP_MTU + 64]; 350 | 351 | uint8 * rtp_buf = sendbuf + offset; 352 | uint8 * pos = data; 353 | 354 | while(len > 0){ 355 | 356 | int payload_size = len <= RTP_MTU ? len : RTP_MTU; 357 | int m = len <= RTP_MTU ? 1: 0; 358 | InitRtpHeader(rtp_buf, m_payLoadType, m_seqNO++, m_timestamp, m_ssrc, m); 359 | rtp_buf[12] = 0; 360 | rtp_buf[13] = 16; 361 | rtp_buf[14] = (uint8)(payload_size >> 5); // for each AU length 13 bits + idx 3bits 362 | rtp_buf[15] = (uint8)((payload_size & 0xff) << 3); 363 | 364 | len -= payload_size; 365 | memcpy(rtp_buf + 16, pos, payload_size); 366 | pos += payload_size; 367 | SendPacket(sendbuf, payload_size + 16 + offset); 368 | } 369 | 370 | m_timestamp += m_mediaCtrl->Timestamp_Inc(); 371 | return 0; 372 | } 373 | 374 | -------------------------------------------------------------------------------- /rtspsvr/mediasource.cpp: -------------------------------------------------------------------------------- 1 | #include "mediasource.h" 2 | #define next_24bit(ptr) (((ptr)[0]<<16)|((ptr)[1]<<8)|(ptr)[2]) 3 | 4 | 5 | 6 | mediaSource::mediaSource(const std::string & streamName){ 7 | m_streamName = streamName; 8 | } 9 | 10 | mediaSource::~mediaSource(){ 11 | 12 | } 13 | 14 | const std::string & mediaSource::GetstreamName(){ 15 | return m_streamName; 16 | } 17 | 18 | void init_framebuffer(framebuffer & fb, int size){ 19 | 20 | fb.buf = new uint8[size]; 21 | fb.len = size; 22 | fb.rpos = fb.wpos = 0; 23 | } 24 | 25 | void del_framebuffer(framebuffer & fb){ 26 | if (fb.buf && fb.len){ 27 | delete fb.buf; 28 | fb.buf = 0; 29 | fb.len = 0; 30 | } 31 | fb.rpos = fb.wpos = 0; 32 | } 33 | 34 | ///////////////////////////////////////////////////////////// 35 | h264FileSource::h264FileSource(const std::string & fileName): 36 | mediaSource(fileName){ 37 | m_fFid = NULL; 38 | init_framebuffer(m_frameBuf, MaxBufSize); 39 | m_frameRate = 25.0f; 40 | m_payloadType = 96; 41 | m_profile_level_id = 0; 42 | } 43 | 44 | h264FileSource::~h264FileSource(){ 45 | del_framebuffer(m_frameBuf); 46 | closeMedia(); 47 | } 48 | 49 | bool isAccessUnitStart(uint8 nal_unit_type){ 50 | return (nal_unit_type >= 6 && nal_unit_type <= 9) || 51 | (nal_unit_type >= 14 && nal_unit_type <= 18); 52 | } 53 | 54 | bool isEof(uint8 nal_unit_type){ 55 | return (nal_unit_type == 10 || nal_unit_type == 11); 56 | } 57 | 58 | bool isVCL(uint8 nal_unit_type){ 59 | return (nal_unit_type <= 5 && nal_unit_type > 0); 60 | } 61 | 62 | int h264FileSource::get_naul(uchar ** payload, int & payload_size){ 63 | 64 | int consume = 0; 65 | int has = m_frameBuf.wpos - m_frameBuf.rpos; 66 | uint8 * data = m_frameBuf.buf + m_frameBuf.rpos; 67 | 68 | int ret = h264_split_nal(data, has, payload, payload_size, consume); 69 | if (ret < 0){ 70 | //naul too big 71 | if(has == m_frameBuf.len){ 72 | return -1; 73 | } 74 | 75 | if(has){ 76 | memmove(m_frameBuf.buf, data, has); 77 | } 78 | 79 | m_frameBuf.rpos = 0; 80 | m_frameBuf.wpos = has; 81 | //read more 82 | if (!feof(m_fFid)){ 83 | int nread = fread(m_frameBuf.buf + m_frameBuf.wpos, 84 | 1, m_frameBuf.len - m_frameBuf.wpos, m_fFid); 85 | if (!nread){ 86 | return -1; 87 | } 88 | m_frameBuf.wpos += nread; 89 | } 90 | else{ 91 | return -1; 92 | } 93 | 94 | //try again 95 | ret = h264_split_nal(m_frameBuf.buf, m_frameBuf.wpos, payload, payload_size, consume); 96 | if (ret < 0){ 97 | return -1; 98 | } 99 | } 100 | 101 | m_frameBuf.rpos += consume; 102 | 103 | return 0; 104 | } 105 | 106 | int h264FileSource::get_next_naul_bytes(uint8 * buf, int bytes){ 107 | 108 | 109 | uint8 * data = m_frameBuf.buf + m_frameBuf.rpos; 110 | int has = m_frameBuf.wpos - m_frameBuf.rpos; 111 | 112 | if(has < 4 + bytes){ 113 | 114 | memmove(m_frameBuf.buf, data, has); 115 | m_frameBuf.rpos = 0; 116 | m_frameBuf.wpos = has; 117 | 118 | if (!feof(m_fFid)){ 119 | int nread = fread(m_frameBuf.buf + m_frameBuf.wpos, 120 | 1, m_frameBuf.len - m_frameBuf.wpos, m_fFid); 121 | if (!nread){ 122 | return -1; 123 | } 124 | m_frameBuf.wpos += nread; 125 | } 126 | else{ 127 | return -1; 128 | } 129 | 130 | if(has < 4 + bytes){ 131 | return -1; 132 | } 133 | 134 | data = m_frameBuf.buf ; 135 | } 136 | 137 | if(next_24bit(data)){ 138 | memcpy(buf, data + 3, bytes); 139 | } 140 | else if(next_24bit(data + 1)){ 141 | memcpy(buf, data + 4, bytes); 142 | } 143 | else{ 144 | error_log("parse buffer fail"); 145 | return -1; 146 | } 147 | 148 | return 0; 149 | } 150 | 151 | //RTP 1460 + rtp header 152 | int h264FileSource::NextFrame(uint8 ** payload, int & payload_size, bool & access_unit_end){ 153 | 154 | if (!m_fFid){ 155 | return -1; 156 | } 157 | 158 | access_unit_end = false; 159 | *payload = NULL; 160 | payload_size = 0; 161 | 162 | if(get_naul(payload, payload_size) < 0){ 163 | access_unit_end = true; 164 | return -1; 165 | } 166 | 167 | uint8 nal_unit_type = (*payload)[0] & 0x1f; 168 | 169 | //access_unit_start 170 | if(isAccessUnitStart(nal_unit_type)){ 171 | access_unit_end = false; 172 | } 173 | //access_unit_end 174 | else if(isEof(nal_unit_type )){ 175 | printf("eof %d\n", nal_unit_type); 176 | access_unit_end = true; 177 | } 178 | else{ 179 | 180 | // We need to check the *next* NAL unit to figure out whether 181 | // the current NAL unit ends an 'access unit': 182 | uint8 next_naul_header[2] = {0}; 183 | if(get_next_naul_bytes(next_naul_header, sizeof(next_naul_header)) < 0){ 184 | access_unit_end = true; 185 | printf("get_next_naul_bytes fail \n"); 186 | } 187 | else{ 188 | uint8 next_nal_unit_type = next_naul_header[0] & 0x1f; 189 | //printf("next_nal_unit_type %d \n", next_nal_unit_type); 190 | 191 | //VCL type 192 | if(isVCL(next_nal_unit_type)){ 193 | access_unit_end = (next_naul_header[1] &0x80) != 0; 194 | // printf("isVCL %d \n", next_nal_unit_type); 195 | } 196 | else if(isAccessUnitStart(next_nal_unit_type)){ 197 | // printf("next isAccessUnitStart %d \n", next_nal_unit_type); 198 | access_unit_end = true; 199 | } 200 | else{ 201 | access_unit_end = false; 202 | } 203 | } 204 | } 205 | 206 | 207 | return 0; 208 | } 209 | 210 | int h264FileSource::parseMedia(){ 211 | 212 | if (!m_fFid){ 213 | m_fFid = fopen(m_streamName.c_str(), "rb"); 214 | } 215 | 216 | if (!m_fFid){ 217 | return -1; 218 | } 219 | 220 | uint8 *data = NULL; 221 | int nsize = 0; 222 | int findsps = 0, findpps = 0; 223 | m_profile_level_id = 0; 224 | 225 | memset(&m_sps, 0, sizeof(m_sps)); 226 | 227 | int ret = -1; 228 | while(!get_naul(&data, nsize)){ 229 | 230 | uint8* nal_data = data; 231 | int nal_size = nsize; 232 | uint8 nal_type = nal_data[0] & 0x1f; 233 | 234 | if (nal_type == 7 && !findsps){//sps 235 | findsps = 1; 236 | if (nsize >= 4){ 237 | m_profile_level_id = (nal_data[1]<<16)|(nal_data[2]<<8)|nal_data[3]; 238 | } 239 | Base64Encode(nal_data, nal_size, m_sps_base64); 240 | 241 | uint8 * sps_buf = new uint8[nal_size]; 242 | int sps_size = 0; 243 | h264_decode_annexb(sps_buf,&sps_size, nal_data, nal_size); 244 | h264_decode_seq_parameter_set(sps_buf, sps_size, &m_sps); 245 | if(m_sps.num_units_in_tick && m_sps.time_scale){ 246 | m_frameRate = (float)m_sps.time_scale / (2 * m_sps.num_units_in_tick); 247 | } 248 | delete[] sps_buf; 249 | } 250 | if (nal_type == 8 && !findpps){//pps 251 | findpps = 1; 252 | Base64Encode(nal_data, nal_size, m_pps_base64); 253 | } 254 | if (findpps && findsps){ 255 | ret = 0; 256 | break; 257 | } 258 | } 259 | 260 | m_frameBuf.rpos = m_frameBuf.wpos = 0; 261 | fseek(m_fFid, 0, SEEK_SET); 262 | return ret; 263 | } 264 | 265 | int h264FileSource::getSdp(std::string & sdpLines){ 266 | 267 | append(sdpLines, 268 | "a=framerate:%.2f\r\n" //for mplayer need this 269 | "a=rtpmap:%u H264/90000\r\n" 270 | "a=fmtp:%u packetization-mode=1" 271 | ";profile-level-id=%06X" 272 | ";sprop-parameter-sets=%s,%s\r\n", 273 | m_frameRate, 274 | m_payloadType, 275 | m_payloadType, 276 | m_profile_level_id, 277 | m_sps_base64.c_str(), 278 | m_pps_base64.c_str()); 279 | return 0; 280 | } 281 | 282 | uint h264FileSource::Timestamp_Inc(){ 283 | return (uint)(0.5 + 90000.0 / m_frameRate); 284 | } 285 | 286 | uint h264FileSource::uDuration(){ 287 | return (uint)(1000 * 1000/ m_frameRate); 288 | } 289 | 290 | void h264FileSource::SetPayloadType(uint type){ 291 | m_payloadType = type; 292 | } 293 | 294 | int h264FileSource::closeMedia(){ 295 | if(m_fFid){ 296 | fclose(m_fFid); 297 | m_fFid = NULL; 298 | } 299 | return 0; 300 | } 301 | 302 | void h264FileSource::h264_decode_annexb(uint8 *dst, int *dstlen, const uint8 *src, const int srclen){ 303 | uint8 *dst_sav = dst; 304 | const uint8 *end = &src[srclen]; 305 | while (src < end){ 306 | if (src < end - 3 && src[0] == 0x00 && src[1] == 0x00 && 307 | src[2] == 0x03){ 308 | *dst++ = 0x00; 309 | *dst++ = 0x00; 310 | src += 3; 311 | continue; 312 | } 313 | *dst++ = *src++; 314 | } 315 | *dstlen = dst - dst_sav; 316 | } 317 | 318 | int h264FileSource::h264_split_nal(uint8 * p_data, uint buf_size, uint8 **payload, int & payload_size, int & consume){ 319 | 320 | uint first_pos = 0; 321 | uint second_pos = 0; 322 | uint start_code = 0; 323 | payload_size = 0; 324 | consume = 0; 325 | /* Split nal units */ 326 | while(second_pos + 4 < buf_size ){ 327 | if (next_24bit(p_data + second_pos) == 0x000001){ 328 | if (start_code){ 329 | payload_size = second_pos - first_pos; 330 | if(!p_data[second_pos - 1])payload_size--; 331 | *payload = p_data + first_pos; 332 | consume = first_pos + payload_size; 333 | return 0; 334 | } 335 | first_pos = second_pos + 3;//skip startcode 336 | start_code = 1; 337 | second_pos += 4; 338 | } 339 | else{ 340 | second_pos++; 341 | } 342 | } 343 | return -1; 344 | } 345 | ////////////////////////////////////////////////// 346 | 347 | aacFileSource::aacFileSource(const std::string & fileName): 348 | mediaSource(fileName){ 349 | m_fFid = NULL; 350 | m_samplingFrequency = 0; 351 | m_channels = 0; 352 | m_payloadType = 96; 353 | m_cfg0 = 0; 354 | m_cfg1 = 0; 355 | init_framebuffer(m_frameBuf, MaxBufSize); 356 | 357 | } 358 | 359 | 360 | aacFileSource:: ~aacFileSource(){ 361 | del_framebuffer(m_frameBuf); 362 | closeMedia(); 363 | } 364 | 365 | void aacFileSource::SetPayloadType(uint type){ 366 | m_payloadType = type; 367 | } 368 | 369 | int aacFileSource::closeMedia(){ 370 | del_framebuffer(m_frameBuf); 371 | if(m_fFid){ 372 | fclose(m_fFid); 373 | m_fFid = NULL; 374 | } 375 | return 0; 376 | } 377 | 378 | int aacFileSource::getSdp(std::string & sdpLines){ 379 | append(sdpLines, 380 | "a=rtpmap:%u MPEG4-GENERIC/%u/%u\r\n" 381 | "a=fmtp:%d streamtype=5;profile-level-id=1;" 382 | "mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;" 383 | "config=%02X%02x\r\n", 384 | m_payloadType, 385 | m_samplingFrequency, 386 | m_channels, 387 | m_payloadType, 388 | m_cfg0, 389 | m_cfg1); 390 | return 0; 391 | } 392 | 393 | int aacFileSource::parseMedia(){ 394 | 395 | if (!m_fFid){ 396 | m_fFid = fopen(m_streamName.c_str(), "rb"); 397 | } 398 | 399 | if (!m_fFid){ 400 | return -1; 401 | } 402 | 403 | static uint const samplingFrequencyTable[16] = { 404 | 96000, 88200, 64000, 48000, 405 | 44100, 32000, 24000, 22050, 406 | 16000, 12000, 11025, 8000, 407 | 7350, 0, 0, 0 408 | }; 409 | 410 | // Now, having opened the input file, read the fixed header of the first frame, 411 | // to get the audio stream's parameters: 412 | uint8 fixedHeader[4]; // it's actually 3.5 bytes long 413 | if (fread(fixedHeader, 1, sizeof(fixedHeader), m_fFid) < sizeof(fixedHeader)){ 414 | return -1; 415 | } 416 | fseek(m_fFid, 0, SEEK_SET); 417 | 418 | // Check the 'syncword': 419 | if (!(fixedHeader[0] == 0xFF && (fixedHeader[1]&0xF0) == 0xF0)) { 420 | //Bad 'syncword' at start of ADTS file 421 | return -1; 422 | } 423 | 424 | // Get and check the 'profile': 425 | uint8 profile = (fixedHeader[2]&0xC0)>>6; // 2 bits 426 | if (profile == 3) { 427 | //Bad (reserved) 'profile': 3 in first frame of ADTS file 428 | return -1; 429 | } 430 | 431 | uint8 sampling_frequency_index = (fixedHeader[2]&0x3C)>>2; // 4 bits 432 | if (samplingFrequencyTable[sampling_frequency_index] == 0) { 433 | //"Bad 'sampling_frequency_index' in first frame of ADTS file" 434 | return -1; 435 | } 436 | 437 | // Get and check the 'channel_configuration': 438 | uint8 channel_configuration = ((fixedHeader[2]&0x01)<<2)|((fixedHeader[3]&0xC0)>>6); // 3 bits 439 | 440 | 441 | // If we get here, the frame header was OK. 442 | // Reset the fid to the beginning of the file: 443 | // SeekFile64(m_fFid, SEEK_SET, 0); 444 | 445 | m_samplingFrequency = samplingFrequencyTable[sampling_frequency_index]; 446 | 447 | m_channels = channel_configuration ? channel_configuration : 2; 448 | 449 | // Construct the 'AudioSpecificConfig', and from it, the corresponding ASCII string: 450 | uint8 const audioObjectType = profile + 1; 451 | 452 | m_cfg0 = (audioObjectType<<3) | (sampling_frequency_index>>1); 453 | m_cfg1 = (sampling_frequency_index<<7) | (channel_configuration<<3); 454 | return 0; 455 | } 456 | 457 | 458 | int aacFileSource::NextFrame(uint8 ** payload, int & payload_size, bool & end_of_frame){ 459 | 460 | // Begin by reading the 7-byte fixed_variable headers: 461 | *payload = NULL; 462 | payload_size = 0; 463 | end_of_frame = true; 464 | 465 | if (!m_fFid){ 466 | return -1; 467 | } 468 | 469 | int consume = 0; 470 | int has = m_frameBuf.wpos - m_frameBuf.rpos; 471 | uint8 * data = m_frameBuf.buf + m_frameBuf.rpos; 472 | int ret = get_frame(data, has, payload, payload_size, consume); 473 | 474 | if(!ret){ 475 | m_frameBuf.rpos += consume; 476 | return 0; 477 | } 478 | 479 | memmove(m_frameBuf.buf, data, has); 480 | m_frameBuf.rpos = 0; 481 | m_frameBuf.wpos = has; 482 | 483 | if (!feof(m_fFid)){ 484 | int nread = fread(m_frameBuf.buf,1, m_frameBuf.len - has, m_fFid); 485 | if (nread < 0){ 486 | return -1; 487 | } 488 | m_frameBuf.wpos += nread; 489 | } 490 | else{ 491 | return -1; 492 | } 493 | 494 | has = m_frameBuf.wpos; 495 | data = m_frameBuf.buf; 496 | ret = get_frame(data, has, payload, payload_size, consume); 497 | if (ret < 0){ 498 | return -1; 499 | } 500 | m_frameBuf.rpos += consume; 501 | 502 | return 0; 503 | } 504 | 505 | int aacFileSource::get_frame(uint8 * p_data, uint buf_size, uint8 ** payload, int & payload_size, int &consume){ 506 | 507 | if (buf_size < 7){ 508 | return -1; 509 | } 510 | 511 | uint8 * headers = (uint8*)p_data; 512 | 513 | bool protection_absent = headers[1]&0x01; 514 | 515 | uint16 frame_length 516 | = ((headers[3]&0x03)<<11) | (headers[4]<<3) | ((headers[5]&0xE0)>>5); 517 | 518 | uint numBytesToRead = frame_length > 7 ? frame_length - 7 : 0; 519 | 520 | // If there's a 'crc_check' field, skip it: 521 | int crc_check = 0; 522 | if (!protection_absent) { 523 | crc_check = 2; 524 | numBytesToRead = numBytesToRead > 2 ? numBytesToRead - 2 : 0; 525 | } 526 | 527 | if (buf_size < crc_check + 7 + numBytesToRead){ 528 | return -1; 529 | } 530 | 531 | *payload = p_data + crc_check + 7; 532 | payload_size = numBytesToRead; 533 | consume = crc_check + 7 + numBytesToRead; 534 | 535 | return 0; 536 | 537 | } 538 | 539 | //for aac 1024 samples 540 | uint aacFileSource::Timestamp_Inc(){ 541 | return 1024; 542 | } 543 | 544 | uint aacFileSource::uDuration(){ 545 | return (1000 * 1000 * 1024 / m_samplingFrequency); 546 | } 547 | -------------------------------------------------------------------------------- /rtspsvr/rtsp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "watcher.h" 5 | #include "rtsp.h" 6 | 7 | std::string dateStr(){ 8 | char buf[64] = {0}; 9 | time_t tt = time(NULL); 10 | strftime(buf, sizeof(buf), "Date: %a, %b %d %Y %H:%M:%S GMT\r\n", gmtime(&tt)); 11 | return buf; 12 | } 13 | 14 | int ParseRTSPRequestString(std::string requst, 15 | std::string & cmd, 16 | std::string & urlPreSuffix, 17 | std::string & urlSuffix, 18 | std::string & cseq, 19 | std::string & sessionId){ 20 | //CMD rtsp://192.168.20.136:5000/xxx666 RTSP/1.0 21 | //DESCRIBE rtsp://wm.microsoft.com/ms/video/0001-hi.wmv RTSP/1.0 22 | 23 | size_type npos = std::string::npos; 24 | 25 | size_type pos = requst.find(' '); 26 | if(npos == pos){ 27 | return -1; 28 | } 29 | cmd = requst.substr(0, pos);//DESCRIBE 30 | 31 | 32 | size_type rtspok = requst.find(" RTSP/", pos + 1); 33 | if(npos == rtspok){ 34 | return -1; 35 | } 36 | 37 | 38 | //rtsp://wm.microsoft.com/ms/video/0001-hi.wmv 39 | std::string url = requst.substr(pos + 1, rtspok - pos - 1); 40 | 41 | pos = url.find("rtsp://"); 42 | if(npos == pos){ 43 | return -1; 44 | } 45 | 46 | //first space or slash after "host" or "host:port" 47 | size_type i = url.find('/', pos + 7); 48 | 49 | //k: last non-space before "RTSP/" 50 | size_type k = url.length(); 51 | 52 | //k1: last slash in the range [i,k] 53 | size_type k1 = url.rfind('/'); 54 | 55 | // [k1+1,k] 0001-hi.wmv 56 | if (i != npos && k > k1 + 1){ 57 | urlSuffix = url.substr(k1 + 1, k - k1 -1); 58 | } 59 | 60 | //[i+1, k1) ms/video 61 | if (i != npos && k1 > i + 1){ 62 | urlPreSuffix = url.substr(i +1, k1 - i -1); 63 | } 64 | 65 | //get cseq 66 | pos = requst.find("CSeq:", rtspok); 67 | if(npos == pos){ 68 | return -1; 69 | } 70 | pos += 5; 71 | while(requst[++pos] == ' '); 72 | size_type spos = requst.find("\r\n", pos); 73 | if(npos == spos){ 74 | return 0; 75 | } 76 | cseq = requst.substr(pos, spos - pos); 77 | 78 | 79 | //get Session id 80 | pos = requst.find("Session:", pos); 81 | if(npos == pos){ 82 | return 0; 83 | } 84 | pos += 7; 85 | while(requst[++pos] == ' '); 86 | spos = requst.find("\r\n", pos); 87 | if(npos == spos){ 88 | return 0; 89 | } 90 | sessionId = requst.substr(pos, spos - pos); 91 | //get Content-Length: need add 92 | 93 | return 0; 94 | } 95 | 96 | int parseTransportHeader(std::string & fullRequestStr, 97 | int &mode, 98 | std::string & destAddrStr, 99 | uchar & dstTTL, 100 | uint &clientRtpPort, uint &clientRtcpPort, //if udp 101 | uchar & rtpChannel, uchar& rtcpChannel //if tcp 102 | ){ 103 | mode = RTP_UDP; 104 | dstTTL = 255; 105 | clientRtpPort = 0; 106 | clientRtcpPort = 0; 107 | rtpChannel = rtcpChannel = 0Xff; 108 | 109 | uint16 p1 = 0, p2 = 0; 110 | uint ttl = 0, rtpId = 0, rtcpId =0; 111 | 112 | size_type pos = 0; 113 | size_type end = fullRequestStr.length() - (size_type)4; // /r/n/r/n 114 | 115 | size_type npos = std::string::npos; 116 | size_type t = fullRequestStr.find("Transport:"); 117 | if (t == npos){ 118 | error_log("no Transport\n"); 119 | return -1; 120 | } 121 | t += 9; 122 | while(fullRequestStr[++t] == ' '); 123 | std::string strParse = fullRequestStr.substr(t, fullRequestStr.length() - t); 124 | 125 | do 126 | { 127 | pos = fullRequestStr.find(';', t); 128 | if (pos == npos){ 129 | pos = end; 130 | } 131 | 132 | std::string str = fullRequestStr.substr(t, pos - t); 133 | t = pos + 1; 134 | 135 | if (str == "RTP/AVP/TCP") { 136 | mode = RTP_TCP; 137 | } 138 | else if (str == "RAW/RAW/UDP" || str == "MP2T/H2221/UDP"){ 139 | return -1; 140 | } 141 | else if (str.find("destination=") != npos){ 142 | destAddrStr = str.substr(12); 143 | } 144 | else if (sscanf(str.c_str(), "ttl%d", &ttl) == 1){ 145 | dstTTL = (int)ttl; 146 | } 147 | else if (sscanf(str.c_str(), "client_port=%hu-%hu", &p1, &p2) == 2) 148 | { 149 | clientRtpPort = p1; 150 | clientRtcpPort = mode == RAW_UDP ? 0 : p2; 151 | } 152 | else if (sscanf(str.c_str(), "client_port=%hu", &p1) == 1) 153 | { 154 | clientRtpPort = p1; 155 | clientRtcpPort = mode == RAW_UDP ? 0 : (p1 + 1); 156 | } 157 | else if (sscanf(str.c_str(), "interleaved=%u-%u", &rtpId, &rtcpId) == 2) 158 | { 159 | rtpChannel = rtpId; 160 | rtcpChannel = rtcpId; //�����ŵ���Ϊ�����ŵ� 161 | } 162 | 163 | }while(pos != end); 164 | 165 | return 0; 166 | } 167 | 168 | int parseRange(std::string & fullRequestStr, 169 | std::string & absStart, 170 | std::string & absEnd, 171 | double & startTime, 172 | double & endTime){ 173 | //parse range 174 | size_type k = fullRequestStr.find("Range: "); 175 | 176 | if(k == std::string::npos){ 177 | return -1; 178 | } 179 | k += 6; 180 | 181 | //remove space 182 | while(fullRequestStr[++k] == ' '); 183 | 184 | const char * paramStr = fullRequestStr.c_str() + k; 185 | 186 | int numCharsMatched = 0; 187 | char as[32] = {0}, ae[32] = {0}; 188 | 189 | 190 | if(sscanf(paramStr, "npt = %lf - %lf", &startTime, &endTime) == 2){ 191 | } 192 | else if (sscanf(paramStr, "npt = %lf -", &startTime) == 1){ 193 | if (startTime < 0){ 194 | endTime = - startTime; 195 | startTime = 0.0; 196 | } 197 | else{ 198 | endTime = 0.0; 199 | } 200 | } 201 | else if (fullRequestStr.find("npt=now-") != std::string::npos){ 202 | startTime = endTime = 0.0; 203 | } 204 | else if (sscanf(paramStr, "clock = %n", &numCharsMatched) == 0 && numCharsMatched > 0){ 205 | startTime = endTime = 0.0; 206 | sscanf(¶mStr[numCharsMatched], "%[^-]-%s", as, ae); 207 | absStart = as; 208 | absEnd = ae; 209 | } 210 | else if (sscanf(paramStr, "smtpe = %n", &numCharsMatched) == 0 && numCharsMatched > 0){ 211 | // not interpret 212 | } 213 | else{ 214 | return -1; 215 | } 216 | 217 | return 0; 218 | } 219 | 220 | 221 | rtsp::rtsp(){ 222 | 223 | } 224 | 225 | rtsp::~rtsp(){ 226 | std::map::iterator it = m_mediaSessionMap.begin(); 227 | for(; it != m_mediaSessionMap.end(); it++){ 228 | delete it->second; 229 | } 230 | m_mediaSessionMap.clear(); 231 | } 232 | 233 | int rtsp::on_initialize(){ 234 | return 0; 235 | } 236 | 237 | int rtsp::on_connect(connection * n){ 238 | return 0; 239 | } 240 | 241 | int rtsp::on_accept(connection * n){ 242 | 243 | RtspClientConnection * session = new RtspClientConnection(n, this); 244 | n->set_context((void*)session); 245 | return 0; 246 | } 247 | 248 | int rtsp::on_unpack(char * data, int len, int& packetlen, char *&packet){ 249 | 250 | if (data[0] != '$'){ 251 | char * flag = strstr(data, "\r\n\r\n"); 252 | if(flag){ 253 | packet = data; 254 | packetlen = flag - data + 4; 255 | return packetlen; 256 | } 257 | else{ 258 | return 0; 259 | } 260 | } 261 | else{ 262 | 263 | if(len < 4){ 264 | return 0; 265 | } 266 | 267 | //uint rtpChannel = data[1]; 268 | int rtpTotalLen = (data[2]<<8) | data[3]; 269 | if (len < rtpTotalLen + 4){ 270 | return 0; 271 | } 272 | else{ 273 | packet = data; 274 | packetlen = rtpTotalLen; 275 | return rtpTotalLen; 276 | } 277 | } 278 | } 279 | 280 | //add 2014-7-11 281 | int rtsp::on_recv(connection * n, char * data, int len){ 282 | 283 | if (data[0] != '$'){ 284 | rtsp_msg(n, data, len); 285 | } 286 | else{ 287 | rtp_msg(n, data, len); 288 | } 289 | return 0; 290 | } 291 | 292 | int rtsp::rtp_msg(connection * n, char * data, int len){ 293 | return 0; 294 | } 295 | 296 | int rtsp::rtsp_msg(connection * n, char * data, int len){ 297 | 298 | RtspClientConnection * clientConnection = (RtspClientConnection*)n->get_context(); 299 | std::string cmd; 300 | std::string urlPreSuffix; 301 | std::string urlSuffix; 302 | std::string strSessionId; 303 | std::string cseq; 304 | std::string requst(data, len); 305 | 306 | int ret = ParseRTSPRequestString(requst, cmd, urlPreSuffix, urlSuffix, cseq, strSessionId); 307 | if(ret < 0){ 308 | return clientConnection->handleCmd_bad(); 309 | } 310 | 311 | debug_log("[%u]parseRTSPRequestString:{%s}\n", pthread_self(), requst.c_str()); 312 | 313 | bool requsetInsesseion = !strSessionId.empty(); 314 | RtspClientSession * clientSession = NULL; 315 | 316 | clientConnection->SetSeq(cseq); 317 | if (requsetInsesseion){ 318 | clientSession = clientConnection->lookupRtspClientSession(strSessionId); 319 | if(!clientSession){ 320 | return clientConnection->handleCmd_sessionNotFound(); 321 | } 322 | } 323 | 324 | if (cmd == "OPTIONS"){ 325 | clientConnection->handle_options(); 326 | } 327 | else if (cmd == "DESCRIBE"){ 328 | clientConnection->handle_describle(urlPreSuffix, urlSuffix, requst); 329 | } 330 | else if (cmd == "SETUP") 331 | { 332 | if(!requsetInsesseion){ 333 | clientSession = clientConnection->createNewRtspClientSession(); 334 | } 335 | clientSession->handle_setup(clientConnection, urlPreSuffix, urlSuffix, requst); 336 | } 337 | else if (cmd == "PLAY" || 338 | cmd == "PAUSE" || 339 | cmd == "GET_PARAMETER" || 340 | cmd == "SET_PARAMETER" || 341 | cmd == "TEARDOWN"){ 342 | 343 | clientSession->handle_insession(clientConnection, cmd, urlPreSuffix, urlSuffix, requst); 344 | 345 | } 346 | else if(cmd == "REGISTER" || cmd == "REGISTER_REMOTE"){ 347 | } 348 | else{ 349 | clientConnection->handleCmd_notSupported(); 350 | } 351 | 352 | return 0; 353 | } 354 | 355 | 356 | 357 | int rtsp::on_close(connection * n, int reason){ 358 | 359 | RtspClientConnection * clientConnection = (RtspClientConnection*)n->get_context(); 360 | 361 | if (clientConnection){ 362 | delete clientConnection; 363 | error_log("v_close RtspClientConnection close, reason %d\n", reason); 364 | } 365 | 366 | n->set_context(0); 367 | 368 | return 0; 369 | } 370 | 371 | int rtsp::add_delay_task(int id, int delay, void * context){ 372 | return set_timer(id, delay, context); 373 | } 374 | 375 | int rtsp::on_timer(int event, int interval, void * ptr){ 376 | 377 | mediaCtrl * mc = (mediaCtrl *)ptr; 378 | //printf("ref %d\n", mc->ReferncCount()); 379 | if(mc->ReferncCount() > 1){ 380 | mc->Playing(this); 381 | } 382 | else{ 383 | mediaCtrlHub::instance()->destoryMediaCtrl(mc); 384 | } 385 | return 0; 386 | } 387 | 388 | 389 | MediaSession* rtsp::createAttachMediaSession(std::string & streamName){ 390 | std::map::iterator it = m_mediaSessionMap.find(streamName); 391 | if (it != m_mediaSessionMap.end()){ 392 | return it->second; 393 | } 394 | 395 | MediaSession * session = createMediaSession(streamName); 396 | if (session){ 397 | m_mediaSessionMap[streamName]= session; 398 | } 399 | return session; 400 | } 401 | 402 | MediaSession* rtsp::createMediaSession(std::string & streamName){ 403 | 404 | MediaSession * session = NULL; 405 | size_type pos = streamName.rfind('.'); 406 | if (pos == std::string::npos){ 407 | return NULL; 408 | } 409 | 410 | int resue = true; 411 | mediaCtrl* mc = mediaCtrlHub::instance()->getMediaCtrl(streamName, resue); 412 | 413 | std::string extension = streamName.substr(pos , streamName.length() - pos); 414 | if (extension == ".264" || extension == ".h264"){ 415 | session = new MediaSession(streamName); 416 | MediaSubSession * subSession = new H264MediaSubSession(mc); 417 | session->AddSubSession(subSession); 418 | subSession->SetTrackId(session->SubSessionCount()); 419 | } 420 | else if (extension == ".aac"){ 421 | session = new MediaSession(streamName); 422 | MediaSubSession * subSession = new Mp4AMediaSubSession(mc); 423 | session->AddSubSession(subSession); 424 | subSession->SetTrackId(session->SubSessionCount()); 425 | } 426 | else{ 427 | return NULL; 428 | } 429 | 430 | 431 | return session; 432 | } 433 | 434 | MediaSession* rtsp::getAndDetachMediaSession(std::string & streamName){ 435 | std::map::iterator it = m_mediaSessionMap.find(streamName); 436 | if (it != m_mediaSessionMap.end()){ 437 | MediaSession * ms = it->second; 438 | m_mediaSessionMap.erase(it); 439 | return ms; 440 | } 441 | else{ 442 | return createMediaSession(streamName); 443 | } 444 | } 445 | /************************************/ 446 | RtspClientSession::RtspClientSession(std::string & sessionId){ 447 | m_sessionId = sessionId; 448 | m_tcpStreamCount = 0; 449 | m_mediaSession = NULL; 450 | } 451 | 452 | RtspClientSession::~RtspClientSession(){ 453 | safe_del(m_mediaSession); 454 | } 455 | 456 | int RtspClientSession::handle_setup(RtspClientConnection * rcc, 457 | std::string & urlPreSuffix, 458 | std::string & urlSuffix, 459 | std::string & fullRequestStr){ 460 | 461 | // "urlPreSuffix" is empty and "urlSuffix" is the session (stream) name, or 462 | // "urlPreSuffix" concatenated with "urlSuffix" (with "/" inbetween) is the session (stream) name. 463 | 464 | //rtsp://192.168.20.136:5000/xxx666/trackID=0 RTSP/1.0 465 | 466 | std::string streamName = urlPreSuffix; 467 | std::string trackId = urlSuffix; 468 | if(urlPreSuffix.empty()){ 469 | streamName = urlSuffix; 470 | } 471 | 472 | if(m_mediaSession){ 473 | if (m_mediaSession->StreamName() != streamName){ 474 | return rcc->handleCmd_bad(); 475 | } 476 | } 477 | else{ 478 | m_mediaSession = rcc->get_rtsp()->getAndDetachMediaSession(streamName); 479 | } 480 | 481 | if (!m_mediaSession){ 482 | return rcc->handleCmd_notFound(); 483 | } 484 | 485 | if (trackId.empty() && m_mediaSession->SubSessionCount() != 1){ 486 | return rcc->handleCmd_bad(); 487 | } 488 | 489 | MediaSubSession * subsession = NULL; 490 | if (trackId.empty()){ 491 | subsession = m_mediaSession->GetSubSession(0); 492 | } 493 | else{ 494 | subsession = m_mediaSession->Lookup(trackId); 495 | } 496 | 497 | if (!subsession){ 498 | return rcc->handleCmd_notFound(); 499 | } 500 | 501 | int transMode = RTP_UDP; 502 | std::string strDstAdder; 503 | uchar dstTTL = 255; 504 | uint rtpPort = 0; //UDP 505 | uint rtcpPort = 1; //UDP 506 | uchar rtpChannel = 0xff; //tcp 507 | uchar rtcpChannel = 0xff; //tcp 508 | 509 | parseTransportHeader(fullRequestStr, transMode, strDstAdder, dstTTL, 510 | rtpPort, rtcpPort, rtpChannel, rtcpChannel); 511 | 512 | if (transMode == RAW_UDP){ 513 | rcc->handleCmd_notSupported(); 514 | return -1; 515 | } 516 | 517 | if (transMode == RTP_TCP && rtpChannel == 0xff){ 518 | // An anomolous situation, caused by a buggy client. Either: 519 | // 1/ TCP streaming was requested, but with no "interleaving=" fields. (QuickTime Player sometimes does this.), or 520 | // 2/ TCP streaming was not requested, but we're doing RTSP-over-HTTP tunneling (which implies TCP streaming). 521 | rtpChannel = m_tcpStreamCount++; 522 | rtcpChannel = m_tcpStreamCount++; 523 | } 524 | 525 | if (fullRequestStr.find("x-playNow:") != std::string::npos){ 526 | rcc->handleCmd_notSupported(); 527 | return -1; 528 | } 529 | 530 | ipaddr dstAddr = {{0},0}; 531 | if(!strDstAdder.empty()){ 532 | strncpy(dstAddr.ip, strDstAdder.c_str(), sizeof(dstAddr.ip)); 533 | } 534 | else{ 535 | dstAddr = rcc->get_peeraddr(); 536 | } 537 | 538 | const ipaddr & localAddr = rcc->get_localaddr(); 539 | uint dstIp = ntohl(inet_addr(dstAddr.ip )); 540 | 541 | std::string response; 542 | 543 | if (transMode == RTP_TCP){ 544 | subsession->GetTcpParam((void*)rcc, rtpChannel, rtcpChannel, dstTTL); 545 | append(response, 546 | "RTSP/1.0 200 OK\r\n" 547 | "CSeq: %s\r\n" 548 | "%s" 549 | "Transport: RTP/AVP/TCP;unicast;destination=%s;source=%s;interleaved=%d-%d\r\n" 550 | "Session: %s\r\n\r\n", 551 | rcc->getSeq().c_str(), 552 | dateStr().c_str(), 553 | dstAddr.ip, localAddr.ip, 554 | rtpChannel, rtcpChannel, 555 | m_sessionId.c_str()); 556 | } 557 | else{ 558 | 559 | uint serverRtpPort = 0; 560 | uint serverRtcpPort = 0; 561 | subsession->GetUdpParam(rtpPort, rtcpPort, dstIp, serverRtpPort, serverRtcpPort); 562 | append(response, 563 | "RTSP/1.0 200 OK\r\n" 564 | "CSeq: %s\r\n" 565 | "%s" 566 | "Transport: RTP/AVP;unicast;source=%s;client_port=%d-%d;server_port=%d-%d\r\n" 567 | "Session: %s\r\n\r\n", 568 | rcc->getSeq().c_str(), 569 | dateStr().c_str(), 570 | localAddr.ip, 571 | rtpPort, rtcpPort, serverRtpPort, serverRtcpPort, 572 | m_sessionId.c_str()); 573 | } 574 | 575 | debug_log("S->C : %s\n", response.c_str()); 576 | rcc->post_send(response.c_str(), response.length()); 577 | 578 | return 0; 579 | } 580 | 581 | int RtspClientSession::handle_insession(RtspClientConnection * rcc, 582 | std::string & cmd, 583 | std::string & urlPreSuffix, 584 | std::string & urlSuffix, 585 | std::string & fullRequestStr){ 586 | 587 | if (!m_mediaSession){ 588 | rcc->handleCmd_notSupported(); 589 | return -1; 590 | } 591 | 592 | //Look up the media subsession whose track id is "urlSuffix": 593 | MediaSubSession *subsession = NULL; 594 | if (!urlSuffix.empty() && urlPreSuffix == m_mediaSession->StreamName()){ 595 | //rtsp://192.168.20.136:5000/xxx666/trackID=0 RTSP/1.0 596 | m_mediaSession->Lookup(urlSuffix); 597 | } 598 | else if(urlSuffix == m_mediaSession->StreamName() || 599 | (urlSuffix.empty() && urlPreSuffix == m_mediaSession->StreamName())){ 600 | //rtsp://192.168.20.136:5000/xxx666 601 | //rtsp://192.168.20.136:5000/xxx666/ 602 | // Aggregated operation 603 | subsession = m_mediaSession->GetSubSession(0); 604 | } 605 | else if(!urlPreSuffix.empty() && !urlSuffix.empty()){ 606 | //rtsp://192.168.20.136:5000/media/xxx666 607 | // Aggregated operation, if / is the session (stream) name: 608 | std::string streamName = urlPreSuffix + "/" + urlSuffix; 609 | if(streamName == m_mediaSession->StreamName()){ 610 | subsession = m_mediaSession->GetSubSession(0); 611 | } 612 | } 613 | 614 | if (!subsession){ 615 | return rcc->handleCmd_notFound(); 616 | } 617 | 618 | if(cmd == "PLAY") 619 | handle_play(rcc, subsession, fullRequestStr); 620 | else if(cmd == "PAUSE") 621 | handle_pause(rcc, subsession); 622 | else if(cmd == "GET_PARAMETER") 623 | handle_getparameter(rcc, subsession, fullRequestStr); 624 | else if(cmd == "SET_PARAMETER") 625 | handle_setparameter(rcc, subsession, fullRequestStr); 626 | else if(cmd == "TEARDOWN") 627 | handle_teardown(rcc, subsession, fullRequestStr); 628 | 629 | return 0; 630 | } 631 | 632 | 633 | int RtspClientSession::handle_pause(RtspClientConnection * rcc, 634 | MediaSubSession * subSession){ 635 | 636 | return 0; 637 | } 638 | 639 | int RtspClientSession::handle_play(RtspClientConnection * rcc, 640 | MediaSubSession * subSession, 641 | std::string & fullRequestStr){ 642 | 643 | std::string strScale; 644 | 645 | //parse scale 646 | size_type pos = fullRequestStr.find("Scale:"); 647 | if(pos != std::string::npos){ 648 | pos += 5; 649 | while(fullRequestStr[++pos] == ' '); 650 | float fscale = (float)atof(fullRequestStr.c_str() + pos); 651 | append(strScale, "Scale: %f\r\n", fscale); 652 | } 653 | 654 | const ipaddr & localAddr = rcc->get_localaddr(); 655 | std::string rtspUrl; 656 | append(rtspUrl, "RTP-Info: rtsp://%s:%u/%s/%s;seq=%u//;rtptime=%u", 657 | localAddr.ip, watcher::instance()->tcp_port(), 658 | m_mediaSession->StreamName().c_str(), 659 | subSession->GetTrackId().c_str(), 660 | subSession->SeqNo(), 661 | subSession->RtpTimestamp()); 662 | 663 | 664 | 665 | std::string absstart, absend; 666 | double startTime = 0, endTime = 0; 667 | 668 | int result = parseRange(fullRequestStr, absstart, absend, startTime, endTime); 669 | std::string response; 670 | append(response, 671 | "RTSP/1.0 200 OK\r\n" 672 | "CSeq: %s\r\n" 673 | "%s" 674 | "%s" 675 | "Session: %s\r\n" 676 | "%s\r\n\r\n", 677 | rcc->getSeq().c_str(), 678 | dateStr().c_str(), 679 | strScale.c_str(), 680 | m_sessionId.c_str(), 681 | rtspUrl.c_str()); 682 | if(result < 0){ 683 | 684 | } 685 | 686 | debug_log("play: %s\n", response.c_str()); 687 | 688 | rcc->post_send(response.c_str(), response.length()); 689 | subSession->StartStream(rcc->get_rtsp()); 690 | 691 | return 0; 692 | } 693 | 694 | int RtspClientSession::handle_teardown(RtspClientConnection * rcc, 695 | MediaSubSession * subSession, 696 | std::string & fullRequestStr){ 697 | std::string response; 698 | append(response, 699 | "RTSP/1.0 200 OK\r\n" 700 | "CSeq: %s\r\n" 701 | "%s" 702 | "Session: %s\r\n\r\n", 703 | rcc->getSeq().c_str(), 704 | dateStr().c_str(), 705 | m_sessionId.c_str()); 706 | 707 | rcc->post_send(response.c_str(), response.length()); 708 | 709 | subSession->StopStream(); 710 | m_mediaSession->DelSubSession(subSession); 711 | delete subSession; 712 | 713 | if(!m_mediaSession->SubSessionCount()){ 714 | delete m_mediaSession; 715 | m_mediaSession = NULL; 716 | } 717 | return 0; 718 | } 719 | 720 | int RtspClientSession::handle_getparameter(RtspClientConnection * rcc, 721 | MediaSubSession * subSession, 722 | std::string & fullRequestStr){ 723 | return rcc->setRtspResponse("200 OK", m_sessionId.c_str(), "2015.10.25"); 724 | } 725 | 726 | int RtspClientSession::handle_setparameter(RtspClientConnection * rcc, 727 | MediaSubSession * subSession, 728 | std::string & fullRequestStr){ 729 | return rcc->setRtspResponseSession("200 OK", m_sessionId.c_str()); 730 | } 731 | /*--------------------------------------- 732 | * 733 | * 734 | *-------------------------------------*/ 735 | 736 | RtspClientConnection::RtspClientConnection(connection * n, rtsp * r){ 737 | m_client = n; 738 | m_rtsp = r; 739 | } 740 | 741 | RtspClientConnection::~RtspClientConnection(){ 742 | std::map::iterator it = m_clientSessionMap.begin(); 743 | for(; it != m_clientSessionMap.end(); it++){ 744 | delete it->second; 745 | } 746 | m_clientSessionMap.clear(); 747 | } 748 | 749 | 750 | const ipaddr & RtspClientConnection::get_peeraddr(){ 751 | return m_client->get_peeraddr(); 752 | } 753 | 754 | const ipaddr & RtspClientConnection::get_localaddr(){ 755 | return m_client->get_localaddr(); 756 | } 757 | 758 | std::string & RtspClientConnection::getSeq(){ 759 | return m_seqNo; 760 | } 761 | 762 | int RtspClientConnection::post_send(const char * data, int len){ 763 | return m_client->post_send((char*)data, len); 764 | } 765 | 766 | void RtspClientConnection::SetSeq(std::string & seqNo){ 767 | m_seqNo = seqNo; 768 | } 769 | 770 | rtsp* RtspClientConnection::get_rtsp(){ 771 | return m_rtsp; 772 | } 773 | 774 | int RtspClientConnection::handle_options(){ 775 | 776 | std::string str; 777 | append(str, 778 | "RTSP/1.0 200 OK\r\n" 779 | "CSeq: %s\r\n" 780 | "%s" 781 | "Public: %s\r\n\r\n", 782 | getSeq().c_str(), 783 | dateStr().c_str(), 784 | "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, GET_PARAMETER, SET_PARAMETER"); 785 | 786 | return post_send(str.c_str(), str.length()); 787 | 788 | } 789 | 790 | 791 | int RtspClientConnection::handle_describle( 792 | std::string & urlPreSuffix, 793 | std::string & urlSuffix, 794 | std::string & fullRequestStr) 795 | { 796 | 797 | std::string urlTotalSuffix = urlPreSuffix ; 798 | if (!urlTotalSuffix.empty()){ 799 | urlTotalSuffix.append("/"); 800 | } 801 | urlTotalSuffix.append(urlSuffix); 802 | 803 | //authenticationOK, add 804 | 805 | MediaSession * session = m_rtsp->createAttachMediaSession(urlTotalSuffix); 806 | if (!session){ 807 | handleCmd_notFound(); 808 | return -1; 809 | } 810 | 811 | const ipaddr & localAddr = m_client->get_localaddr(); 812 | std::string sdp = session->GenerateSDPDescription(localAddr); 813 | 814 | //get the rtsp url 815 | //rtsp://127.0.0.1/ 816 | std::string rtspUrl; 817 | 818 | append(rtspUrl, "rtsp://%s:%u/%s", 819 | localAddr.ip, watcher::instance()->tcp_port() , 820 | session->StreamName().c_str()); 821 | 822 | std::string response = "RTSP/1.0 200 OK\r\n"; 823 | 824 | append(response, "CSeq: %s\r\n" 825 | "%s" 826 | "Content-Base: %s\r\n" 827 | "Content-Type: application/sdp\r\n" 828 | "Content-Length: %d\r\n\r\n" 829 | "%s", 830 | getSeq().c_str(), 831 | dateStr().c_str(), 832 | rtspUrl.c_str(), 833 | sdp.length(), 834 | sdp.c_str()); 835 | 836 | debug_log("S-C : %s\n", response.c_str()); 837 | 838 | return post_send(response.c_str(), response.length()); 839 | } 840 | 841 | 842 | int RtspClientConnection::handle_getparameter(std::string & fullRequestStr) 843 | { 844 | /* 845 | "GET_PARAMETER rtsp://172.16.128.98:554/TestSession/1.h264 RTSP/1.0 846 | CSeq: 6 847 | User-Agent: LibVLC/2.1.3 (LIVE555 Streaming Media v2014.01.21) 848 | Session: 8000 849 | */ 850 | return setRtspResponse("200 OK","2015.10.25"); 851 | } 852 | 853 | int RtspClientConnection::handle_setparameter(std::string & fullRequestStr){ 854 | return setRtspResponse("200 OK"); 855 | } 856 | 857 | int RtspClientConnection::setRtspResponse(const char * responseStr){ 858 | std::string response; 859 | append(response, 860 | "RTSP/1.0 %s\r\n" 861 | "CSeq: %s\r\n" 862 | "%s\r\n", 863 | responseStr, 864 | m_seqNo.c_str(), 865 | dateStr().c_str()); 866 | return post_send(response.c_str(), response.length()); 867 | } 868 | 869 | int RtspClientConnection::setRtspResponse(const char * responseStr, const char * contentStr){ 870 | if (!contentStr){ 871 | contentStr = ""; 872 | } 873 | std::string response; 874 | 875 | append(response, 876 | "RTSP/1.0 %s\r\n" 877 | "CSeq: %s\r\n" 878 | "%s" 879 | "Content-Length: %d\r\n\r\n" 880 | "%s", 881 | responseStr, 882 | m_seqNo.c_str(), 883 | dateStr().c_str(), 884 | strlen(contentStr), 885 | contentStr); 886 | return post_send(response.c_str(), response.length()); 887 | } 888 | 889 | int RtspClientConnection::setRtspResponseSession(const char * responseStr, const char * seseionId){ 890 | std::string response; 891 | append(response, 892 | "RTSP/1.0 %s\r\n" 893 | "CSeq: %s\r\n" 894 | "%s" 895 | "Session: %s\r\n\r\n", 896 | responseStr, 897 | m_seqNo.c_str(), 898 | dateStr().c_str(), 899 | seseionId); 900 | return post_send(response.c_str(), response.length()); 901 | } 902 | 903 | int RtspClientConnection::setRtspResponse(const char * responseStr, 904 | const char* seseionId, const char * contentStr){ 905 | if (!contentStr){ 906 | contentStr = ""; 907 | } 908 | std::string response; 909 | append(response, 910 | "RTSP/1.0 %s\r\n" 911 | "CSeq: %s\r\n" 912 | "%s" 913 | "Session: %s\r\n" 914 | "Content-Length: %d\r\n\r\n" 915 | "%s", 916 | responseStr, 917 | m_seqNo.c_str(), 918 | dateStr().c_str(), 919 | seseionId, 920 | strlen(contentStr), 921 | contentStr); 922 | return post_send(response.c_str(), response.length()); 923 | } 924 | 925 | RtspClientSession * RtspClientConnection::createNewRtspClientSession(){ 926 | 927 | std::string sessionId; 928 | append(sessionId, "S%lldD", GetTickCount64U()); 929 | RtspClientSession * rcs = new RtspClientSession(sessionId); 930 | m_clientSessionMap.insert(std::make_pair(sessionId, rcs)); 931 | return rcs; 932 | } 933 | 934 | RtspClientSession * RtspClientConnection::lookupRtspClientSession(const std::string & sessionId){ 935 | std::map::iterator it = m_clientSessionMap.find(sessionId); 936 | return it == m_clientSessionMap.end()? NULL: it->second; 937 | } 938 | 939 | --------------------------------------------------------------------------------