// StartRTSP v1.0.0.2 #include #ifdef WIN32 #include #else #include #include #include #include #include #include #include #endif #define MAX_CMD_LENGTH 1024 #define MAX_RTP_BUFF_SIZE 10000 #define MAX_VIDEO_DATA_SIZE 100000 #define RTP_WAIT_TIME 10000 #define NUM_OF_MEDIA 3 #define PAYLOAD_ULAW 0 #define PAYLOAD_MPEG4 96 #define PAYLOAD_PCM 98 #define PAYLOAD_EVENT 110 #define PROTOCOL_UDP 1 #define PROTOCOL_TCP 2 #define RTSP_IP "192.168.2.26" #define RTSP_PORT 554 #define RTSP_PROTOCOL PROTOCOL_UDP #define WAVE_FORMAT_MULAW 7 // comment out the following definition if you want to get uLaw audio. //#define PCM_AUDIO #ifdef PCM_AUDIO // PCM: 16KHz, 16-bit #define AUDIO_SAMPLE_RATE 16000 #define WAVE_FORMAT_TAG WAVE_FORMAT_PCM #define BITS_PER_SAMPLE 16 #define WAVE_FORMAT_STRING "pcm" #else // uLaw: 8KHz, 8-bit #define AUDIO_SAMPLE_RATE 8000 #define WAVE_FORMAT_TAG WAVE_FORMAT_MULAW #define BITS_PER_SAMPLE 8 #define WAVE_FORMAT_STRING "ulaw" #endif #define NUM_AUDIO_CHANNELS 1 #define AUDIO_LENGTH_IN_SEC 10 #define MAX_AUDIO_BYTES (AUDIO_LENGTH_IN_SEC * NUM_AUDIO_CHANNELS * AUDIO_SAMPLE_RATE * BITS_PER_SAMPLE / 8) #ifdef WIN32 SOCKET sock_rtsp; SOCKET sock_rtp[NUM_OF_MEDIA]; #else int sock_rtsp; int sock_rtp[NUM_OF_MEDIA]; #endif FILE *video_fp; FILE *audio_fp; FILE *idx_fp; int seq_num; int track; int sock_rtp_index; char request[MAX_CMD_LENGTH]; char response[MAX_CMD_LENGTH]; struct sockaddr_in addr_rtsp; struct sockaddr_in addr_rtp[NUM_OF_MEDIA]; unsigned char video_data[MAX_VIDEO_DATA_SIZE]; unsigned int video_data_offset = 0; char* g_audioBytes = NULL; int g_numAudioBytes = 0; typedef struct _NVE_EVENT { //int Type; // nChID, Major, Minor, Param unsigned char ChID; // 0xFF : all, [0x00..0xF]:Video0~15, [0x10..0x1F]:Audio0~15 unsigned char Major; // unsigned char Minor; unsigned char Param; struct timeval tTimestamp; int nLength; void *pData; } NVE_EVENT; #pragma pack(push, StartRTSP) #pragma pack(1) #ifndef WIN32 // Borrowed from MMSystem.h and modified to be complied in other platform #define WAVE_FORMAT_PCM 1 typedef struct tWAVEFORMATEX { WORD wFormatTag; /* format type */ WORD nChannels; /* number of channels (i.e. mono, stereo...) */ DWORD nSamplesPerSec; /* sample rate */ DWORD nAvgBytesPerSec; /* for buffer estimation */ WORD nBlockAlign; /* block size of data */ WORD wBitsPerSample; /* number of bits per sample of mono data */ WORD cbSize; /* the count in bytes of the size of */ /* extra information (after cbSize) */ } WAVEFORMATEX; #endif typedef struct { long chunkID; long chunkSize; WAVEFORMATEX waveformat; } FORMATCHUNK; typedef struct { long chunkID; long chunkSize; long sampleLength; } FACTCHUNK; typedef struct { long chunkID; long chunkSize; } DATACHUNK; #pragma pack(pop, StartRTSP) void release() { // release rtsp socket if (sock_rtsp) { #ifdef WIN32 closesocket(sock_rtsp); #else close(sock_rtsp); #endif } // release rtp socket and close file for (int i=0; i NUM_OF_MEDIA) { printf("Exceeded number of media\n"); release(); exit(0); } // rtp memset(&addr_rtp[sock_rtp_index], 0, sizeof(addr_rtp[sock_rtp_index])); addr_rtp[sock_rtp_index].sin_family = AF_INET; addr_rtp[sock_rtp_index].sin_addr.s_addr = htonl(INADDR_ANY); addr_rtp[sock_rtp_index].sin_port = htons(port); sock_rtp[sock_rtp_index] = socket(AF_INET, SOCK_DGRAM, 0); if (sock_rtp[sock_rtp_index] < 0) { printf("Cannot create socket[%d].\n", sock_rtp_index); release(); exit(0); } if (bind(sock_rtp[sock_rtp_index], (struct sockaddr*)&addr_rtp[sock_rtp_index], sizeof(addr_rtp[sock_rtp_index])) < 0) { printf("Cannot bind[%d]\n", sock_rtp_index); release(); exit(0); } sock_rtp_index++; } void send_request(char *cmd) { printf("%s\n", request); if (send(sock_rtsp, request, strlen(request), 0) != (int)strlen(request)) { printf("Cannot send request(%s).\n", cmd); release(); exit(0); } } void recv_response(char *cmd) { memset(response, 0, sizeof(response)); if (recv(sock_rtsp, response, MAX_CMD_LENGTH, 0) <= 0) { printf("Cannot receive response(%s).\n", cmd); release(); exit(0); } printf("%s\n", response); } #ifdef WIN32 #define FACTOR (0x19db1ded53e8000I64) void filetime_to_timeval(FILETIME *src, struct timeval *dst) { ULARGE_INTEGER x; x.LowPart = src->dwLowDateTime; x.HighPart = src->dwHighDateTime; x.QuadPart -= FACTOR; dst->tv_sec = (LONG)(x.QuadPart / 10000000); dst->tv_usec = (LONG)((x.QuadPart % 10000000) / 10); } #endif void process_mpeg4(unsigned char *packet, unsigned int size) { // save mpeg4 data struct timeval tv; unsigned long head; #ifdef WIN32 SYSTEMTIME sys_time; FILETIME file_time; GetSystemTime(&sys_time); SystemTimeToFileTime(&sys_time, &file_time); filetime_to_timeval(&file_time, &tv); #else gettimeofday(&tv, 0); #endif unsigned int offset = ftell(video_fp); if (offset == 0) { head = *(unsigned long*)packet; if (head != 0xb0010000) { return; } } fwrite(packet, size, 1, video_fp); fwrite(&tv, sizeof(tv), 1, idx_fp); fwrite(&offset, sizeof(offset), 1, idx_fp); } void process_pcm(unsigned char *packet, unsigned int size) { // convert to little-endian unsigned int num_values = size/2; short* value = (short*)packet; for (unsigned int i = 0; i < num_values; ++i) { short const orig = value[i]; value[i] = ((orig&0xFF)<<8) | ((orig&0xFF00)>>8); } if (g_numAudioBytes + size < MAX_AUDIO_BYTES) { memcpy(&g_audioBytes[g_numAudioBytes], value, size); g_numAudioBytes += size; } } void process_uLaw(unsigned char *packet, unsigned int size) { // convert to little-endian unsigned int num_values = size/2; short* value = (short*)packet; for (unsigned int i = 0; i < num_values; ++i) { short const orig = value[i]; value[i] = ((orig&0xFF)<<8) | ((orig&0xFF00)>>8); } if (g_numAudioBytes + size < MAX_AUDIO_BYTES) { memcpy(&g_audioBytes[g_numAudioBytes], value, size); g_numAudioBytes += size; } } void process_event(unsigned char *packet) { // show event data NVE_EVENT *event_data = (NVE_EVENT*)packet; printf("Ch ID[%d]\n", event_data->ChID); printf("Major[%d]\n", event_data->Major); printf("Minor[%d]\n", event_data->Minor); printf("Param[%d]\n", event_data->Param); printf("Length[%d]\n", event_data->nLength); printf("\n"); } #define ADVANCE(n) packet+=n; head+=n; void process_rtp_packet(unsigned char *packet, unsigned int size) { unsigned int head = 0, tail = size; unsigned char payload_type; while (1) { // Check for the 12-byte RTP header: unsigned int rtp_hdr = ntohl(*(unsigned int*)(packet)); ADVANCE(4); int rtp_marker_bit = (rtp_hdr&0x00800000) >> 23; unsigned int rtp_timestamp = ntohl(*(unsigned int*)(packet)); ADVANCE(4); unsigned int rtp_ssrc = ntohl(*(unsigned int*)(packet)); ADVANCE(4); printf("timestamp[%d], ssrc[%d]\n", rtp_timestamp, rtp_ssrc); // Check the RTP version number (it should be 2): if ((rtp_hdr&0xC0000000) != 0x80000000) break; // Skip over any CSRC identifiers in the header: unsigned int cc = (rtp_hdr>>24)&0xF; if (tail-head < cc) break; ADVANCE(cc*4); // Check for (& ignore) any RTP header extension if (rtp_hdr&0x10000000) { if (tail-head < 4) break; unsigned int ext_hdr = ntohl(*(unsigned int*)(packet)); ADVANCE(4); unsigned int rem_ext_size = 4*(ext_hdr&0xFFFF); if (tail-head < rem_ext_size) break; ADVANCE(rem_ext_size); } // Discard any padding bytes: if (rtp_hdr&0x20000000) { if (tail-head == 0) break; unsigned int numPaddingBytes = (unsigned int)(packet)[tail-head-1]; if (tail-head < numPaddingBytes) break; tail-=numPaddingBytes; } // Check the Payload Type. payload_type = (unsigned char)((rtp_hdr&0x007F0000)>>16); printf("payload type[%d]\n", payload_type); switch(payload_type) { case PAYLOAD_MPEG4: memcpy(&video_data[video_data_offset], packet, tail-head); video_data_offset += tail-head; if (rtp_marker_bit == 1) { process_mpeg4(video_data, video_data_offset); video_data_offset = 0; } break; case PAYLOAD_PCM: process_pcm(packet, tail-head); break; case PAYLOAD_ULAW: process_uLaw(packet, tail-head); break; case PAYLOAD_EVENT: process_event(packet); break; default: break; } return; } printf("Cannot parse rtp header\n"); release(); exit(0); } void read_rtp_data() { fd_set rset; struct timeval tv; int i, rs, recv_bytes; unsigned char buff[MAX_RTP_BUFF_SIZE]; #ifdef WIN32 unsigned int start, current; #else struct timeval start, current; #endif #ifdef WIN32 start = GetTickCount(); #else gettimeofday(&start, 0); #endif printf("Get rtp packet for %d seconds...\n", RTP_WAIT_TIME/1000); while (1) { tv.tv_sec = 1; tv.tv_usec = 0; FD_ZERO(&rset); for (i=0; i RTP_WAIT_TIME) { printf("timeout\n"); break; } #else gettimeofday(¤t, 0); int interval = (current.tv_sec-start.tv_sec)*1000 + (current.tv_usec-start.tv_usec)/1000; if (interval > RTP_WAIT_TIME) { printf("timeout\n"); break; } #endif } } void rtsp_describe() { sprintf(request, "DESCRIBE / RTSP/1.0\r\n" "CSeq: %d\r\n" "Accept: application/sdp\r\n\r\n", ++seq_num); send_request("DESCRIBE"); recv_response("DESCRIBE"); } void rtsp_setup() { int rtp_port = 30000; // mpeg4 video sprintf(request, "SETUP /track1 RTSP/1.0\r\n" "CSeq: %d\r\n" "Transport: RTP/AVP;unicast;client_port=%d-%d\r\n\r\n", ++seq_num, rtp_port, rtp_port+1); send_request("SETUP"); recv_response("SETUP"); init_rtp_sock(rtp_port); rtp_port += 2; #ifdef PCM_AUDIO // pcm audio sprintf(request, "SETUP /track3 RTSP/1.0\r\n" "CSeq: %d\r\n" "Transport: RTP/AVP;unicast;client_port=%d-%d\r\n\r\n", ++seq_num, rtp_port, rtp_port+1); send_request("SETUP"); recv_response("SETUP"); init_rtp_sock(rtp_port); rtp_port += 2; #else // uLaw audio sprintf(request, "SETUP /track4 RTSP/1.0\r\n" "CSeq: %d\r\n" "Transport: RTP/AVP;unicast;client_port=%d-%d\r\n\r\n", ++seq_num, rtp_port, rtp_port+1); send_request("SETUP"); recv_response("SETUP"); init_rtp_sock(rtp_port); rtp_port += 2; #endif // event sprintf(request, "SETUP /track6 RTSP/1.0\r\n" "CSeq: %d\r\n" "Transport: RTP/AVP;unicast;client_port=%d-%d\r\n\r\n", ++seq_num, rtp_port, rtp_port+1); send_request("SETUP"); recv_response("SETUP"); init_rtp_sock(rtp_port); } void rtsp_play() { sprintf(request, "PLAY / RTSP/1.0\r\n" "CSeq: %d\r\n\r\n", ++seq_num); send_request("PLAY"); recv_response("PLAY"); } void rtsp_teardown() { sprintf(request, "TEARDOWN / RTSP/1.0\r\n" "CSeq: %d\r\n\r\n", ++seq_num); send_request("TEARDOWN"); recv_response("TEARDOWN"); } int main() { #ifdef WIN32 WSAData WsaData; WSAStartup(WINSOCK_VERSION, &WsaData); #endif seq_num = 0; sock_rtsp = 0; sock_rtp_index = 0; video_fp = 0; audio_fp = 0; idx_fp = 0; memset(sock_rtp, 0, sizeof(sock_rtp)); g_audioBytes = (char*)malloc(MAX_AUDIO_BYTES); g_numAudioBytes = 0; open_file(); init_rtsp_sock(); rtsp_describe(); rtsp_setup(); rtsp_play(); read_rtp_data(); rtsp_teardown(); write_wav(); release(); free(g_audioBytes); #ifdef WIN32 WSACleanup(); #endif return 0; }