]> git.sesse.net Git - vlc/blob - modules/demux/sgimb.c
segfault fix when id3tag is unavailable
[vlc] / modules / demux / sgimb.c
1 /*****************************************************************************
2  * sgimb.c: a meta demux to parse sgimb referrer files
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id$
6  *
7  * Authors: Derk-Jan Hartman <hartman at videolan dot org>
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  * This is a metademux for the Kasenna MediaBase metafile format.
26  * Kasenna MediaBase first returns this file when you are trying to access
27  * their MPEG streams (MIME: application/x-sgimb). Very few applications
28  * understand this format and the format is not really documented on the net.
29  * Following a typical MediaBase file. Notice the sgi prefix of all the elements.
30  * This stems from the fact that the MediaBase servers were first introduced by SGI?????.
31  *
32  * sgiNameServerHost=host.name.tld
33  * Stream="xdma://host.name.tld/demo/a_very_cool.mpg"
34  * sgiMovieName=/demo/a_very_cool.mpg
35  * sgiAuxState=1
36  * sgiFormatName=PARTNER_41_MPEG-4
37  * sgiBitrate=1630208
38  * sgiDuration=378345000
39  * sgiQTFileBegin
40  * rtsptext
41  * rtsp://host.name.tld/demo/a_very_cool.mpg
42  * sgiQTFileEnd
43  * sgiApplicationName=MediaBaseURL
44  * sgiElapsedTime=0
45  * sgiServerVersion=6.1.2
46  * sgiRtspPort=554
47  * AutoStart=True
48  * sgiUserAccount=pid=1724&time=1078527309&displayText=You%20are%20logged%20as%20guest&
49  * sgiUserPassword=
50  *
51  *****************************************************************************/
52
53
54 /*****************************************************************************
55  * Preamble
56  *****************************************************************************/
57 #include <stdlib.h>                                      /* malloc(), free() */
58
59 #include <vlc/vlc.h>
60 #include <vlc/input.h>
61 #include <vlc_playlist.h>
62
63 /*****************************************************************************
64  * Module descriptor
65  *****************************************************************************/
66 static int  Activate  ( vlc_object_t * );
67 static void Deactivate( vlc_object_t * );
68
69 vlc_module_begin();
70     set_description( _("Kasenna MediaBase metademux") );
71     set_capability( "demux2", 170 );
72     set_callbacks( Activate, Deactivate );
73     add_shortcut( "sgimb" );
74 vlc_module_end();
75
76 /*****************************************************************************
77  * Local prototypes
78  *****************************************************************************/
79 #define MAX_LINE 1024
80
81 struct demux_sys_t
82 {
83     char        *psz_uri;       /* Stream= or sgiQTFileBegin rtsp link */
84     char        *psz_server;    /* sgiNameServerHost= */
85     char        *psz_location;  /* sgiMovieName= */
86     char        *psz_name;      /* sgiShowingName= */
87     char        *psz_user;      /* sgiUserAccount= */
88     char        *psz_password;  /* sgiUserPassword= */
89     char        *psz_mcast_ip;  /* sgiMulticastAddress= */
90     int         i_mcast_port;   /* sgiMulticastPort= */
91     int         i_packet_size;  /* sgiPacketSize= */
92     mtime_t     i_duration;     /* sgiDuration= */
93     int         i_port;         /* sgiRtspPort= */
94     int         i_sid;          /* sgiSid= */
95 };
96
97 static int Demux ( demux_t *p_demux );
98 static int Control( demux_t *p_demux, int i_query, va_list args );
99
100 /*****************************************************************************
101  * Activate: initializes m3u demux structures
102  *****************************************************************************/
103 static int Activate( vlc_object_t * p_this )
104 {
105     demux_t *p_demux = (demux_t *)p_this;
106     demux_sys_t *p_sys;
107     byte_t *p_peek;
108     int i_size;
109
110     /* Lets check the content to see if this is a sgi mediabase file */
111     i_size = stream_Peek( p_demux->s, &p_peek, MAX_LINE );
112     i_size -= sizeof("sgiNameServerHost=") - 1;
113     if ( i_size > 0 )
114     {
115         while ( i_size && strncasecmp( p_peek, "sgiNameServerHost=",
116                                        sizeof("sgiNameServerHost=") - 1 ) )
117         {
118             p_peek++;
119             i_size--;
120         }
121         if ( !strncasecmp( p_peek, "sgiNameServerHost=",
122                            sizeof("sgiNameServerHost=") -1 ) )
123         {
124             p_demux->pf_demux = Demux;
125             p_demux->pf_control = Control;
126
127             p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
128             p_sys->psz_uri = NULL;
129             p_sys->psz_server = NULL;
130             p_sys->psz_location = NULL;
131             p_sys->psz_name = NULL;
132             p_sys->psz_user = NULL;
133             p_sys->psz_password = NULL;
134             p_sys->psz_mcast_ip = NULL;
135             p_sys->i_mcast_port = 0;
136             p_sys->i_packet_size = 0;
137             p_sys->i_duration = 0;
138             p_sys->i_port = 0;
139
140             return VLC_SUCCESS;
141         }
142     }
143     return VLC_EGENERIC;
144 }
145
146 /*****************************************************************************
147  * Deactivate: frees unused data
148  *****************************************************************************/
149 static void Deactivate( vlc_object_t *p_this )
150 {
151     demux_t *p_demux = (demux_t*)p_this;
152     demux_sys_t *p_sys = p_demux->p_sys;
153     if( p_sys->psz_uri )
154         free( p_sys->psz_uri );
155     if( p_sys->psz_server )
156         free( p_sys->psz_server );
157     if( p_sys->psz_location )
158         free( p_sys->psz_location );
159     if( p_sys->psz_name )
160         free( p_sys->psz_name );
161     if( p_sys->psz_user )
162         free( p_sys->psz_user );
163     if( p_sys->psz_password )
164         free( p_sys->psz_password );
165     if( p_sys->psz_mcast_ip )
166         free( p_sys->psz_mcast_ip );
167     free( p_demux->p_sys );
168     return;
169 }
170
171 static int ParseLine ( demux_t *p_demux, char *psz_line )
172 {
173     char        *psz_bol;
174     demux_sys_t *p_sys = p_demux->p_sys;
175
176     psz_bol = psz_line;
177
178     /* Remove unnecessary tabs or spaces at the beginning of line */
179     while( *psz_bol == ' ' || *psz_bol == '\t' ||
180            *psz_bol == '\n' || *psz_bol == '\r' )
181     {
182         psz_bol++;
183     }
184
185     if( !strncasecmp( psz_bol, "rtsp://", sizeof("rtsp://") - 1 ) )
186     {
187         /* We found the link, it was inside a sgiQTFileBegin */
188         p_sys->psz_uri = strdup( psz_bol );
189     }
190     else if( !strncasecmp( psz_bol, "Stream=\"", sizeof("Stream=\"") - 1 ) )
191     {
192         psz_bol += sizeof("Stream=\"") - 1;
193         if ( !psz_bol )
194             return 0;
195         strrchr( psz_bol, '"' )[0] = '\0';
196         /* We cheat around xdma. for some reason xdma links work different then rtsp */
197         if( !strncasecmp( psz_bol, "xdma://", sizeof("xdma://") - 1 ) )
198         {
199             psz_bol[0] = 'r';
200             psz_bol[1] = 't';
201             psz_bol[2] = 's';
202             psz_bol[3] = 'p';
203         }
204         p_sys->psz_uri = strdup( psz_bol );
205     }
206     else if( !strncasecmp( psz_bol, "sgiNameServerHost=", sizeof("sgiNameServerHost=") - 1 ) )
207     {
208         psz_bol += sizeof("sgiNameServerHost=") - 1;
209         p_sys->psz_server = strdup( psz_bol );
210     }
211     else if( !strncasecmp( psz_bol, "sgiMovieName=", sizeof("sgiMovieName=") - 1 ) )
212     {
213         psz_bol += sizeof("sgiMovieName=") - 1;
214         p_sys->psz_location = strdup( psz_bol );
215     }
216     else if( !strncasecmp( psz_bol, "sgiUserAccount=", sizeof("sgiUserAccount=") - 1 ) )
217     {
218         psz_bol += sizeof("sgiUserAccount=") - 1;
219         p_sys->psz_user = strdup( psz_bol );
220     }
221     else if( !strncasecmp( psz_bol, "sgiUserPassword=", sizeof("sgiUserPassword=") - 1 ) )
222     {
223         psz_bol += sizeof("sgiUserPassword=") - 1;
224         p_sys->psz_password = strdup( psz_bol );
225     }
226     else if( !strncasecmp( psz_bol, "sgiShowingName=", sizeof("sgiShowingName=") - 1 ) )
227     {
228         psz_bol += sizeof("sgiShowingName=") - 1;
229         p_sys->psz_name = strdup( psz_bol );
230     }
231     else if( !strncasecmp( psz_bol, "sgiMulticastAddress=", sizeof("sgiMulticastAddress=") - 1 ) )
232     {
233         psz_bol += sizeof("sgiMulticastAddress=") - 1;
234         p_sys->psz_mcast_ip = strdup( psz_bol );
235     }
236     else if( !strncasecmp( psz_bol, "sgiMulticastPort=", sizeof("sgiMulticastPort=") - 1 ) )
237     {
238         psz_bol += sizeof("sgiMulticastPort=") - 1;
239         p_sys->i_mcast_port = (int) strtol( psz_bol, NULL, 0 );
240     }
241     else if( !strncasecmp( psz_bol, "sgiPacketSize=", sizeof("sgiPacketSize=") - 1 ) )
242     {
243         psz_bol += sizeof("sgiPacketSize=") - 1;
244         p_sys->i_packet_size = (int) strtol( psz_bol, NULL, 0 );
245     }
246     else if( !strncasecmp( psz_bol, "sgiDuration=", sizeof("sgiDuration=") - 1 ) )
247     {
248         psz_bol += sizeof("sgiDuration=") - 1;
249         p_sys->i_duration = (mtime_t) strtol( psz_bol, NULL, 0 );
250     }
251     else if( !strncasecmp( psz_bol, "sgiRtspPort=", sizeof("sgiRtspPort=") - 1 ) )
252     {
253         psz_bol += sizeof("sgiRtspPort=") - 1;
254         p_sys->i_port = (int) strtol( psz_bol, NULL, 0 );
255     }else
256     {
257         /* This line isn't really important */
258         return 0;
259     }
260     return VLC_SUCCESS;
261 }
262
263 /*****************************************************************************
264  * Demux: reads and demuxes data packets
265  *****************************************************************************
266  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
267  *****************************************************************************/
268 static int Demux ( demux_t *p_demux )
269 {
270     demux_sys_t     *p_sys = p_demux->p_sys;
271     playlist_t      *p_playlist;
272     playlist_item_t *p_item;
273     
274     char            *psz_line;
275     int             i_position;
276
277     p_playlist = (playlist_t *) vlc_object_find( p_demux, VLC_OBJECT_PLAYLIST,
278                                                  FIND_ANYWHERE );
279     if( !p_playlist )
280     {
281         msg_Err( p_demux, "can't find playlist" );
282         return -1;
283     }
284
285     p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;
286     i_position = p_playlist->i_index + 1;
287
288     while( ( psz_line = stream_ReadLine( p_demux->s ) ) )
289     {
290         ParseLine( p_demux, psz_line );
291         if( psz_line ) free( psz_line );
292     }
293
294     if( p_sys->psz_mcast_ip )
295     {
296         char *temp;
297
298         temp = (char *)malloc( sizeof("udp://@000.000.000.000:123456789" ) );
299         sprintf( temp, "udp://@" "%s:%i", p_sys->psz_mcast_ip, p_sys->i_mcast_port );
300         if( p_sys->psz_uri ) free( p_sys->psz_uri );
301         p_sys->psz_uri = strdup( temp );
302         free( temp );
303     }
304     else if( p_sys->psz_uri == NULL )
305     {
306         if( p_sys->psz_server && p_sys->psz_location )
307         {
308             char *temp;
309             
310             temp = (char *)malloc( sizeof("rtsp/live://" ":" "123456789") +
311                                        strlen( p_sys->psz_server ) + strlen( p_sys->psz_location ) );
312             sprintf( temp, "rtsp/live://" "%s:%i%s",
313                      p_sys->psz_server, p_sys->i_port > 0 ? p_sys->i_port : 554, p_sys->psz_location );
314             
315             p_sys->psz_uri = strdup( temp );
316             free( temp );
317         }
318     }
319
320     p_item = playlist_ItemNew( p_playlist, p_sys->psz_uri,
321                       p_sys->psz_name ? p_sys->psz_name : p_sys->psz_uri );
322
323     if( !p_item || !p_item->input.psz_uri )
324     {
325         msg_Err( p_demux, "A valid playlistitem could not be created" );
326         return VLC_EGENERIC;
327     }
328
329     if( p_sys->i_packet_size && p_sys->psz_mcast_ip )
330     {
331         char *psz_option;
332         p_sys->i_packet_size += 1000;
333         asprintf( &psz_option, "mtu=%i", p_sys->i_packet_size );
334         playlist_ItemAddOption( p_item, psz_option );
335         free( psz_option );
336     }
337
338     playlist_ItemSetDuration( p_item, p_sys->i_duration );
339     playlist_AddItem( p_playlist, p_item, PLAYLIST_INSERT, i_position );
340
341     vlc_object_release( p_playlist );
342     return VLC_SUCCESS;
343 }
344
345 static int Control( demux_t *p_demux, int i_query, va_list args )
346 {
347     return VLC_EGENERIC;
348 }
349