📄 rtsp.c
字号:
/***************************************************************************** * rtsp.c: minimalistic implementation of rtsp protocol. * Not RFC 2326 compilant yet and only handle REAL RTSP. ***************************************************************************** * Copyright (C) 2002-2004 the xine project * Copyright (C) 2005 VideoLAN * $Id$ * * Authors: Gildas Bazin <gbazin@videolan.org> * Adapted from xine which itself adapted it from joschkas real tools. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include "rtsp.h"#define BUF_SIZE 4096#define HEADER_SIZE 1024#define MAX_FIELDS 256struct rtsp_s { int s; char *host; int port; char *path; char *mrl; char *user_agent; char *server; unsigned int server_state; uint32_t server_caps; unsigned int cseq; char *session; char *answers[MAX_FIELDS]; /* data of last message */ char *scheduled[MAX_FIELDS]; /* will be sent with next message */};/* * constants */const char rtsp_protocol_version[]="RTSP/1.0";/* server states */#define RTSP_CONNECTED 1#define RTSP_INIT 2#define RTSP_READY 4#define RTSP_PLAYING 8#define RTSP_RECORDING 16/* server capabilities */#define RTSP_OPTIONS 0x001#define RTSP_DESCRIBE 0x002#define RTSP_ANNOUNCE 0x004#define RTSP_SETUP 0x008#define RTSP_GET_PARAMETER 0x010#define RTSP_SET_PARAMETER 0x020#define RTSP_TEARDOWN 0x040#define RTSP_PLAY 0x080#define RTSP_RECORD 0x100/* * rtsp_get gets a line from stream * and returns a null terminated string (must be freed). */ static char *rtsp_get( rtsp_client_t *rtsp ){ char *psz_buffer = malloc( BUF_SIZE ); char *psz_string = NULL; if( rtsp->pf_read_line( rtsp->p_userdata, (uint8_t*)psz_buffer, (unsigned int)BUF_SIZE ) >= 0 ) { //printf( "<< '%s'\n", psz_buffer ); psz_string = strdup( psz_buffer ); } free( psz_buffer ); return psz_string;}/* * rtsp_put puts a line on stream */static int rtsp_put( rtsp_client_t *rtsp, const char *psz_string ){ unsigned int i_buffer = strlen( psz_string ); char *psz_buffer = malloc( i_buffer + 3 ); int i_ret; strcpy( psz_buffer, psz_string ); psz_buffer[i_buffer] = '\r'; psz_buffer[i_buffer+1] = '\n'; psz_buffer[i_buffer+2] = 0; i_ret = rtsp->pf_write( rtsp->p_userdata, (uint8_t*)psz_buffer, i_buffer + 2 ); free( psz_buffer ); return i_ret;}/* * extract server status code */static int rtsp_get_status_code( rtsp_client_t *rtsp, const char *psz_string ){ char psz_buffer[4]; int i_code = 0; if( !strncmp( psz_string, "RTSP/1.0", sizeof("RTSP/1.0") - 1 ) ) { memcpy( psz_buffer, psz_string + sizeof("RTSP/1.0"), 3 ); psz_buffer[3] = 0; i_code = atoi( psz_buffer ); } else if( !strncmp( psz_string, "SET_PARAMETER", 8 ) ) { return RTSP_STATUS_SET_PARAMETER; } if( i_code != 200 ) { //fprintf( stderr, "librtsp: server responds: '%s'\n", psz_string ); } return i_code;}/* * send a request */static int rtsp_send_request( rtsp_client_t *rtsp, const char *psz_type, const char *psz_what ){ char **ppsz_payload = rtsp->p_private->scheduled; char *psz_buffer; int i_ret; psz_buffer = malloc( strlen(psz_type) + strlen(psz_what) + sizeof("RTSP/1.0") + 2 ); sprintf( psz_buffer, "%s %s %s", psz_type, psz_what, "RTSP/1.0" ); i_ret = rtsp_put( rtsp, psz_buffer ); free( psz_buffer ); if( ppsz_payload ) while( *ppsz_payload ) { rtsp_put( rtsp, *ppsz_payload ); ppsz_payload++; } rtsp_put( rtsp, "" ); rtsp_unschedule_all( rtsp ); return i_ret;}/* * schedule standard fields */static void rtsp_schedule_standard( rtsp_client_t *rtsp ){ char tmp[17]; sprintf( tmp, "Cseq: %u", rtsp->p_private->cseq); rtsp_schedule_field( rtsp, tmp ); if( rtsp->p_private->session ) { char *buf; buf = malloc( strlen(rtsp->p_private->session) + 15 ); sprintf( buf, "Session: %s", rtsp->p_private->session ); rtsp_schedule_field( rtsp, buf ); free( buf ); }}/* * get the answers, if server responses with something != 200, return NULL */static int rtsp_get_answers( rtsp_client_t *rtsp ){ char *answer = NULL; unsigned int answer_seq; char **answer_ptr = rtsp->p_private->answers; int code; int ans_count = 0; answer = rtsp_get( rtsp ); if( !answer ) return 0; code = rtsp_get_status_code( rtsp, answer ); free( answer ); rtsp_free_answers( rtsp ); do { /* while we get answer lines */ answer = rtsp_get( rtsp ); if( !answer ) return 0; if( !strncasecmp( answer, "Cseq:", 5 ) ) { sscanf( answer, "%*s %u", &answer_seq ); if( rtsp->p_private->cseq != answer_seq ) { //fprintf( stderr, "warning: Cseq mismatch. got %u, assumed %u", // answer_seq, rtsp->p_private->cseq ); rtsp->p_private->cseq = answer_seq; } } if( !strncasecmp( answer, "Server:", 7 ) ) { char *buf = malloc( strlen(answer) ); sscanf( answer, "%*s %s", buf ); free( rtsp->p_private->server ); rtsp->p_private->server = buf; } if( !strncasecmp( answer, "Session:", 8 ) ) { char *buf = malloc( strlen(answer) ); sscanf( answer, "%*s %s", buf ); if( rtsp->p_private->session ) { if( strcmp( buf, rtsp->p_private->session ) ) { //fprintf( stderr, // "rtsp: warning: setting NEW session: %s\n", buf ); free( rtsp->p_private->session ); rtsp->p_private->session = strdup( buf ); } } else { //fprintf( stderr, "setting session id to: %s\n", buf ); rtsp->p_private->session = strdup( buf ); } free( buf ); } *answer_ptr = answer; answer_ptr++; } while( (strlen(answer) != 0) && (++ans_count < MAX_FIELDS) ); rtsp->p_private->cseq++; *answer_ptr = NULL; rtsp_schedule_standard( rtsp ); return code;}/* * send an ok message */int rtsp_send_ok( rtsp_client_t *rtsp ){ char cseq[16]; rtsp_put( rtsp, "RTSP/1.0 200 OK" ); sprintf( cseq, "CSeq: %u", rtsp->p_private->cseq ); rtsp_put( rtsp, cseq ); rtsp_put( rtsp, "" ); return 0;}/* * implementation of must-have rtsp requests; functions return * server status code. */int rtsp_request_options( rtsp_client_t *rtsp, const char *what ){ char *buf; if( what ) buf = strdup(what); else { buf = malloc( strlen(rtsp->p_private->host) + 16 ); sprintf( buf, "rtsp://%s:%i", rtsp->p_private->host, rtsp->p_private->port ); } rtsp_send_request( rtsp, "OPTIONS", buf ); free( buf ); return rtsp_get_answers( rtsp );}int rtsp_request_describe( rtsp_client_t *rtsp, const char *what ){ char *buf; if( what ) { buf = strdup(what); } else { buf = malloc( strlen(rtsp->p_private->host) + strlen(rtsp->p_private->path) + 16 ); sprintf( buf, "rtsp://%s:%i/%s", rtsp->p_private->host, rtsp->p_private->port, rtsp->p_private->path ); } rtsp_send_request( rtsp, "DESCRIBE", buf ); free( buf ); return rtsp_get_answers( rtsp );}int rtsp_request_setup( rtsp_client_t *rtsp, const char *what ){ rtsp_send_request( rtsp, "SETUP", what ); return rtsp_get_answers( rtsp );}int rtsp_request_setparameter( rtsp_client_t *rtsp, const char *what ){ char *buf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -