1 /*****************************************************************************
2 * m3u.c: a meta demux to parse m3u and asx playlists
3 *****************************************************************************
4 * Copyright (C) 2001 VideoLAN
5 * $Id: m3u.c,v 1.10 2002/12/14 01:05:53 babal Exp $
7 * Authors: Sigmund Augdal <sigmunau@idi.ntnu.no>
8 * Gildas Bazin <gbazin@netcourrier.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
28 #include <stdlib.h> /* malloc(), free() */
29 #include <string.h> /* strdup() */
33 #include <vlc/input.h>
34 #include <vlc_playlist.h>
36 #include <sys/types.h>
38 /*****************************************************************************
39 * Constants and structures
40 *****************************************************************************/
49 int i_type; /* playlist type (m3u/asx) */
52 /*****************************************************************************
54 *****************************************************************************/
55 static int Activate ( vlc_object_t * );
56 static void Deactivate( vlc_object_t * );
57 static int Demux ( input_thread_t * );
59 /*****************************************************************************
61 *****************************************************************************/
63 set_description( "m3u/asx metademux" );
64 set_capability( "demux", 10 );
65 set_callbacks( Activate, Deactivate );
66 add_shortcut( "m3u" );
67 add_shortcut( "asx" );
68 add_shortcut( "html" );
71 /*****************************************************************************
72 * Activate: initializes m3u demux structures
73 *****************************************************************************/
74 static int Activate( vlc_object_t * p_this )
76 input_thread_t *p_input = (input_thread_t *)p_this;
81 /* Initialize access plug-in structures. */
82 if( p_input->i_mtu == 0 )
85 p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
88 p_input->pf_demux = Demux;
89 p_input->pf_rewind = NULL;
91 /* Check for m3u/asx file extension */
92 psz_ext = strrchr ( p_input->psz_name, '.' );
93 if( !strcasecmp( psz_ext, ".m3u") ||
94 ( p_input->psz_demux && !strncmp(p_input->psz_demux, "m3u", 3) ) )
98 else if( !strcasecmp( psz_ext, ".asx") ||
99 ( p_input->psz_demux && !strncmp(p_input->psz_demux, "asx", 3) ) )
103 else if( !strcasecmp( psz_ext, ".html") ||
104 ( p_input->psz_demux && !strncmp(p_input->psz_demux, "html", 4) ) )
109 /* we had no luck looking at the file extention, so we have a look
110 * at the content. This is useful for .asp, .php and similar files
111 * that are actually html. Also useful for som asx files that have
112 * another extention */
116 int i_size = input_Peek( p_input, &p_peek, MAX_LINE );
117 i_size -= sizeof("<html>") - 1;
120 && strncasecmp( p_peek, "<html>", sizeof("<html>") - 1 )
121 && strncasecmp( p_peek, "<asx", sizeof("<asx") - 1 ) )
130 else if ( !strncasecmp( p_peek, "<html>", sizeof("<html>") -1 ) )
134 else if ( !strncasecmp( p_peek, "<asx", sizeof("<asx") -1 ) )
141 if( !( p_m3u = malloc( sizeof( demux_sys_t ) ) ) )
143 msg_Err( p_input, "out of memory" );
146 p_input->p_demux_data = p_m3u;
148 p_m3u->i_type = i_type;
153 /*****************************************************************************
154 * Deactivate: frees unused data
155 *****************************************************************************/
156 static void Deactivate( vlc_object_t *p_this )
158 input_thread_t *p_input = (input_thread_t *)p_this;
159 demux_sys_t *p_m3u = (demux_sys_t *)p_input->p_demux_data ;
164 /*****************************************************************************
165 * Demux: reads and demuxes data packets
166 *****************************************************************************
167 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
168 *****************************************************************************/
169 static void ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u
170 , playlist_t *p_playlist , char psz_line[MAX_LINE] )
172 char *psz_bol, *psz_name;
176 /* Remove unnecessary tabs or spaces at the beginning of line */
177 while( *psz_bol == ' ' || *psz_bol == '\t' ||
178 *psz_bol == '\n' || *psz_bol == '\r' )
181 if( p_m3u->i_type == TYPE_M3U )
183 /* Check for comment line */
184 if( *psz_bol == '#' )
185 /*line is comment or extended info, ignored for now */
188 else if ( p_m3u->i_type == TYPE_ASX )
190 /* We are dealing with ASX files.
191 * We are looking for "<ref href=" xml markups that
192 * begins with "mms://", "http://" or "file://" */
196 strncasecmp( psz_bol, "ref", sizeof("ref") - 1 ) )
199 if( !*psz_bol ) return;
202 strncasecmp( psz_bol, "href", sizeof("href") - 1 ) )
205 if( !*psz_bol ) return;
208 strncasecmp( psz_bol, "mms://",
209 sizeof("mms://") - 1 ) &&
210 strncasecmp( psz_bol, "http://",
211 sizeof("http://") - 1 ) &&
212 strncasecmp( psz_bol, "file://",
213 sizeof("file://") - 1 ) )
216 if( !*psz_bol ) return;
218 psz_eol = strchr( psz_bol, '"');
226 /* We are dealing with a html file with embedded
227 * video. We are looking for "<param name="filename"
228 * value=" html markups that begin with "http://" */
232 strncasecmp( psz_bol, "param", sizeof("param") - 1 ) )
235 if( !*psz_bol ) return;
238 strncasecmp( psz_bol, "filename", sizeof("filename") - 1 ) )
241 if( !*psz_bol ) return;
244 strncasecmp( psz_bol, "http://",
245 sizeof("http://") - 1 ) )
248 if( !*psz_bol ) return;
250 psz_eol = strchr( psz_bol, '"');
259 * From now on, we know we've got a meaningful line
262 /* Check if the line has an absolute or relative path */
264 while( *psz_name && strncmp( psz_name, "://", sizeof("://") - 1 ) )
269 if( !*psz_name && *psz_bol != '/' )
271 if( !*psz_name && (strlen(psz_bol) < 2 ||
272 ( *(psz_bol+1) != ':' &&
273 strncmp( psz_bol, "\\\\", 2 ) ) ) )
276 /* the line doesn't specify a protocol name.
277 * If this line doesn't begin with a '/' then assume the path
278 * is relative to the path of the m3u file. */
279 char *psz_path = strdup( p_input->psz_name );
282 psz_name = strrchr( psz_path, '/' );
284 psz_name = strrchr( psz_path, '\\' );
285 if ( ! psz_name ) psz_name = strrchr( psz_path, '/' );
287 if( psz_name ) *psz_name = '\0';
288 else *psz_path = '\0';
290 psz_name = malloc( strlen(psz_path) + strlen(psz_bol) + 2 );
291 sprintf( psz_name, "%s/%s", psz_path, psz_bol );
293 if ( *psz_path != '\0' )
295 psz_name = malloc( strlen(psz_path) + strlen(psz_bol) + 2 );
296 sprintf( psz_name, "%s\\%s", psz_path, psz_bol );
298 else psz_name = strdup( psz_bol );
304 psz_name = strdup( psz_bol );
307 playlist_Add( p_playlist, psz_name,
308 PLAYLIST_APPEND, PLAYLIST_END );
313 static int Demux ( input_thread_t *p_input )
315 data_packet_t *p_data;
316 char *p_buf, psz_line[MAX_LINE], eol_tok;
317 int i_size, i_bufpos, i_linepos = 0;
318 playlist_t *p_playlist;
319 vlc_bool_t b_discard = VLC_FALSE;
321 demux_sys_t *p_m3u = (demux_sys_t *)p_input->p_demux_data;
323 p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
327 msg_Err( p_input, "can't find playlist" );
331 p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;
333 /* Depending on wether we are dealing with an m3u/asf file, the end of
334 * line token will be different */
335 if( p_m3u->i_type == TYPE_ASX || p_m3u->i_type == TYPE_HTML )
340 while( ( i_size = input_SplitBuffer( p_input, &p_data, MAX_LINE ) ) > 0 )
342 i_bufpos = 0; p_buf = p_data->p_payload_start;
346 /* Build a line < MAX_LINE */
347 while( p_buf[i_bufpos] != eol_tok && i_size )
349 if( i_linepos == MAX_LINE || b_discard == VLC_TRUE )
351 /* line is bigger than MAX_LINE, discard it */
353 b_discard = VLC_TRUE;
357 if ( eol_tok != '\n' || p_buf[i_bufpos] != '\r' )
359 psz_line[i_linepos] = p_buf[i_bufpos];
364 i_size--; i_bufpos++;
367 /* Check if we need more data */
368 if( !i_size ) continue;
370 i_size--; i_bufpos++;
371 b_discard = VLC_FALSE;
373 /* Check for empty line */
374 if( !i_linepos ) continue;
376 psz_line[i_linepos] = '\0';
378 ProcessLine ( p_input, p_m3u , p_playlist , psz_line );
381 input_DeletePacket( p_input->p_method_data, p_data );
384 if ( i_linepos && b_discard != VLC_TRUE && eol_tok == '\n' )
386 psz_line[i_linepos] = '\0';
388 ProcessLine ( p_input, p_m3u , p_playlist , psz_line );
391 vlc_object_release( p_playlist );