1 Star 4 Fork 2

eyhxh/rtspclient

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
RTSPClient.c 28.61 KB
一键复制 编辑 原始数据 按行查看 历史
hexinhua 提交于 2017-08-15 00:42 . 优化了一部分程序
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <netdb.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdarg.h>
#include <ctype.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <netinet/if_ether.h>
#include <net/if.h>
#include <linux/if_ether.h>
#include <linux/sockios.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "rtp.h"
// #include "./dbg_printf.h"
#define OUR_DEV
//#define HOME
typedef void * HANDLE;
#ifdef OUR_DEV
#define URL "192.168.1.95"
#define DEF_RTSP_URL "rtsp://192.168.1.95/264.264"
// #define DEF_RTSP_URL "rtsp://192.168.0.28/trackID1"
// #define DEF_RTSP_URL "rtsp://192.168.2.112/264.264"
#else
#define DEF_RTSP_URL "rtsp://192.168.0.29/"
#endif
#define RTSP_PORT 554
#define PRG_NAME "main"
#define UDP_RECV_PORT0 1023
#define UDP_RECV_PORT1 1024
#define max( a, b ) ( a > b ? a : b )
typedef enum RTSP_STAT
{
RTSP_NONE = 0,
RTSP_OPTION,
RTSP_DESCRIPT,
RTSP_SETUP,
RTSP_PLAY,
RTSP_GETPARM,
RTSP_KEEP,
RTSP_PAUSE,
RTSP_STOP
}RTPS_STAT_E;
typedef enum LINK_STAT
{
LINK_DISCONNECT = 0,
LINK_CONNECTING,
LINK_CONNECTED
}LINK_STAT_E;
typedef enum TRANSPORT
{
TRANS_UDP = 0,
TRANS_TCP,
TRANS_RAW
}TRANSPORT_E;
#define MAGIC_NUM 0x1a2b4c3d
#define RTSP_INVALID( obj ) ( obj->magic != MAGIC_NUM )
typedef struct tagRtspClient
{
unsigned int magic;
int fd; //rtsp web socket
TRANSPORT_E stream_type; // 码流方式
int recv_fd[2]; //
int recv_port[2]; // 监听端口
char rtsp_url[128]; // rtsp request url
char server_ip[128];
int server_port[2];
char session[20];
char authName[64];
char authPwd[64];
int support_cmd;
int bQuit;
int trackId;
time_t tou;
RTPS_STAT_E stat;
LINK_STAT_E link;
int CSeq;
unsigned char *recv_buf;
int maxBufSize;
HANDLE Filter;
HANDLE Vdec;
HANDLE rtp;
pthread_t threadID;
// struct list_head list;
}RtspClient, *PVHRtspClient;
#define SOCK_ERROR() do{\
if( len <= 0 )\
{\
fd = 0;\
printf("sock error, %s!\r\n", strerror(errno));\
break;\
}\
}while(0)
/* TCP and UDP API*/
int sock_listen( int port, const char *ipbind, int backlog )
{
struct sockaddr_in my_addr;
int fd, tmp = 1;
fd = socket(AF_INET,SOCK_STREAM,0);
if (fd < 0)
return -1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons ((short)port);
if( ipbind != NULL ) {
inet_aton( ipbind, & my_addr.sin_addr );
} else {
my_addr.sin_addr.s_addr = htonl (INADDR_ANY);
}
if( 0 == bind (fd, (struct sockaddr *) &my_addr, sizeof (my_addr)) )
{
if( 0 == listen(fd, backlog) ) {
return fd;
}
}
close(fd);
return -1;
}
int sock_dataready( int fd, int tout )
{
fd_set rfd_set;
struct timeval tv, *ptv;
int nsel;
FD_ZERO( &rfd_set );
FD_SET( fd, &rfd_set );
if ( tout == -1 )
{
ptv = NULL;
}
else
{
tv.tv_sec = 0;
tv.tv_usec = tout * 1000;
ptv = &tv;
}
nsel = select( fd+1, &rfd_set, NULL, NULL, ptv );
if ( nsel > 0 && FD_ISSET( fd, &rfd_set ) )
return 1;
return 0;
}
int sock_udp_bind( int port )
{
struct sockaddr_in my_addr;
int tmp=0;
int udp_fd;
// signal init, to avoid app quit while pipe broken
// signal(SIGPIPE, SIG_IGN);
if ( (udp_fd = socket( AF_INET, SOCK_DGRAM, 0 )) >= 0 )
{
setsockopt( udp_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons ((short)port);
my_addr.sin_addr.s_addr = htonl (INADDR_ANY); // get_ifadapter_ip("eth0",NULL);
if (bind ( udp_fd, (struct sockaddr *) &my_addr, sizeof (my_addr)) < 0)
{
close( udp_fd );
udp_fd = -EIO;
}
}
return udp_fd;
}
int sock_udp_send( const char *ip, int port, const void* msg, int len )
{
// SOCKADDR_IN udp_addr;
struct sockaddr_in udp_addr;
int sockfd, ret;
sockfd = socket( AF_INET, SOCK_DGRAM, 0 );
if( sockfd <= 0 ) return -1;
//setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
memset( & udp_addr, 0, sizeof(udp_addr) );
udp_addr.sin_family = AF_INET;
inet_aton( ip, &udp_addr.sin_addr );
udp_addr.sin_port = htons( (short)port );
ret = sendto( sockfd, msg, len, 0, (const struct sockaddr *) & udp_addr, sizeof(udp_addr) );
close( sockfd );
return ret;
}
static sock_read( int fd , char *buf, int maxBuf )
{
return read( fd, buf, maxBuf );
}
int sock_connect( const char *host, int port )
{
struct sockaddr_in destaddr;
struct hostent *hp;
int fd = 0;
memset( & destaddr, 0, sizeof(destaddr) );
destaddr.sin_family = AF_INET;
destaddr.sin_port = htons( (short)port );
if ((inet_aton(host, & destaddr.sin_addr)) == 0)
{
hp = gethostbyname(host);
if(! hp) return -EINVAL;
memcpy (& destaddr.sin_addr, hp->h_addr, sizeof(destaddr.sin_addr));
}
fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0) return -EIO;
if ( connect(fd, (struct sockaddr *)&destaddr, sizeof(destaddr)) < 0 )
{
close( fd );
return -EIO;
}
return fd;
}
static const char* to_b64 =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
/* encode 72 characters per line */
#define CHARS_PER_LINE 72
typedef unsigned char byte;
/* return value:
* >0: encoded string length, -1 buf too small
* Encoded string is terminated by '\0'.
*/
int str_b64enc(const char *src, char *buf, int bufsize )
{
int size = strlen( src );
int div = size / 3;
int rem = size % 3;
int chars = div*4 + rem + 1;
int newlines = (chars + CHARS_PER_LINE - 1) / CHARS_PER_LINE;
int outsize = chars + newlines;
const byte* data = (const byte *)src;
byte* enc = (byte *)buf;
if ( bufsize < outsize + 1 ) return -1;
chars = 0;
while (div > 0)
{
enc[0] = to_b64[ (data[0] >> 2) & 0x3f];
enc[1] = to_b64[((data[0] << 4) & 0x30) + ((data[1] >> 4) & 0xf)];
enc[2] = to_b64[((data[1] << 2) & 0x3c) + ((data[2] >> 6) & 0x3)];
enc[3] = to_b64[ data[2] & 0x3f];
data += 3;
enc += 4;
div--;
chars += 4;
if (chars == CHARS_PER_LINE)
{
chars = 0;
// *(enc++) = '\n'; /* keep the encoded string in single line */
}
}
switch (rem)
{
case 2:
enc[0] = to_b64[ (data[0] >> 2) & 0x3f];
enc[1] = to_b64[((data[0] << 4) & 0x30) + ((data[1] >> 4) & 0xf)];
enc[2] = to_b64[ (data[1] << 2) & 0x3c];
enc[3] = '=';
enc += 4;
chars += 4;
break;
case 1:
enc[0] = to_b64[ (data[0] >> 2) & 0x3f];
enc[1] = to_b64[ (data[0] << 4) & 0x30];
enc[2] = '=';
enc[3] = '=';
enc += 4;
chars += 4;
break;
}
*enc = '\0';
return strlen(buf); // exclude the tail '\0'
}
/*
* decode a base64 encoded string.
* return -1: bufsize too small, \
* 0: string content error,
* > 0: decoded string (null terminated).
*/
int str_b64dec(const char* string, char *buf, int bufsize)
{
register int length = string ? strlen(string) : 0;
register byte* data = (byte *)buf;
/* do a format verification first */
if (length > 0)
{
register int count = 0, rem = 0;
register const char* tmp = string;
while (length > 0)
{
register int skip = strspn(tmp, to_b64);
count += skip;
length -= skip;
tmp += skip;
if (length > 0)
{
register int i, vrfy = strcspn(tmp, to_b64);
for (i = 0; i < vrfy; i++)
{
if (isspace(tmp[i])) continue;
if (tmp[i] == '=')
{
/* we should check if we're close to the end of the string */
if ( (rem = count % 4) < 2 )
/* rem must be either 2 or 3, otherwise no '=' should be here */
return 0;
/* end-of-message recognized */
break;
}
else
{
/* Invalid padding character. */
return 0;
}
}
length -= vrfy;
tmp += vrfy;
}
}
if ( bufsize < (count/4 * 3 + (rem ? (rem-1) : 0)) )
return -1;
if (count > 0)
{
register int i, qw = 0;
length = strlen(string);
for (i = 0; i < length; i++)
{
register char ch = string[i];
register byte bits;
if (isspace(ch)) continue;
bits = 0;
if ((ch >= 'A') && (ch <= 'Z'))
{
bits = (byte) (ch - 'A');
}
else if ((ch >= 'a') && (ch <= 'z'))
{
bits = (byte) (ch - 'a' + 26);
}
else if ((ch >= '0') && (ch <= '9'))
{
bits = (byte) (ch - '0' + 52);
}
else if (ch == '=')
break;
switch (qw++)
{
case 0:
data[0] = (bits << 2) & 0xfc;
break;
case 1:
data[0] |= (bits >> 4) & 0x03;
data[1] = (bits << 4) & 0xf0;
break;
case 2:
data[1] |= (bits >> 2) & 0x0f;
data[2] = (bits << 6) & 0xc0;
break;
case 3:
data[2] |= bits & 0x3f;
break;
}
if (qw == 4)
{
qw = 0;
data += 3;
}
}
data += qw;
*data = '\0';
}
}
return data - (unsigned char *)buf;
}
int strstartwith(const char *string, const char *prefix, int minmatch, char ** pleft)
{
int len = strlen(prefix);
int n = strlen( string );
if ( n < len && n >=minmatch && minmatch ) len = n;
if( 0 == strncmp(string, prefix, len) ) {
if(pleft) *pleft = (char*)(string + len);
return 1;
}
if(pleft) *pleft = NULL;
return 0;
}
int stridxinargs( const char *key, int minmatch,...)
{
va_list va;
char *matcharg;
int matched_arg = -1;
int arg_index = 0;
va_start( va, minmatch );
while ( (matcharg = va_arg( va , char * )) != NULL )
{
if ( (minmatch==0 && strcmp(key, matcharg)==0) ||
(minmatch && strstartwith( key, matcharg, minmatch, NULL) ) )
{
matched_arg = arg_index;
break;
}
arg_index++;
}
va_end(va);
return matched_arg;
}
int strgetword( const char *string, char *buf, int size, char **pleft)
{
const char *ptr, *q;
int len;
/* skip leading white-space */
for(ptr=string; *ptr && (*ptr==' ' || *ptr=='\t' || *ptr=='\n'); ptr++);
if ( *ptr=='\0' ) return 0;
for(q=ptr; *q && *q!=' ' && *q!='\t' && *q!='\n'; q++);
len = q - ptr;
if ( len < size )
{
memcpy( buf, ptr, len );
buf[len] = '\0';
if ( pleft )
*pleft=(char*)q;
return len;
}
return 0;
}
/* TCP and UDP API EDN */
static const char *read_line( char *buf, char *line, char **dptr )
{
if( !buf || *buf == '\0') return 0;
char *ptr = buf;
char *lineS = line;
for( ;*ptr != '\n'; ptr++ ) *line++ = *ptr;
*line++ = '\n';
*line = '\0';
*dptr = (ptr+1);
return lineS;
}
static int new_sock( int type, PVHRtspClient client )
{
int i = 0;
client->stream_type = TRANS_TCP;
if( type == 0 )
{
client->stream_type = TRANS_UDP;
printf("使用UDP方式获取码流!\r\n");
}
else
printf("使用TCP方式获取码流!\r\n");
int fd0, fd1;
if( client->recv_fd[0] > 0 )
close( client->recv_fd[0] );
if( client->recv_fd[1] > 0 )
close( client->recv_fd[1] );
client->recv_port[0] = 0;
client->recv_port[1] = 0;
for( i; i < 100; i++ )
{
if( client->stream_type == TRANS_UDP )
{
fd0 = sock_udp_bind( 1024 + i );
if( fd0 < 0 )
continue;
fd1 = sock_udp_bind( 1024 + i+1 );
if( fd1 < 0 )
{
i++;
close( fd0 );
continue;
}
client->recv_fd[0] = fd0;
client->recv_fd[1] = fd1;
client->recv_port[0] = 1024 + i;
client->recv_port[1] = 1024 + i+1;
printf("绑定本地UDP端口:%d -%d \r\n", client->recv_port[0], client->recv_port[1] );
break;
}else if( client->stream_type == TRANS_TCP ){
fd0 = sock_listen(1024 + i, NULL, 0);
if( fd0 < 0 )
continue;
fd1 = sock_listen(1024 + i + 1, NULL, 0);
if( fd1 < 0 )
{
i++;
close( fd0 );
continue;
}
client->recv_fd[0] = fd0;
client->recv_fd[1] = fd1;
client->recv_port[0] = 1024 + i;
client->recv_port[1] = 1024 + i+1;
break;
}
}
if( client->recv_port[0] > 0 )
return 0;
else
return -1;
}
static int IsAnsOK( char *buf )
{
int code = 0;
if( buf == NULL )
return -1;
sscanf( buf, "RTSP/1.0 %d", &code );
if( code == 200 )
return 0;
printf("ANS ERROR:%s \r\n", buf );
return -1;
}
static void AnsOption( HANDLE handle, char *buf )
{
PVHRtspClient obj = (PVHRtspClient)handle;
obj->support_cmd = 0;
if( IsAnsOK( buf ) != 0 )
return;
char *ptr = NULL;
ptr = strstr( buf, "\r\n\r\n" );
if( ptr )
{
ptr += 4;
if( *ptr == '\0' )
return;
printf("Content:%s\r\n", ptr);
}
char *options = NULL;
char key[30];
while( strgetword( options, key, sizeof( key ), &options ) != 0 )
{
int index = stridxinargs( key, 5, "OPTIONS", "DESCRIBE", "SETUP", "PLAY", "TEARDOWN", "GET_PARAMETER" );
switch( index )
{
case 0: obj->support_cmd |= (1)<<0; break;
case 1: obj->support_cmd |= (1)<<1; break;
case 2: obj->support_cmd |= (1)<<2; break;
case 3: obj->support_cmd |= (1)<<3; break;
case 4: obj->support_cmd |= (1)<<4; break;
case 5: obj->support_cmd |= (1)<<5; break;
case 6: obj->support_cmd |= (1)<<6; break;
default:
break;
}
}
obj->stat = RTSP_DESCRIPT;
}
static void AnsDescript( HANDLE handle, char *buf )
{
PVHRtspClient obj = (PVHRtspClient)handle;
if( IsAnsOK( buf ) != 0 )
return;
char *ptr , *q;
char tmp[128] = {0};
ptr = strstr( buf, "\r\n\r\n" );
if( ptr )
{
ptr += 4;
if( *ptr == '\0' )
return;
}
// 获取Descript中关于Track的内容,由于Reply的Content里会有a=control:*部分,这部分我们不用,直接跳过,获取第一个track部分
//定位到视频部分
ptr = strstr( buf, "m=video" );
if( ptr )
{
ptr = strstr( ptr, "a=control" );
if( ptr )
{
for( ;*ptr != ':'; ptr++ );
ptr++;
q = tmp;
while( *ptr != '\r' && *ptr != ';' && *ptr != '\t' && *ptr != '\n')
if( *ptr != ' ' )
*q++ = *ptr++;
else
ptr++;
*q = '\0';
// 获取到的control后设置rtsp请求头,不然有问题
// if( obj->rtsp_url[0] == '\0' )
sprintf( obj->rtsp_url, "rtsp://%s/%s", obj->server_ip, tmp );
printf("rtsp_url ip:%s \r\n", obj->rtsp_url );
}else{
printf("can not find the rtsp source");
obj->stat = RTSP_OPTION;
}
}else
{
printf("can not find the rtsp source");
obj->stat = RTSP_OPTION;
}
obj->stat = RTSP_SETUP;
}
static void AnsSetup( HANDLE handle, char *buf )
{
PVHRtspClient obj = (PVHRtspClient)handle;
if( IsAnsOK( buf ) != 0 )
return;
char tmp[128];
char *ptr, *q;
ptr = strstr( buf, "server_port=" );
if( ptr )
{
ptr += 12;
q = tmp;
while( *ptr != '\r' && *ptr != ';' && *ptr != '\t' && *ptr != '\n')
if( *ptr != ' ' )
*q++ = *ptr++;
else
ptr++;
*q = '\0';
int start, end;
sscanf( tmp, "%d-%d", &start, &end );
obj->server_port[0] = start;
obj->server_port[1] = end;
printf("Server listen port:%d - %d\r\n", start, end );
}
ptr = strstr( buf, "Session:" );
if( ptr )
{
q = tmp;
ptr += 8;
while( *ptr != '\r' && *ptr != ';' && *ptr != '\t' && *ptr != '\n')
{
if( *ptr != ' ' )
*q++ = *ptr++;
else
ptr++;
}
printf("Session:%s \r\n", tmp );
*q = '\0';
strcpy( obj->session, tmp );
}else{
printf("Not find ptr!\r\n");
obj->stat = RTSP_OPTION;
}
obj->stat = RTSP_PLAY;
}
static void AnsPlay( HANDLE handle, char *buf )
{
PVHRtspClient obj = (PVHRtspClient)handle;
if( IsAnsOK( buf ) != 0 )
return;
char *ptr = NULL;
obj->stat = RTSP_KEEP;
ptr = strstr( buf, "\r\n\r\n" );
if( ptr )
{
ptr += 4;
if( *ptr == '\0' )
return;
}
}
// 该接口没用过,等到以后需要使用的时候再说,也不知道该接口干嘛的
static void AnsGetParam( HANDLE handle, char *buf )
{
PVHRtspClient obj = (PVHRtspClient)handle;
if( IsAnsOK( buf ) != 0 )
return;
char *ptr = NULL;
ptr = strstr( buf, "\r\n\r\n" );
if( ptr )
{
ptr += 4;
if( *ptr == '\0' )
return;
printf("Content:%s\r\n", ptr);
}
obj->stat = RTSP_KEEP;
}
// 关闭数据流
static void AnsStop( HANDLE handle, char *buf )
{
if( IsAnsOK( buf ) != 0 )
return;
char *ptr = NULL;
ptr = strstr( buf, "\r\n\r\n" );
if( ptr )
{
ptr += 4;
if( *ptr == '\0' )
return;
printf("Content:%s\r\n", ptr);
}
}
static const char *getAuthurationInfo( HANDLE handle )
{
//这边的内容待定,暂时没有用户名密码输入的需求,后期有的话再开发,大概这这么写的
PVHRtspClient obj = (PVHRtspClient)handle;
static char authon[256] = {0};
if( obj->authName[0] == '\0')
{
memset(authon, 0, sizeof( authon ) );
return authon;
}
char body[128] = {0};
char enBody[256] = {0};
//char const* const authFmt = "Authorization: Basic %s\r\n";
char const* const authFmt = "";
unsigned usernamePasswordLength = strlen(obj->authName) + 1 + strlen(obj->authPwd);
sprintf(body, "%s:%s", obj->authName, obj->authPwd);
// int len = str_b64enc(body, enBody, sizeof( enBody ));
// unsigned const authBufSize = strlen(authFmt) + strlen(enBody) + 1;
sprintf(authon, authFmt, enBody );
return authon;
}
int SendRequest( HANDLE handle , RTPS_STAT_E type )
{
PVHRtspClient obj = (PVHRtspClient)handle;
char *cmd = NULL;
if( type == RTSP_NONE )
obj->CSeq = 0;
if( type != RTSP_PLAY )
obj->CSeq++;
char Agent[128] = {0}, StrCSeq[30] = {0}, Authoration[128] = {0};
char contentLengthHeader[128] = {0}, extraHeaders[128] = {0};
char contentStr[512] = {0};
char const* protocolStr = "RTSP/1.0"; // by default
char const* const cmdFmt =
"%s %s %s\r\n" // type, url, rtsp
"%s" // CSeq
"%s" // Authuration
"%s" // Agent
"%s" // extraHeader
"%s" // contentlen
"\r\n"
"%s"; // content
switch( type )
{
case RTSP_NONE:
case RTSP_OPTION:
cmd = "OPTIONS";
break;
case RTSP_DESCRIPT:
cmd = "DESCRIBE";
break;
case RTSP_SETUP:
cmd = "SETUP";
break;
case RTSP_PLAY:
cmd = "PLAY";
break;
case RTSP_GETPARM:
cmd = "GET_PARAMETER";
break;
case RTSP_PAUSE:
case RTSP_STOP:
cmd = "TEARDOWN";
break;
case RTSP_KEEP:
return 0;
break;
default:
break;
}
sprintf( Agent, "User-Agent: %s\r\n", PRG_NAME );
sprintf( StrCSeq, "CSeq: %d\r\n", obj->CSeq );
if( obj->session[0] != '\0' && obj->stat > RTSP_SETUP )
sprintf( extraHeaders, "Session: %s\r\nRange: npt=0.000-\r\n", obj->session );
else
sprintf( extraHeaders, "Range: npt=0.000-\r\n" );
if( obj->stat == RTSP_SETUP )
{
//new_sock( TRANS_TCP, obj );
//sprintf( extraHeaders, "Transport: RTP/AVP/TCP;unicast;client_port=%d-%d\r\n", obj->recv_port[0], obj->recv_port[1] );
sprintf( extraHeaders, "Transport: RTP/AVP/TCP;unicast;interleaved=0-1\r\n");
}
if( obj->stat <= RTSP_DESCRIPT )
sprintf( extraHeaders,"Accept: application/sdp\r\n");
// if we have contelen and content info
sprintf( Authoration, "%s", getAuthurationInfo(obj));
sprintf( obj->recv_buf , cmdFmt, cmd, obj->rtsp_url, protocolStr,\
StrCSeq, Authoration, Agent, extraHeaders,\
contentLengthHeader, contentStr );
if( obj->fd > 0 )
{
printf("Send Requtst:%s \r\n", obj->recv_buf );
write( obj->fd, obj->recv_buf, strlen( obj->recv_buf) );
}
if( sock_dataready(obj->fd, 2000) )
{
memset( obj->recv_buf, 0, obj->maxBufSize );
if( 0 >= read( obj->fd, obj->recv_buf, obj->maxBufSize ) )
{
printf("No response!\r\n");
return 0;
}
printf("ANS:\n%s\r\n", obj->recv_buf );
switch( type )
{
case RTSP_NONE:
case RTSP_OPTION:
AnsOption( obj, obj->recv_buf );
break;
case RTSP_DESCRIPT:
AnsDescript( obj, obj->recv_buf );
break;
case RTSP_SETUP:
AnsSetup( obj, obj->recv_buf );
break;
case RTSP_PLAY:
AnsPlay( obj, obj->recv_buf );
break;
case RTSP_GETPARM:
AnsGetParam( obj, obj->recv_buf );
break;
case RTSP_PAUSE:
case RTSP_STOP:
AnsStop( obj, obj->recv_buf );
break;
break;
default:
break;
}
}
return 0;
}
// extern HANDLE NewFilter( int size , HANDLE Vde);
extern int FilterWrite( HANDLE h, char *buf, int size );
const char *show_hex( const char *ch, int rlen)
{
int i = 0;
char *ptr =(char*)ch;
static char buf[1024];
memset( buf, 0, sizeof( buf ));
char *off = buf;
unsigned char val;
int len = rlen > 300 ? 300 : rlen;
memset( buf, 0, sizeof( buf ));
for (i = 0; i < len; i++)
{
val = *ptr++;
sprintf( off, "%02x ", val);
off+=3;
}
*off = '\0';
return buf;
}
void RTCP_PackParse( PVHRtspClient client , char *buf, int size )
{
memset( buf, 0, size );
int len = create_rtcp_reportinfo( buf, 128 );
// RTCP 包就回复一下就好了, 无所谓的,基本不用的
sock_udp_send( client->server_ip, client->server_port[1], buf, len );
// printf("==================>>>>>>>>> Receive RTCP Rackage %s !\r\n", show_hex( buf, len ));
}
int RTP_PackParse( PVHRtspClient client, char *buf, int size )
{
//printf("receive pack:%d\r\n", size );
if( ParseRtp( client->rtp , buf, size ) == 1 )
{
//printf("Get a Full Nalu Packet!\r\n");
return 1;
// 如果获取到足够发送的码流,发送到解码通道
// if( client->Vdec )
// RTP_Send( client->rtp, client->Vdec );
}
return 0;
}
int readn(int fd,void *buf,int len )
{
int readsum=0;
int tmp;
while(readsum < len)
{
tmp = read(fd,buf+readsum,len-readsum);
readsum += tmp;
usleep(1000);
}
return readsum;
}
//const unsigned char nalu[4] = {0x00,0x00,0x00,0x01};
//unsigned char rtpbuf[20*1024] = {0};
//unsigned char databuf[20*1024] = {0};
//unsigned char magicnum ;
//unsigned char channel;
void *rtsp_work_thread(void *args)
{
PVHRtspClient obj = (PVHRtspClient)args;
obj->link = LINK_CONNECTING;
int len;
int fd;
time_t tout;
//这里我url是直接传入的,所以不需要在这里生成url!!!
// 先创建访问RTSP的OPTION部分内容
//if( obj->rtsp_url[0] == '\0' )
// sprintf( obj->rtsp_url, "rtsp://%s/", obj->server_ip );
while( !obj->bQuit )
{
if( obj->link != LINK_CONNECTED )
obj->link = LINK_CONNECTING;
obj->stat = RTSP_NONE;
if(obj->link != LINK_CONNECTED && obj->stat == RTSP_NONE )
{
fd = sock_connect( obj->server_ip, obj->server_port[0] );
if( fd < 0 )
{
printf("connect failed! %s \r\n", strerror( errno ));
usleep( 1000*1000 );
obj->link = LINK_DISCONNECT;
continue;
}else{
struct sockaddr_in localaddr;
printf("connect success!\r\n");
//getsockname(fd,&localaddr,sizeof(struct sockaddr));
//printf("local ip->%s:%d\n",inet_ntoa(localaddr.sin_addr),localaddr.sin_port);
obj->link = LINK_CONNECTED;
}
}
obj->fd = fd;
if( SendRequest(obj, RTSP_OPTION ) == 0 )
{
printf("====> option OK!\r\n");
}else
continue;
if( SendRequest(obj, RTSP_DESCRIPT ) == 0 )
{
printf("====> Descriput OK!\r\n");
}else
continue;
if( SendRequest(obj, RTSP_SETUP ) == 0 )
{
printf("====> Setup OK!\r\n");
}else
continue;
if( SendRequest(obj, RTSP_PLAY ) == 0 )
{
printf("Play OK!\r\n");
obj->stat = RTSP_KEEP;
obj->tou = time(NULL) + 60;
}else
{
printf("Play Error!\r\n");
continue;
}
tout = time( NULL );
int flags = fcntl(obj->fd , F_GETFL, 0);
fcntl(obj->fd, F_SETFL, flags & ~O_NONBLOCK);
int frame_error_flag = 0;
int ret;
FILE *fp = fopen("ipc.264","wb+");
if(fp==NULL)
{
perror("fopen") ;
exit(-1);
}
unsigned short rtplength;
while( obj->stat == RTSP_KEEP )
{
// 如果一直连接,则接收码流数据,如果5秒还没收到码流数据,或者1分钟超时,就发送一次心跳包,就发个OPTION帧好了
// if( obj->tou < time(NULL) || ( tout + 5 ) < time( NULL ) )
// {
// if( SendRequest(obj, RTSP_OPTION ) == 0 )
// {
// obj->stat = RTSP_KEEP;
// // each 60s should be reconnect to rtsp send play as the heartbeat
// obj->tou = time(NULL) + 60;
// tout = time( NULL );
// }else{
// printf("has already disconnect!\r\n");
// obj->stat = RTSP_NONE;
// }
// }
if( obj->stream_type == TRANS_TCP )
{
// tcp方式的话直接解析就好了,已经包含了RTP包了
// not supprt now!
if(frame_error_flag)
{
while(1)
{
ret = readn (obj->fd, obj->recv_buf, 1);
if( obj->recv_buf[0] == '$')
{
ret = readn (obj->fd, obj->recv_buf+1, 3);
frame_error_flag = 0;
break;
}
}
}
else
{
ret = readn (obj->fd, obj->recv_buf, 4);
}
if(ret==4)
{
// printf("%#x %#x %#x %#x\n",rtpbuf[0],rtpbuf[1],rtpbuf[2],rtpbuf[3]);
if( obj->recv_buf[0]== '$')
{
//channel = rtpbuf[1];
rtplength = obj->recv_buf[2];
rtplength <<= 8;
rtplength += obj->recv_buf[3];
// printf("len=%d\n",rtplength);
ret = readn (obj->fd, obj->recv_buf, rtplength);
//解析rtp协议
if(RTP_PackParse(obj, obj->recv_buf,rtplength) == 1)
{
RTP_PACK_S *rtpobj = (RTP_PACK_S*) (obj->rtp );
if( RTP_INVALID( obj ) )
{
printf("invlaid obj!\r\n");
//return -1;
}
printf("frame_offset = %d\n",rtpobj->frame_offset);
//保存到文件
//fwrite(nalu ,4, 1, fp);
fwrite(rtpobj->frame, rtpobj->frame_offset, 1, fp);
rtpobj->frame_offset = 0;
}
}
else
{
printf("frame error!\n");
frame_error_flag = 1;
}
}else
{
printf("read 4 bytes error! ret=%d\n",ret );
//不出里不等于4的情况,这个种情况应该极小
}
}else if( obj->stream_type == TRANS_UDP )
{
int maxFd = max( obj->recv_fd[0], obj->recv_fd[1] );
struct timeval tv;
fd_set rfd_set;
int nsel;
FD_ZERO( &rfd_set );
FD_SET( obj->recv_fd[0], &rfd_set );
FD_SET( obj->recv_fd[1], &rfd_set );
tv.tv_sec = 0;
tv.tv_usec = 10 * 1000;
nsel = select( maxFd + 1, &rfd_set, NULL, NULL, &tv );
if ( nsel > 0 && FD_ISSET( obj->recv_fd[1], &rfd_set ) )
{
len = sock_read( obj->recv_fd[1], obj->recv_buf, obj->maxBufSize );
if( len > 4 )
RTCP_PackParse( obj, obj->recv_buf, len );
}else if( nsel > 0 && FD_ISSET( obj->recv_fd[0], &rfd_set ))
{
len = sock_read( obj->recv_fd[0], obj->recv_buf, obj->maxBufSize );
if( len > 4 )
RTP_PackParse( obj, obj->recv_buf, len );
tout = time( NULL );
}
}
}
}
close( obj->fd );
}
// 主码流次码流?现在不支持选择,只是放这边好了
HANDLE RTSP_New( const char *strIP , int maj, const char *usr, const char *pwd , HANDLE Vdec )
{
if ( inet_addr(strIP) == -1 )
{
printf("input ip invalid! :%s \r\n", strIP );
return NULL;
}
RtspClient *client = malloc( sizeof( RtspClient ));
memset( client, 0, sizeof( RtspClient ));
client->magic = MAGIC_NUM;
strcpy( client->server_ip, strIP );
if( usr )
strcpy( client->authName, usr );
if( pwd )
strcpy( client->authPwd , pwd );
client->maxBufSize = 5*1024;
client->recv_buf = malloc(client->maxBufSize);
client->Vdec = Vdec;
HANDLE rtp = RTP_Init();
client->rtp = rtp;
pthread_create( &client->threadID, NULL, rtsp_work_thread, (void *)client );
return client;
}
/*我加的新函数*/
HANDLE RTSP_New1( RtspClient *client)
{
pthread_create( &client->threadID, NULL, rtsp_work_thread, (void *)client );
return client;
}
void RTSP_Delete( HANDLE handle )
{
RtspClient *obj = (RtspClient*)handle;
if( RTSP_INVALID( obj ) )
return;
obj->bQuit = 1;
if( obj->recv_buf )
free( obj->recv_buf );
pthread_cancel( obj->threadID );
pthread_join( obj->threadID, NULL );
}
RtspClient client;
int main(int argc, char *argv[])
{
if(argc != 2)
{
printf("error! useage : prog url\n");
exit(-1);
}
printf("%s\n",argv[1]);
char username[20] = {0};
char password[20] = {0};
char ipaddr[20] = {0};
char port[20] = {0};
sscanf(argv[1],"rtsp://%[^:]:%[^@]@%[^:]:%[^/]",username,password,ipaddr,port);
puts(username);
puts(password);
puts(ipaddr);
puts(port);
client.magic = MAGIC_NUM;
strcpy(client.server_ip, ipaddr);
client.server_port[0] = atoi(port);
if(strlen(username)!=0)
strcpy(client.authName,username);
if(strlen(password)!=0)
strcpy(client.authPwd,password);
client.maxBufSize = 10*1024;
client.recv_buf = malloc(client.maxBufSize);
client.Vdec = 0;
client.stream_type = TRANS_TCP;
HANDLE rtp = RTP_Init();
client.rtp = rtp;
strcpy(client.rtsp_url,argv[1]);
HANDLE rtsp = RTSP_New1( &client );
while( 1 )
usleep( 1 );
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/eyhxh/rtspclient.git
[email protected]:eyhxh/rtspclient.git
eyhxh
rtspclient
rtspclient
master

搜索帮助

0d507c66 1850385 C8b1a773 1850385