]> git.sesse.net Git - vlc/blob - modules/demux/sdp.c
* sdp: - fixed loading of file > 1024 bytes.
[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.3 2003/08/04 00:48:11 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     add_category_hint( "Stream", NULL, VLC_FALSE );
44         add_integer( "sdp-session", 0, NULL,
45                      "Session", "Session", VLC_TRUE );
46
47     set_callbacks( Open, Close );
48     add_shortcut( "sdp" );
49 vlc_module_end();
50
51
52 /*****************************************************************************
53  * Local prototypes
54  *****************************************************************************/
55 static int  Demux ( input_thread_t * );
56
57 #define FREE( p ) if( p ) { free( p ) ; (p) = NULL; }
58
59 /*
60  * SDP definitions
61  */
62 typedef struct
63 {
64     char *psz_name;
65     char *psz_value;
66
67 } sdp_attribute_t;
68
69 typedef struct
70 {
71     char    *psz_media;
72     char    *psz_description;
73     char    *psz_connection;
74     char    *psz_bandwith;
75     char    *psz_key;
76
77     int             i_attribute;
78     sdp_attribute_t *attribute;
79
80 } sdp_media_t;
81
82 typedef struct
83 {
84     char    *psz_origin;
85     char    *psz_session;
86     char    *psz_description;
87     char    *psz_uri;
88     char    *psz_email;
89     char    *psz_phone;
90     char    *psz_connection;
91     char    *psz_bandwith;
92     char    *psz_key;
93     char    *psz_timezone;
94
95     int             i_attribute;
96     sdp_attribute_t *attribute;
97
98     int         i_media;
99     sdp_media_t *media;
100
101 } sdp_session_t;
102
103 typedef struct
104 {
105     int           i_session;
106     sdp_session_t *session;
107
108 } sdp_t;
109
110
111 static sdp_t *sdp_Parse     ( char * );
112 static void   sdp_Dump      ( input_thread_t *, sdp_t * );
113 static void   sdp_Release   ( sdp_t * );
114
115 #define RTP_PAYLOAD_MAX 10
116 typedef struct
117 {
118     int     i_cat;          /* AUDIO_ES, VIDEO_ES */
119
120     char    *psz_control;   /* If any, eg rtsp://blabla/... */
121
122     int     i_port;         /* base port */
123     int     i_port_count;   /* for hierachical stream */
124
125     int     i_address_count;/* for hierachical stream */
126     int     i_address_ttl;
127     char    *psz_address;
128
129     char    *psz_transport; /* RTP/AVP, udp, ... */
130
131     int     i_payload_count;
132     struct
133     {
134         int     i_type;
135         char    *psz_rtpmap;
136         char    *psz_fmtp;
137     } payload[RTP_PAYLOAD_MAX];
138
139 } sdp_track_t;
140
141 static sdp_track_t *sdp_TrackCreate ( sdp_t *, int , int , char * );
142 static void         sdp_TrackRelease( sdp_track_t * );
143
144 /*
145  * Module specific
146  */
147
148
149 struct demux_sys_t
150 {
151     stream_t *s;
152
153     int      i_session;
154     sdp_t    *p_sdp;
155
156 };
157
158 /*****************************************************************************
159  * Open:
160  *****************************************************************************/
161 static int Open( vlc_object_t * p_this )
162 {
163     input_thread_t *p_input = (input_thread_t *)p_this;
164     demux_sys_t    *p_sys;
165     uint8_t        *p_peek;
166
167     int            i_sdp;
168     int            i_sdp_max;
169     char           *psz_sdp;
170
171     vlc_value_t    val;
172
173     int            i;
174     sdp_session_t  *p_session;
175
176     /* See if it looks like a SDP
177        v, o, s fields are mandatory and in this order */
178     if( input_Peek( p_input, &p_peek, 7 ) < 7 )
179     {
180         msg_Err( p_input, "cannot peek" );
181         return VLC_EGENERIC;
182     }
183     if( strncmp( p_peek, "v=0\r\no=", 7 ) &&
184         strncmp( p_peek, "v=0\no=", 6 ) )
185     {
186         msg_Err( p_input, "SDP module discarded" );
187         return VLC_EGENERIC;
188     }
189
190     /* Set input_thread_t fields */
191     p_input->pf_demux = Demux;
192     p_input->p_demux_data = p_sys = malloc( sizeof( demux_sys_t ) );
193
194     /* Init private data */
195     p_sys->i_session= 0;
196     p_sys->p_sdp    = NULL;
197     if( ( p_sys->s = stream_OpenInput( p_input ) ) == NULL )
198     {
199         msg_Err( p_input, "cannot create stream" );
200         goto error;
201     }
202
203     /* Read the complete SDP file */
204     i_sdp = 0;
205     i_sdp_max = 1024;
206     psz_sdp = malloc( i_sdp_max );
207     for( ;; )
208     {
209         int i_read;
210
211         i_read = stream_Read( p_sys->s, &psz_sdp[i_sdp], i_sdp_max - i_sdp -1 );
212         if( i_read < i_sdp_max - i_sdp -1 )
213         {
214             if( i_read > 0 )
215             {
216                 i_sdp += i_read;
217             }
218             break;
219         }
220         i_sdp += i_read;
221         i_sdp_max += 1024;
222         psz_sdp = realloc( psz_sdp, i_sdp_max );
223     }
224     psz_sdp[i_sdp] = '\0';
225
226     if( strlen( psz_sdp ) <= 0 )
227     {
228         msg_Err( p_input, "cannot read SDP file" );
229         goto error;
230
231     }
232
233     /* Parse this SDP */
234     if( ( p_sys->p_sdp = sdp_Parse( psz_sdp ) ) == NULL )
235     {
236         msg_Err( p_input, "cannot parse SDP" );
237         goto error;
238     }
239     sdp_Dump( p_input, p_sys->p_sdp );
240
241     /* Get the selected session */
242     var_Create( p_input, "sdp-session", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
243     var_Get( p_input, "sdp-session", &val );
244     p_sys->i_session = val.i_int;
245     if( p_sys->i_session >= p_sys->p_sdp->i_session )
246     {
247         p_sys->i_session = 0;
248     }
249     p_session = &p_sys->p_sdp->session[p_sys->i_session];
250
251     /* Now create a track for each media */
252     for( i = 0; i < p_session->i_media; i++ )
253     {
254         sdp_track_t *tk;
255         int j;
256
257         tk = sdp_TrackCreate( p_sys->p_sdp, p_sys->i_session, i, p_input->psz_source );
258         if( tk == NULL )
259         {
260             msg_Warn( p_input, "media[%d] invalid", i );
261             continue;
262         }
263
264         msg_Dbg( p_input, "media[%d] :", i );
265         msg_Dbg( p_input, "    - cat : %s",
266                  tk->i_cat == AUDIO_ES ? "audio" :
267                                 ( tk->i_cat == VIDEO_ES ? "video":"unknown") );
268         msg_Dbg( p_input, "    - control : %s", tk->psz_control );
269         msg_Dbg( p_input, "    - address : %s ttl : %d count : %d",
270                  tk->psz_address, tk->i_address_ttl, tk->i_address_count );
271         msg_Dbg( p_input, "    - port : %d count : %d", tk->i_port, tk->i_port_count );
272         msg_Dbg( p_input, "    - transport : %s", tk->psz_transport );
273         for( j = 0; j < tk->i_payload_count; j++ )
274         {
275             msg_Dbg( p_input, "    - payload[%d] : type : %d rtpmap : %s fmtp : %s",
276                      j, tk->payload[j].i_type,
277                      tk->payload[j].psz_rtpmap,
278                      tk->payload[j].psz_fmtp );
279         }
280
281         sdp_TrackRelease( tk );
282     }
283     return VLC_SUCCESS;
284
285 error:
286     if( p_sys->s )
287     {
288         stream_Release( p_sys->s );
289     }
290     free( p_sys );
291     return VLC_EGENERIC;
292 }
293
294 /*****************************************************************************
295  * Close: frees unused data
296  *****************************************************************************/
297 static void Close( vlc_object_t *p_this )
298 {
299     input_thread_t *p_input = (input_thread_t *)p_this;
300     demux_sys_t    *p_sys = p_input->p_demux_data;
301
302     sdp_Release( p_sys->p_sdp );
303     free( p_sys );
304 }
305
306 /*****************************************************************************
307  * Demux: reads and demuxes data packets
308  *****************************************************************************
309  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
310  *****************************************************************************/
311 static int Demux ( input_thread_t *p_input )
312 {
313
314     return 0;
315 }
316
317 /*****************************************************************************
318  *
319  *****************************************************************************/
320
321 /*****************************************************************************
322  *  SDP Parser
323  *****************************************************************************/
324 static int   sdp_GetLine( char **ppsz_sdp, char *p_com, char **pp_arg )
325 {
326     char *p = *ppsz_sdp;
327     char *p_end;
328     int  i_size;
329
330     if( p[0] < 'a' || p[0] > 'z' || p[1] != '=' )
331     {
332         return VLC_EGENERIC;
333     }
334
335     *p_com = p[0];
336
337     if( ( p_end = strstr( p, "\n" ) ) == NULL )
338     {
339         p_end = p + strlen( p );
340     }
341     else
342     {
343         while( *p_end == '\n' || *p_end == '\r' )
344         {
345             p_end--;
346         }
347         p_end++;
348     }
349
350     i_size = p_end - &p[2];
351     *pp_arg = malloc( i_size + 1 );
352     memcpy(  *pp_arg, &p[2], i_size );
353     (*pp_arg)[i_size] = '\0';
354
355     while( *p_end == '\r' || *p_end == '\n' )
356     {
357         p_end++;
358     }
359     *ppsz_sdp = p_end;
360     return VLC_SUCCESS;
361 }
362
363 static sdp_t *sdp_Parse  ( char *psz_sdp )
364 {
365     sdp_t *sdp = malloc( sizeof( sdp_t ) );
366
367     sdp->i_session = -1;
368     sdp->session   = NULL;
369
370     for( ;; )
371     {
372 #define p_session (&sdp->session[sdp->i_session])
373 #define p_media   (&p_session->media[p_session->i_media])
374         char com, *psz;
375
376         if( sdp_GetLine( &psz_sdp, &com, &psz ) )
377         {
378             break;
379         }
380         fprintf( stderr, "com=%c arg=%s\n", com, psz );
381         if( sdp->i_session < 0 && ( com !='v' || strcmp( psz, "0" ) ) )
382         {
383             break;
384         }
385         switch( com )
386         {
387             case 'v':
388                 fprintf( stderr, "New session added\n" );
389                 if( sdp->i_session != -1 )
390                 {
391                     p_session->i_media++;
392                 }
393                 /* Add a new session */
394                 sdp->i_session++;
395                 sdp->session =
396                     realloc( sdp->session,
397                              (sdp->i_session + 1)*sizeof(sdp_session_t) );
398                 p_session->psz_origin     = NULL;
399                 p_session->psz_session    = NULL;
400                 p_session->psz_description= NULL;
401                 p_session->psz_uri        = NULL;
402                 p_session->psz_email      = NULL;
403                 p_session->psz_phone      = NULL;
404                 p_session->psz_connection = NULL;
405                 p_session->psz_bandwith   = NULL;
406                 p_session->psz_key        = NULL;
407                 p_session->psz_timezone   = NULL;
408                 p_session->i_media        = -1;
409                 p_session->media          = NULL;
410                 p_session->i_attribute    = 0;
411                 p_session->attribute      = 0;
412
413                 break;
414             case 'm':
415                 fprintf( stderr, "New media added\n" );
416                 p_session->i_media++;
417                 p_session->media =
418                     realloc( p_session->media,
419                              (p_session->i_media + 1)*sizeof( sdp_media_t ) );
420                 p_media->psz_media      = strdup( psz );
421                 p_media->psz_description= NULL;
422                 p_media->psz_connection = NULL;
423                 p_media->psz_bandwith   = NULL;
424                 p_media->psz_key        = NULL;
425                 p_media->i_attribute    = 0;
426                 p_media->attribute      = 0;
427                 break;
428             case 'o':
429                 p_session->psz_origin = strdup( psz );
430                 break;
431             case 's':
432                 p_session->psz_session = strdup( psz );
433                 break;
434             case 'i':
435                 if( p_session->i_media != -1 )
436                 {
437                     p_media->psz_description = strdup( psz );
438                 }
439                 else
440                 {
441                     p_session->psz_description = strdup( psz );
442                 }
443                 break;
444             case 'u':
445                 p_session->psz_uri = strdup( psz );
446                 break;
447             case 'e':
448                 p_session->psz_email = strdup( psz );
449                 break;
450             case 'p':
451                 p_session->psz_phone = strdup( psz );
452                 break;
453             case 'c':
454                 if( p_session->i_media != -1 )
455                 {
456                     p_media->psz_connection = strdup( psz );
457                 }
458                 else
459                 {
460                     /* FIXME could be multiple address FIXME */
461                     /* For instance
462                            c=IN IP4 224.2.1.1/127
463                            c=IN IP4 224.2.1.2/127
464                            c=IN IP4 224.2.1.3/127
465                         is valid */
466                     p_session->psz_connection = strdup( psz );
467                 }
468                 break;
469             case 'b':
470                 if( p_session->i_media != -1 )
471                 {
472                     p_media->psz_bandwith = strdup( psz );
473                 }
474                 else
475                 {
476                     p_session->psz_bandwith = strdup( psz );
477                 }
478                 break;
479             case 'k':
480                 if( p_session->i_media != -1 )
481                 {
482                     p_media->psz_key = strdup( psz );
483                 }
484                 else
485                 {
486                     p_session->psz_key = strdup( psz );
487                 }
488                 break;
489             case 'z':
490                 p_session->psz_timezone   = strdup( psz );
491                 break;
492             case 'a':
493             {
494                 char *p = strchr( psz, ':' );
495                 char *name = NULL;
496                 char *value= NULL;
497
498                 if( p )
499                 {
500                     *p++ = '\0';
501                     value= strdup( p);
502                 }
503                 name = strdup( psz );
504
505                 if( p_session->i_media != -1 )
506                 {
507                     p_media->attribute
508                         = realloc( p_media->attribute,
509                                    ( p_media->i_attribute + 1 ) *
510                                         sizeof( sdp_attribute_t ) );
511                     p_media->attribute[p_media->i_attribute].psz_name = name;
512                     p_media->attribute[p_media->i_attribute].psz_value = value;
513                     p_media->i_attribute++;
514                 }
515                 else
516                 {
517                     p_session->psz_key = strdup( psz );
518                     p_session->attribute
519                         = realloc( p_session->attribute,
520                                    ( p_session->i_attribute + 1 ) *
521                                         sizeof( sdp_attribute_t ) );
522                     p_session->attribute[p_session->i_attribute].psz_name = name;
523                     p_session->attribute[p_session->i_attribute].psz_value = value;
524                     p_session->i_attribute++;
525                 }
526                 break;
527             }
528
529             default:
530                 fprintf( stderr, "unhandled com=%c\n", com );
531                 break;
532         }
533
534 #undef p_media
535 #undef p_session
536     }
537
538     if( sdp->i_session < 0 )
539     {
540         free( sdp );
541         return NULL;
542     }
543     sdp->session[sdp->i_session].i_media++;
544     sdp->i_session++;
545
546     return sdp;
547 }
548 static void   sdp_Release( sdp_t *p_sdp )
549 {
550     int i, j, i_attr;
551     for( i = 0; i < p_sdp->i_session; i++ )
552     {
553         FREE( p_sdp->session[i].psz_origin );
554         FREE( p_sdp->session[i].psz_session );
555         FREE( p_sdp->session[i].psz_description );
556         FREE( p_sdp->session[i].psz_uri );
557         FREE( p_sdp->session[i].psz_email );
558         FREE( p_sdp->session[i].psz_phone );
559         FREE( p_sdp->session[i].psz_connection );
560         FREE( p_sdp->session[i].psz_bandwith );
561         FREE( p_sdp->session[i].psz_key );
562         FREE( p_sdp->session[i].psz_timezone );
563         for( i_attr = 0; i_attr < p_sdp->session[i].i_attribute; i_attr++ )
564         {
565             FREE( p_sdp->session[i].attribute[i].psz_name );
566             FREE( p_sdp->session[i].attribute[i].psz_value );
567         }
568         FREE( p_sdp->session[i].attribute );
569
570         for( j = 0; j < p_sdp->session[i].i_media; j++ )
571         {
572             FREE( p_sdp->session[i].media[j].psz_media );
573             FREE( p_sdp->session[i].media[j].psz_description );
574             FREE( p_sdp->session[i].media[j].psz_connection );
575             FREE( p_sdp->session[i].media[j].psz_bandwith );
576             FREE( p_sdp->session[i].media[j].psz_key );
577             for( i_attr = 0; i_attr < p_sdp->session[i].i_attribute; i_attr++ )
578             {
579                 FREE( p_sdp->session[i].media[j].attribute[i_attr].psz_name );
580                 FREE( p_sdp->session[i].media[j].attribute[i_attr].psz_value );
581             }
582             FREE( p_sdp->session[i].media[j].attribute );
583         }
584         FREE( p_sdp->session[i].media);
585     }
586     FREE( p_sdp->session );
587     free( p_sdp );
588 }
589
590 static void  sdp_Dump   ( input_thread_t *p_input, sdp_t *p_sdp )
591 {
592     int i, j, i_attr;
593 #define PRINTS( var, fmt ) \
594     if( var ) { msg_Dbg( p_input, "    - " fmt " : %s", var ); }
595 #define PRINTM( var, fmt ) \
596     if( var ) { msg_Dbg( p_input, "        - " fmt " : %s", var ); }
597
598     for( i = 0; i < p_sdp->i_session; i++ )
599     {
600         msg_Dbg( p_input, "session[%d]", i );
601         PRINTS( p_sdp->session[i].psz_origin, "Origin" );
602         PRINTS( p_sdp->session[i].psz_session, "Session" );
603         PRINTS( p_sdp->session[i].psz_description, "Description" );
604         PRINTS( p_sdp->session[i].psz_uri, "URI" );
605         PRINTS( p_sdp->session[i].psz_email, "e-mail" );
606         PRINTS( p_sdp->session[i].psz_phone, "Phone" );
607         PRINTS( p_sdp->session[i].psz_connection, "Connection" );
608         PRINTS( p_sdp->session[i].psz_bandwith, "Bandwith" );
609         PRINTS( p_sdp->session[i].psz_key, "Key" );
610         PRINTS( p_sdp->session[i].psz_timezone, "TimeZone" );
611         for( i_attr = 0; i_attr < p_sdp->session[i].i_attribute; i_attr++ )
612         {
613             msg_Dbg( p_input, "    - attribute[%d] name:'%s' value:'%s'",
614                     i_attr,
615                     p_sdp->session[i].attribute[i_attr].psz_name,
616                     p_sdp->session[i].attribute[i_attr].psz_value );
617         }
618
619         for( j = 0; j < p_sdp->session[i].i_media; j++ )
620         {
621             msg_Dbg( p_input, "    - media[%d]", j );
622             PRINTM( p_sdp->session[i].media[j].psz_media, "Name" );
623             PRINTM( p_sdp->session[i].media[j].psz_description, "Description" );
624             PRINTM( p_sdp->session[i].media[j].psz_connection, "Connection" );
625             PRINTM( p_sdp->session[i].media[j].psz_bandwith, "Bandwith" );
626             PRINTM( p_sdp->session[i].media[j].psz_key, "Key" );
627
628             for( i_attr = 0; i_attr < p_sdp->session[i].media[j].i_attribute; i_attr++ )
629             {
630                 msg_Dbg( p_input, "        - attribute[%d] name:'%s' value:'%s'",
631                         i_attr,
632                         p_sdp->session[i].media[j].attribute[i_attr].psz_name,
633                         p_sdp->session[i].media[j].attribute[i_attr].psz_value );
634             }
635         }
636     }
637 #undef PRINTS
638 }
639
640 static char * sdp_AttributeValue( int i_attribute, sdp_attribute_t *attribute,
641                                   char *name )
642 {
643     int i;
644
645     for( i = 0; i < i_attribute; i++ )
646     {
647         if( !strcmp( attribute[i].psz_name, name ) )
648         {
649             return attribute[i].psz_value;
650         }
651     }
652     return NULL;
653 }
654
655 /*
656  * Create a track from an SDP session/media
657  */
658 static sdp_track_t *sdp_TrackCreate( sdp_t *p_sdp, int i_session, int i_media,
659                                      char *psz_url_base )
660 {
661     sdp_track_t   *tk = malloc( sizeof( sdp_track_t ) );
662     sdp_session_t *p_session = &p_sdp->session[i_session];
663     sdp_media_t   *p_media = &p_session->media[i_media];
664
665     char *p;
666     char *psz;
667
668     /* Get track type */
669     if( !strncmp( p_media->psz_media, "audio", 5 ) )
670     {
671         tk->i_cat = AUDIO_ES;
672     }
673     else if( !strncmp( p_media->psz_media, "video", 5 ) )
674     {
675         tk->i_cat = VIDEO_ES;
676     }
677     else
678     {
679         free( tk );
680         return NULL;
681     }
682     p = &p_media->psz_media[5];
683
684     /* Get track port base and count */
685     tk->i_port = strtol( p, &p, 0 );
686
687     if( *p == '/' )
688     {
689         p++;
690         tk->i_port_count = strtol( p, &p, 0 );
691     }
692     else
693     {
694         tk->i_port_count = 0;
695     }
696
697     while( *p == ' ' )
698     {
699         p++;
700     }
701
702     /* Get transport */
703     tk->psz_transport = strdup( p );
704     if( ( psz = strchr( tk->psz_transport, ' ' ) ) )
705     {
706         *psz = '\0';
707     }
708     while( *p && *p != ' ' )
709     {
710         p++;
711     }
712
713     /* Get payload type+fmt */
714     tk->i_payload_count = 0;
715     for( ;; )
716     {
717         int i;
718
719         tk->payload[tk->i_payload_count].i_type     = strtol( p, &p, 0 );
720         tk->payload[tk->i_payload_count].psz_rtpmap = NULL;
721         tk->payload[tk->i_payload_count].psz_fmtp   = NULL;
722
723         for( i = 0; i < p_media->i_attribute; i++ )
724         {
725             if( !strcmp( p_media->attribute[i].psz_name, "rtpmap" ) &&
726                 p_media->attribute[i].psz_value )
727             {
728                 char *p = p_media->attribute[i].psz_value;
729                 int i_type = strtol( p, &p, 0 );
730
731                 if( i_type == tk->payload[tk->i_payload_count].i_type )
732                 {
733                     tk->payload[tk->i_payload_count].psz_rtpmap = strdup( p );
734                 }
735             }
736             else if( !strcmp( p_media->attribute[i].psz_name, "fmtp" ) &&
737                      p_media->attribute[i].psz_value )
738             {
739                 char *p = p_media->attribute[i].psz_value;
740                 int i_type = strtol( p, &p, 0 );
741
742                 if( i_type == tk->payload[tk->i_payload_count].i_type )
743                 {
744                     tk->payload[tk->i_payload_count].psz_fmtp = strdup( p );
745                 }
746             }
747
748         }
749         tk->i_payload_count++;
750         if( *p == '\0' || tk->i_payload_count >= RTP_PAYLOAD_MAX )
751         {
752             break;
753         }
754     }
755
756     /* Get control */
757     psz = sdp_AttributeValue( p_media->i_attribute, p_media->attribute, "control" );
758     if( !psz || *psz == '\0' )
759     {
760         psz = sdp_AttributeValue( p_session->i_attribute, p_session->attribute,
761                                   "control" );
762     }
763
764     if( psz )
765     {
766         if( strstr( psz, "://" ) || psz_url_base == NULL )
767         {
768             tk->psz_control = strdup( psz );
769         }
770         else
771         {
772             tk->psz_control = malloc( strlen( psz_url_base ) + strlen( psz ) + 1 );
773             strcpy( tk->psz_control, psz_url_base );
774             strcat( tk->psz_control, psz );
775         }
776     }
777     else
778     {
779         tk->psz_control = NULL;
780     }
781
782     /* Get address */
783     psz = p_media->psz_connection;
784     if( psz == NULL )
785     {
786         psz = p_session->psz_connection;
787     }
788     if( psz )
789     {
790         tk->i_address_count = 0;
791         tk->i_address_ttl   = 0;
792         tk->psz_address     = NULL;
793
794         if( ( p = strstr( psz, "IP4" ) ) == NULL )
795         {
796             p = strstr( psz, "IP6" );   /* FIXME No idea if it exists ... */
797         }
798         if( p )
799         {
800             p += 3;
801             while( *p == ' ' )
802             {
803                 p++;
804             }
805
806             tk->psz_address = p = strdup( p );
807             p = strchr( p, '/' );
808             if(p )
809             {
810                 *p++ = '\0';
811
812                 tk->i_address_ttl= strtol( p, &p, 0 );
813                 if( p )
814                 {
815                     tk->i_address_count = strtol( p, &p, 0 );
816                 }
817             }
818         }
819     }
820     else
821     {
822         tk->i_address_count = 0;
823         tk->i_address_ttl   = 0;
824         tk->psz_address     = NULL;
825     }
826
827     return tk;
828 }
829
830
831 static void         sdp_TrackRelease( sdp_track_t *tk )
832 {
833     int i;
834
835     FREE( tk->psz_control );
836     FREE( tk->psz_address );
837     FREE( tk->psz_transport );
838     for( i = 0; i < tk->i_payload_count; i++ )
839     {
840         FREE( tk->payload[i].psz_rtpmap );
841         FREE( tk->payload[i].psz_fmtp );
842     }
843     free( tk );
844 }
845
846
847