1 /*****************************************************************************
2 * sdp.c: SDP parser and builtin UDP/RTP/RTSP
3 *****************************************************************************
4 * Copyright (C) 2001 VideoLAN
5 * $Id: sdp.c,v 1.1 2003/08/03 15:25:33 fenrir Exp $
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
30 #include <vlc/input.h>
34 /*****************************************************************************
36 *****************************************************************************/
37 static int Open ( vlc_object_t * );
38 static void Close( vlc_object_t * );
41 set_description( _("SDP demuxer + UDP/RTP/RTSP") );
42 set_capability( "demux", 100 );
43 set_callbacks( Open, Close );
44 add_shortcut( "sdp" );
48 /*****************************************************************************
50 *****************************************************************************/
51 static int Demux ( input_thread_t * );
56 char *psz_description;
67 char *psz_description;
84 sdp_session_t *session;
95 static sdp_t *sdp_Parse ( char * );
96 static void sdp_Dump ( input_thread_t *, sdp_t * );
97 static void sdp_Release( sdp_t * );
99 /*****************************************************************************
101 *****************************************************************************/
102 static int Open( vlc_object_t * p_this )
104 input_thread_t *p_input = (input_thread_t *)p_this;
112 /* See if it looks like a SDP
113 v, o, s fields are mandatory and in this order */
114 if( input_Peek( p_input, &p_peek, 7 ) < 7 )
116 msg_Err( p_input, "cannot peek" );
119 if( strncmp( p_peek, "v=0\r\no=", 7 ) &&
120 strncmp( p_peek, "v=0\no=", 6 ) )
122 msg_Err( p_input, "SDP module discarded" );
126 /* Set input_thread_t fields */
127 p_input->pf_demux = Demux;
128 p_input->p_demux_data = p_sys = malloc( sizeof( demux_sys_t ) );
130 if( ( p_sys->s = stream_OpenInput( p_input ) ) == NULL )
132 msg_Err( p_input, "cannot create stream" );
136 /* Read the complete SDP file */
139 psz_sdp = malloc( i_sdp_max );
144 i_read = stream_Read( p_sys->s, &psz_sdp[i_sdp], i_sdp_max - i_sdp -1 );
145 if( i_read <= i_sdp_max - i_sdp -1 )
155 psz_sdp = realloc( psz_sdp, i_sdp_max );
157 psz_sdp[i_sdp] = '\0';
159 if( strlen( psz_sdp ) <= 0 )
161 msg_Err( p_input, "cannot read SDP file" );
166 if( ( p_sys->p_sdp = sdp_Parse( psz_sdp ) ) == NULL )
168 msg_Err( p_input, "cannot parse SDP" );
171 sdp_Dump( p_input, p_sys->p_sdp );
178 stream_Release( p_sys->s );
184 /*****************************************************************************
185 * Close: frees unused data
186 *****************************************************************************/
187 static void Close( vlc_object_t *p_this )
189 input_thread_t *p_input = (input_thread_t *)p_this;
190 demux_sys_t *p_sys = p_input->p_demux_data;
192 sdp_Release( p_sys->p_sdp );
196 /*****************************************************************************
197 * Demux: reads and demuxes data packets
198 *****************************************************************************
199 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
200 *****************************************************************************/
201 static int Demux ( input_thread_t *p_input )
207 /*****************************************************************************
209 *****************************************************************************/
211 /*****************************************************************************
213 *****************************************************************************/
214 static int sdp_GetLine( char **ppsz_sdp, char *p_com, char **pp_arg )
220 if( p[0] < 'a' || p[0] > 'z' || p[1] != '=' )
227 if( ( p_end = strstr( p, "\n" ) ) == NULL )
229 p_end = p + strlen( p );
233 while( *p_end == '\n' || *p_end == '\r' )
240 i_size = p_end - &p[2];
241 *pp_arg = malloc( i_size + 1 );
242 memcpy( *pp_arg, &p[2], i_size );
243 (*pp_arg)[i_size] = '\0';
245 while( *p_end == '\r' || *p_end == '\n' )
253 static sdp_t *sdp_Parse ( char *psz_sdp )
255 sdp_t *sdp = malloc( sizeof( sdp_t ) );
262 #define p_session (&sdp->session[sdp->i_session])
263 #define p_media (&p_session->media[p_session->i_media])
266 if( sdp_GetLine( &psz_sdp, &com, &psz ) )
270 fprintf( stderr, "com=%c arg=%s\n", com, psz );
271 if( sdp->i_session < 0 && ( com !='v' || strcmp( psz, "0" ) ) )
278 fprintf( stderr, "New session added\n" );
279 if( sdp->i_session != -1 )
281 p_session->i_media++;
283 /* Add a new session */
286 realloc( sdp->session,
287 (sdp->i_session + 1)*sizeof(sdp_session_t) );
288 p_session->psz_origin = NULL;
289 p_session->psz_session = NULL;
290 p_session->psz_description= NULL;
291 p_session->psz_uri = NULL;
292 p_session->psz_email = NULL;
293 p_session->psz_phone = NULL;
294 p_session->psz_connection = NULL;
295 p_session->psz_bandwith = NULL;
296 p_session->psz_key = NULL;
297 p_session->psz_timezone = NULL;
298 p_session->i_media = -1;
299 p_session->media = NULL;
302 fprintf( stderr, "New media added\n" );
303 p_session->i_media++;
305 realloc( p_session->media,
306 (p_session->i_media + 1)*sizeof( sdp_media_t ) );
307 p_media->psz_media = strdup( psz );
308 p_media->psz_description= NULL;
309 p_media->psz_connection = NULL;
310 p_media->psz_bandwith = NULL;
311 p_media->psz_key = NULL;
314 p_session->psz_origin = strdup( psz );
317 p_session->psz_session = strdup( psz );
320 if( p_session->i_media != -1 )
322 p_media->psz_description = strdup( psz );
326 p_session->psz_description = strdup( psz );
330 p_session->psz_uri = strdup( psz );
333 p_session->psz_email = strdup( psz );
336 p_session->psz_phone = strdup( psz );
339 if( p_session->i_media != -1 )
341 p_media->psz_connection = strdup( psz );
345 p_session->psz_connection = strdup( psz );
349 if( p_session->i_media != -1 )
351 p_media->psz_bandwith = strdup( psz );
355 p_session->psz_bandwith = strdup( psz );
359 if( p_session->i_media != -1 )
361 p_media->psz_key = strdup( psz );
365 p_session->psz_key = strdup( psz );
369 p_session->psz_timezone = strdup( psz );
373 fprintf( stderr, "unhandled com=%c\n", com );
380 if( sdp->i_session < 0 )
385 sdp->session[sdp->i_session].i_media++;
390 static void sdp_Release( sdp_t *p_sdp )
392 #define FREE( p ) if( p ) { free( p ) ; (p) = NULL; }
394 for( i = 0; i < p_sdp->i_session; i++ )
396 FREE( p_sdp->session[i].psz_origin );
397 FREE( p_sdp->session[i].psz_session );
398 FREE( p_sdp->session[i].psz_description );
399 FREE( p_sdp->session[i].psz_uri );
400 FREE( p_sdp->session[i].psz_email );
401 FREE( p_sdp->session[i].psz_phone );
402 FREE( p_sdp->session[i].psz_connection );
403 FREE( p_sdp->session[i].psz_bandwith );
404 FREE( p_sdp->session[i].psz_key );
405 FREE( p_sdp->session[i].psz_timezone );
407 for( j = 0; j < p_sdp->session[i].i_media; j++ )
409 FREE( p_sdp->session[i].media[j].psz_media );
410 FREE( p_sdp->session[i].media[j].psz_description );
411 FREE( p_sdp->session[i].media[j].psz_connection );
412 FREE( p_sdp->session[i].media[j].psz_bandwith );
413 FREE( p_sdp->session[i].media[j].psz_key );
415 FREE( p_sdp->session[i].media);
417 FREE( p_sdp->session );
422 static void sdp_Dump ( input_thread_t *p_input, sdp_t *p_sdp )
425 #define PRINTS( var, fmt ) \
426 if( var ) { msg_Dbg( p_input, " - " fmt " : %s", var ); }
427 #define PRINTM( var, fmt ) \
428 if( var ) { msg_Dbg( p_input, " - " fmt " : %s", var ); }
430 for( i = 0; i < p_sdp->i_session; i++ )
432 msg_Dbg( p_input, "session[%d]", i );
433 PRINTS( p_sdp->session[i].psz_origin, "Origin" );
434 PRINTS( p_sdp->session[i].psz_session, "Session" );
435 PRINTS( p_sdp->session[i].psz_description, "Description" );
436 PRINTS( p_sdp->session[i].psz_uri, "URI" );
437 PRINTS( p_sdp->session[i].psz_email, "e-mail" );
438 PRINTS( p_sdp->session[i].psz_phone, "Phone" );
439 PRINTS( p_sdp->session[i].psz_connection, "Connection" );
440 PRINTS( p_sdp->session[i].psz_bandwith, "Bandwith" );
441 PRINTS( p_sdp->session[i].psz_key, "Key" );
442 PRINTS( p_sdp->session[i].psz_timezone, "TimeZone" );
443 for( j = 0; j < p_sdp->session[i].i_media; j++ )
445 msg_Dbg( p_input, " - media[%d]", j );
446 PRINTM( p_sdp->session[i].media[j].psz_media, "Name" );
447 PRINTM( p_sdp->session[i].media[j].psz_description, "Description" );
448 PRINTM( p_sdp->session[i].media[j].psz_connection, "Connection" );
449 PRINTM( p_sdp->session[i].media[j].psz_bandwith, "Bandwith" );
450 PRINTM( p_sdp->session[i].media[j].psz_key, "Key" );