]> git.sesse.net Git - vlc/blob - modules/demux/sdp.c
* sdp: begining of a SDP parser. It won't let you play anything for
[vlc] / modules / demux / sdp.c
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 $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31
32 #include <ninput.h>
33
34 /*****************************************************************************
35  * Module descriptor
36  *****************************************************************************/
37 static int  Open  ( vlc_object_t * );
38 static void Close( vlc_object_t * );
39
40 vlc_module_begin();
41     set_description( _("SDP demuxer + UDP/RTP/RTSP") );
42     set_capability( "demux", 100 );
43     set_callbacks( Open, Close );
44     add_shortcut( "sdp" );
45 vlc_module_end();
46
47
48 /*****************************************************************************
49  * Local prototypes
50  *****************************************************************************/
51 static int  Demux ( input_thread_t * );
52
53 typedef struct
54 {
55     char    *psz_media;
56     char    *psz_description;
57     char    *psz_connection;
58     char    *psz_bandwith;
59     char    *psz_key;
60
61 } sdp_media_t;
62
63 typedef struct
64 {
65     char    *psz_origin;
66     char    *psz_session;
67     char    *psz_description;
68     char    *psz_uri;
69     char    *psz_email;
70     char    *psz_phone;
71     char    *psz_connection;
72     char    *psz_bandwith;
73     char    *psz_key;
74     char    *psz_timezone;
75
76     int         i_media;
77     sdp_media_t *media;
78
79 } sdp_session_t;
80
81 typedef struct
82 {
83     int           i_session;
84     sdp_session_t *session;
85
86 } sdp_t;
87
88 struct demux_sys_t
89 {
90     stream_t *s;
91
92     sdp_t    *p_sdp;
93 };
94
95 static sdp_t *sdp_Parse  ( char * );
96 static void  sdp_Dump    ( input_thread_t *, sdp_t * );
97 static void   sdp_Release( sdp_t * );
98
99 /*****************************************************************************
100  * Open:
101  *****************************************************************************/
102 static int Open( vlc_object_t * p_this )
103 {
104     input_thread_t *p_input = (input_thread_t *)p_this;
105     demux_sys_t    *p_sys;
106     uint8_t        *p_peek;
107
108     int            i_sdp;
109     int            i_sdp_max;
110     char           *psz_sdp;
111
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 )
115     {
116         msg_Err( p_input, "cannot peek" );
117         return VLC_EGENERIC;
118     }
119     if( strncmp( p_peek, "v=0\r\no=", 7 ) &&
120         strncmp( p_peek, "v=0\no=", 6 ) )
121     {
122         msg_Err( p_input, "SDP module discarded" );
123         return VLC_EGENERIC;
124     }
125
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 ) );
129
130     if( ( p_sys->s = stream_OpenInput( p_input ) ) == NULL )
131     {
132         msg_Err( p_input, "cannot create stream" );
133         goto error;
134     }
135
136     /* Read the complete SDP file */
137     i_sdp = 0;
138     i_sdp_max = 1024;
139     psz_sdp = malloc( i_sdp_max );
140     for( ;; )
141     {
142         int i_read;
143
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 )
146         {
147             if( i_read > 0 )
148             {
149                 i_sdp += i_read;
150             }
151             break;
152         }
153         i_sdp += i_read;
154         i_sdp_max += 1024;
155         psz_sdp = realloc( psz_sdp, i_sdp_max );
156     }
157     psz_sdp[i_sdp] = '\0';
158
159     if( strlen( psz_sdp ) <= 0 )
160     {
161         msg_Err( p_input, "cannot read SDP file" );
162         goto error;
163
164     }
165
166     if( ( p_sys->p_sdp = sdp_Parse( psz_sdp ) ) == NULL )
167     {
168         msg_Err( p_input, "cannot parse SDP" );
169         goto error;
170     }
171     sdp_Dump( p_input, p_sys->p_sdp );
172
173     return VLC_SUCCESS;
174
175 error:
176     if( p_sys->s )
177     {
178         stream_Release( p_sys->s );
179     }
180     free( p_sys );
181     return VLC_EGENERIC;
182 }
183
184 /*****************************************************************************
185  * Close: frees unused data
186  *****************************************************************************/
187 static void Close( vlc_object_t *p_this )
188 {
189     input_thread_t *p_input = (input_thread_t *)p_this;
190     demux_sys_t    *p_sys = p_input->p_demux_data;
191
192     sdp_Release( p_sys->p_sdp );
193     free( p_sys );
194 }
195
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 )
202 {
203
204     return 0;
205 }
206
207 /*****************************************************************************
208  *
209  *****************************************************************************/
210
211 /*****************************************************************************
212  *  SDP Parser
213  *****************************************************************************/
214 static int   sdp_GetLine( char **ppsz_sdp, char *p_com, char **pp_arg )
215 {
216     char *p = *ppsz_sdp;
217     char *p_end;
218     int  i_size;
219
220     if( p[0] < 'a' || p[0] > 'z' || p[1] != '=' )
221     {
222         return VLC_EGENERIC;
223     }
224
225     *p_com = p[0];
226
227     if( ( p_end = strstr( p, "\n" ) ) == NULL )
228     {
229         p_end = p + strlen( p );
230     }
231     else
232     {
233         while( *p_end == '\n' || *p_end == '\r' )
234         {
235             p_end--;
236         }
237         p_end++;
238     }
239
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';
244
245     while( *p_end == '\r' || *p_end == '\n' )
246     {
247         p_end++;
248     }
249     *ppsz_sdp = p_end;
250     return VLC_SUCCESS;
251 }
252
253 static sdp_t *sdp_Parse  ( char *psz_sdp )
254 {
255     sdp_t *sdp = malloc( sizeof( sdp_t ) );
256
257     sdp->i_session = -1;
258     sdp->session   = NULL;
259
260     for( ;; )
261     {
262 #define p_session (&sdp->session[sdp->i_session])
263 #define p_media   (&p_session->media[p_session->i_media])
264         char com, *psz;
265
266         if( sdp_GetLine( &psz_sdp, &com, &psz ) )
267         {
268             break;
269         }
270         fprintf( stderr, "com=%c arg=%s\n", com, psz );
271         if( sdp->i_session < 0 && ( com !='v' || strcmp( psz, "0" ) ) )
272         {
273             break;
274         }
275         switch( com )
276         {
277             case 'v':
278                 fprintf( stderr, "New session added\n" );
279                 if( sdp->i_session != -1 )
280                 {
281                     p_session->i_media++;
282                 }
283                 /* Add a new session */
284                 sdp->i_session++;
285                 sdp->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;
300                 break;
301             case 'm':
302                 fprintf( stderr, "New media added\n" );
303                 p_session->i_media++;
304                 p_session->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;
312                 break;
313             case 'o':
314                 p_session->psz_origin = strdup( psz );
315                 break;
316             case 's':
317                 p_session->psz_session = strdup( psz );
318                 break;
319             case 'i':
320                 if( p_session->i_media != -1 )
321                 {
322                     p_media->psz_description = strdup( psz );
323                 }
324                 else
325                 {
326                     p_session->psz_description = strdup( psz );
327                 }
328                 break;
329             case 'u':
330                 p_session->psz_uri = strdup( psz );
331                 break;
332             case 'e':
333                 p_session->psz_email = strdup( psz );
334                 break;
335             case 'p':
336                 p_session->psz_phone = strdup( psz );
337                 break;
338             case 'c':
339                 if( p_session->i_media != -1 )
340                 {
341                     p_media->psz_connection = strdup( psz );
342                 }
343                 else
344                 {
345                     p_session->psz_connection = strdup( psz );
346                 }
347                 break;
348             case 'b':
349                 if( p_session->i_media != -1 )
350                 {
351                     p_media->psz_bandwith = strdup( psz );
352                 }
353                 else
354                 {
355                     p_session->psz_bandwith = strdup( psz );
356                 }
357                 break;
358             case 'k':
359                 if( p_session->i_media != -1 )
360                 {
361                     p_media->psz_key = strdup( psz );
362                 }
363                 else
364                 {
365                     p_session->psz_key = strdup( psz );
366                 }
367                 break;
368             case 'z':
369                 p_session->psz_timezone   = strdup( psz );
370                 break;
371
372             default:
373                 fprintf( stderr, "unhandled com=%c\n", com );
374                 break;
375         }
376
377 #undef p_session
378     }
379
380     if( sdp->i_session < 0 )
381     {
382         free( sdp );
383         return NULL;
384     }
385     sdp->session[sdp->i_session].i_media++;
386     sdp->i_session++;
387
388     return sdp;
389 }
390 static void   sdp_Release( sdp_t *p_sdp )
391 {
392 #define FREE( p ) if( p ) { free( p ) ; (p) = NULL; }
393     int i, j;
394     for( i = 0; i < p_sdp->i_session; i++ )
395     {
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 );
406
407         for( j = 0; j < p_sdp->session[i].i_media; j++ )
408         {
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 );
414         }
415         FREE( p_sdp->session[i].media);
416     }
417     FREE( p_sdp->session );
418     free( p_sdp );
419 #undef FREE
420 }
421
422 static void  sdp_Dump   ( input_thread_t *p_input, sdp_t *p_sdp )
423 {
424     int i, j;
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 ); }
429
430     for( i = 0; i < p_sdp->i_session; i++ )
431     {
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++ )
444         {
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" );
451         }
452     }
453 #undef PRINTS
454 }