From 8736900818047d0dc46b5d552bd66482917f04f0 Mon Sep 17 00:00:00 2001 From: Laurent Aimar Date: Sun, 3 Aug 2003 15:25:33 +0000 Subject: [PATCH] * sdp: begining of a SDP parser. It won't let you play anything for now, it just does (incomplete) parsing. --- modules/demux/sdp.c | 454 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 454 insertions(+) create mode 100644 modules/demux/sdp.c diff --git a/modules/demux/sdp.c b/modules/demux/sdp.c new file mode 100644 index 0000000000..9cd6d5f44d --- /dev/null +++ b/modules/demux/sdp.c @@ -0,0 +1,454 @@ +/***************************************************************************** + * sdp.c: SDP parser and builtin UDP/RTP/RTSP + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: sdp.c,v 1.1 2003/08/03 15:25:33 fenrir Exp $ + * + * Authors: Laurent Aimar + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include /* malloc(), free() */ + +#include +#include + +#include + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close( vlc_object_t * ); + +vlc_module_begin(); + set_description( _("SDP demuxer + UDP/RTP/RTSP") ); + set_capability( "demux", 100 ); + set_callbacks( Open, Close ); + add_shortcut( "sdp" ); +vlc_module_end(); + + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Demux ( input_thread_t * ); + +typedef struct +{ + char *psz_media; + char *psz_description; + char *psz_connection; + char *psz_bandwith; + char *psz_key; + +} sdp_media_t; + +typedef struct +{ + char *psz_origin; + char *psz_session; + char *psz_description; + char *psz_uri; + char *psz_email; + char *psz_phone; + char *psz_connection; + char *psz_bandwith; + char *psz_key; + char *psz_timezone; + + int i_media; + sdp_media_t *media; + +} sdp_session_t; + +typedef struct +{ + int i_session; + sdp_session_t *session; + +} sdp_t; + +struct demux_sys_t +{ + stream_t *s; + + sdp_t *p_sdp; +}; + +static sdp_t *sdp_Parse ( char * ); +static void sdp_Dump ( input_thread_t *, sdp_t * ); +static void sdp_Release( sdp_t * ); + +/***************************************************************************** + * Open: + *****************************************************************************/ +static int Open( vlc_object_t * p_this ) +{ + input_thread_t *p_input = (input_thread_t *)p_this; + demux_sys_t *p_sys; + uint8_t *p_peek; + + int i_sdp; + int i_sdp_max; + char *psz_sdp; + + /* See if it looks like a SDP + v, o, s fields are mandatory and in this order */ + if( input_Peek( p_input, &p_peek, 7 ) < 7 ) + { + msg_Err( p_input, "cannot peek" ); + return VLC_EGENERIC; + } + if( strncmp( p_peek, "v=0\r\no=", 7 ) && + strncmp( p_peek, "v=0\no=", 6 ) ) + { + msg_Err( p_input, "SDP module discarded" ); + return VLC_EGENERIC; + } + + /* Set input_thread_t fields */ + p_input->pf_demux = Demux; + p_input->p_demux_data = p_sys = malloc( sizeof( demux_sys_t ) ); + + if( ( p_sys->s = stream_OpenInput( p_input ) ) == NULL ) + { + msg_Err( p_input, "cannot create stream" ); + goto error; + } + + /* Read the complete SDP file */ + i_sdp = 0; + i_sdp_max = 1024; + psz_sdp = malloc( i_sdp_max ); + for( ;; ) + { + int i_read; + + i_read = stream_Read( p_sys->s, &psz_sdp[i_sdp], i_sdp_max - i_sdp -1 ); + if( i_read <= i_sdp_max - i_sdp -1 ) + { + if( i_read > 0 ) + { + i_sdp += i_read; + } + break; + } + i_sdp += i_read; + i_sdp_max += 1024; + psz_sdp = realloc( psz_sdp, i_sdp_max ); + } + psz_sdp[i_sdp] = '\0'; + + if( strlen( psz_sdp ) <= 0 ) + { + msg_Err( p_input, "cannot read SDP file" ); + goto error; + + } + + if( ( p_sys->p_sdp = sdp_Parse( psz_sdp ) ) == NULL ) + { + msg_Err( p_input, "cannot parse SDP" ); + goto error; + } + sdp_Dump( p_input, p_sys->p_sdp ); + + return VLC_SUCCESS; + +error: + if( p_sys->s ) + { + stream_Release( p_sys->s ); + } + free( p_sys ); + return VLC_EGENERIC; +} + +/***************************************************************************** + * Close: frees unused data + *****************************************************************************/ +static void Close( vlc_object_t *p_this ) +{ + input_thread_t *p_input = (input_thread_t *)p_this; + demux_sys_t *p_sys = p_input->p_demux_data; + + sdp_Release( p_sys->p_sdp ); + free( p_sys ); +} + +/***************************************************************************** + * Demux: reads and demuxes data packets + ***************************************************************************** + * Returns -1 in case of error, 0 in case of EOF, 1 otherwise + *****************************************************************************/ +static int Demux ( input_thread_t *p_input ) +{ + + return 0; +} + +/***************************************************************************** + * + *****************************************************************************/ + +/***************************************************************************** + * SDP Parser + *****************************************************************************/ +static int sdp_GetLine( char **ppsz_sdp, char *p_com, char **pp_arg ) +{ + char *p = *ppsz_sdp; + char *p_end; + int i_size; + + if( p[0] < 'a' || p[0] > 'z' || p[1] != '=' ) + { + return VLC_EGENERIC; + } + + *p_com = p[0]; + + if( ( p_end = strstr( p, "\n" ) ) == NULL ) + { + p_end = p + strlen( p ); + } + else + { + while( *p_end == '\n' || *p_end == '\r' ) + { + p_end--; + } + p_end++; + } + + i_size = p_end - &p[2]; + *pp_arg = malloc( i_size + 1 ); + memcpy( *pp_arg, &p[2], i_size ); + (*pp_arg)[i_size] = '\0'; + + while( *p_end == '\r' || *p_end == '\n' ) + { + p_end++; + } + *ppsz_sdp = p_end; + return VLC_SUCCESS; +} + +static sdp_t *sdp_Parse ( char *psz_sdp ) +{ + sdp_t *sdp = malloc( sizeof( sdp_t ) ); + + sdp->i_session = -1; + sdp->session = NULL; + + for( ;; ) + { +#define p_session (&sdp->session[sdp->i_session]) +#define p_media (&p_session->media[p_session->i_media]) + char com, *psz; + + if( sdp_GetLine( &psz_sdp, &com, &psz ) ) + { + break; + } + fprintf( stderr, "com=%c arg=%s\n", com, psz ); + if( sdp->i_session < 0 && ( com !='v' || strcmp( psz, "0" ) ) ) + { + break; + } + switch( com ) + { + case 'v': + fprintf( stderr, "New session added\n" ); + if( sdp->i_session != -1 ) + { + p_session->i_media++; + } + /* Add a new session */ + sdp->i_session++; + sdp->session = + realloc( sdp->session, + (sdp->i_session + 1)*sizeof(sdp_session_t) ); + p_session->psz_origin = NULL; + p_session->psz_session = NULL; + p_session->psz_description= NULL; + p_session->psz_uri = NULL; + p_session->psz_email = NULL; + p_session->psz_phone = NULL; + p_session->psz_connection = NULL; + p_session->psz_bandwith = NULL; + p_session->psz_key = NULL; + p_session->psz_timezone = NULL; + p_session->i_media = -1; + p_session->media = NULL; + break; + case 'm': + fprintf( stderr, "New media added\n" ); + p_session->i_media++; + p_session->media = + realloc( p_session->media, + (p_session->i_media + 1)*sizeof( sdp_media_t ) ); + p_media->psz_media = strdup( psz ); + p_media->psz_description= NULL; + p_media->psz_connection = NULL; + p_media->psz_bandwith = NULL; + p_media->psz_key = NULL; + break; + case 'o': + p_session->psz_origin = strdup( psz ); + break; + case 's': + p_session->psz_session = strdup( psz ); + break; + case 'i': + if( p_session->i_media != -1 ) + { + p_media->psz_description = strdup( psz ); + } + else + { + p_session->psz_description = strdup( psz ); + } + break; + case 'u': + p_session->psz_uri = strdup( psz ); + break; + case 'e': + p_session->psz_email = strdup( psz ); + break; + case 'p': + p_session->psz_phone = strdup( psz ); + break; + case 'c': + if( p_session->i_media != -1 ) + { + p_media->psz_connection = strdup( psz ); + } + else + { + p_session->psz_connection = strdup( psz ); + } + break; + case 'b': + if( p_session->i_media != -1 ) + { + p_media->psz_bandwith = strdup( psz ); + } + else + { + p_session->psz_bandwith = strdup( psz ); + } + break; + case 'k': + if( p_session->i_media != -1 ) + { + p_media->psz_key = strdup( psz ); + } + else + { + p_session->psz_key = strdup( psz ); + } + break; + case 'z': + p_session->psz_timezone = strdup( psz ); + break; + + default: + fprintf( stderr, "unhandled com=%c\n", com ); + break; + } + +#undef p_session + } + + if( sdp->i_session < 0 ) + { + free( sdp ); + return NULL; + } + sdp->session[sdp->i_session].i_media++; + sdp->i_session++; + + return sdp; +} +static void sdp_Release( sdp_t *p_sdp ) +{ +#define FREE( p ) if( p ) { free( p ) ; (p) = NULL; } + int i, j; + for( i = 0; i < p_sdp->i_session; i++ ) + { + FREE( p_sdp->session[i].psz_origin ); + FREE( p_sdp->session[i].psz_session ); + FREE( p_sdp->session[i].psz_description ); + FREE( p_sdp->session[i].psz_uri ); + FREE( p_sdp->session[i].psz_email ); + FREE( p_sdp->session[i].psz_phone ); + FREE( p_sdp->session[i].psz_connection ); + FREE( p_sdp->session[i].psz_bandwith ); + FREE( p_sdp->session[i].psz_key ); + FREE( p_sdp->session[i].psz_timezone ); + + for( j = 0; j < p_sdp->session[i].i_media; j++ ) + { + FREE( p_sdp->session[i].media[j].psz_media ); + FREE( p_sdp->session[i].media[j].psz_description ); + FREE( p_sdp->session[i].media[j].psz_connection ); + FREE( p_sdp->session[i].media[j].psz_bandwith ); + FREE( p_sdp->session[i].media[j].psz_key ); + } + FREE( p_sdp->session[i].media); + } + FREE( p_sdp->session ); + free( p_sdp ); +#undef FREE +} + +static void sdp_Dump ( input_thread_t *p_input, sdp_t *p_sdp ) +{ + int i, j; +#define PRINTS( var, fmt ) \ + if( var ) { msg_Dbg( p_input, " - " fmt " : %s", var ); } +#define PRINTM( var, fmt ) \ + if( var ) { msg_Dbg( p_input, " - " fmt " : %s", var ); } + + for( i = 0; i < p_sdp->i_session; i++ ) + { + msg_Dbg( p_input, "session[%d]", i ); + PRINTS( p_sdp->session[i].psz_origin, "Origin" ); + PRINTS( p_sdp->session[i].psz_session, "Session" ); + PRINTS( p_sdp->session[i].psz_description, "Description" ); + PRINTS( p_sdp->session[i].psz_uri, "URI" ); + PRINTS( p_sdp->session[i].psz_email, "e-mail" ); + PRINTS( p_sdp->session[i].psz_phone, "Phone" ); + PRINTS( p_sdp->session[i].psz_connection, "Connection" ); + PRINTS( p_sdp->session[i].psz_bandwith, "Bandwith" ); + PRINTS( p_sdp->session[i].psz_key, "Key" ); + PRINTS( p_sdp->session[i].psz_timezone, "TimeZone" ); + for( j = 0; j < p_sdp->session[i].i_media; j++ ) + { + msg_Dbg( p_input, " - media[%d]", j ); + PRINTM( p_sdp->session[i].media[j].psz_media, "Name" ); + PRINTM( p_sdp->session[i].media[j].psz_description, "Description" ); + PRINTM( p_sdp->session[i].media[j].psz_connection, "Connection" ); + PRINTM( p_sdp->session[i].media[j].psz_bandwith, "Bandwith" ); + PRINTM( p_sdp->session[i].media[j].psz_key, "Key" ); + } + } +#undef PRINTS +} -- 2.39.2