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.8 2002/11/25 15:56:39 sigmunau 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 int Demux ( input_thread_t *p_input )
171 data_packet_t *p_data;
172 char *p_buf, psz_line[MAX_LINE], *psz_bol, *psz_name, eol_tok;
173 int i_size, i_bufpos, i_linepos = 0;
174 playlist_t *p_playlist;
175 vlc_bool_t b_discard = VLC_FALSE;
177 demux_sys_t *p_m3u = (demux_sys_t *)p_input->p_demux_data;
179 p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
183 msg_Err( p_input, "can't find playlist" );
187 p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;
189 /* Depending on wether we are dealing with an m3u/asf file, the end of
190 * line token will be different */
191 if( p_m3u->i_type == TYPE_ASX )
196 while( ( i_size = input_SplitBuffer( p_input, &p_data, MAX_LINE ) ) > 0 )
198 i_bufpos = 0; p_buf = p_data->p_payload_start;
202 /* Build a line < MAX_LINE */
203 while( p_buf[i_bufpos] != eol_tok && i_size )
205 if( i_linepos == MAX_LINE || b_discard == VLC_TRUE )
207 /* line is bigger than MAX_LINE, discard it */
209 b_discard = VLC_TRUE;
213 psz_line[i_linepos] = p_buf[i_bufpos];
217 i_size--; i_bufpos++;
220 /* Check if we need more data */
221 if( !i_size ) continue;
223 i_size--; i_bufpos++;
224 b_discard = VLC_FALSE;
226 /* Check for empty line */
227 if( !i_linepos ) continue;
229 psz_line[i_linepos] = '\0';
233 /* Remove unnecessary tabs or spaces at the beginning of line */
234 while( *psz_bol == ' ' || *psz_bol == '\t' ||
235 *psz_bol == '\n' || *psz_bol == '\r' )
238 if( p_m3u->i_type == TYPE_M3U )
240 /* Check for comment line */
241 if( *psz_bol == '#' )
242 /*line is comment or extended info, ignored for now */
245 else if ( p_m3u->i_type == TYPE_ASX )
247 /* We are dealing with ASX files.
248 * We are looking for "<ref href=" xml markups that
249 * begins with "mms://", "http://" or "file://" */
253 strncasecmp( psz_bol, "ref", sizeof("ref") - 1 ) )
256 if( !*psz_bol ) continue;
259 strncasecmp( psz_bol, "href", sizeof("href") - 1 ) )
262 if( !*psz_bol ) continue;
265 strncasecmp( psz_bol, "mms://",
266 sizeof("mms://") - 1 ) &&
267 strncasecmp( psz_bol, "http://",
268 sizeof("http://") - 1 ) &&
269 strncasecmp( psz_bol, "file://",
270 sizeof("file://") - 1 ) )
273 if( !*psz_bol ) continue;
275 psz_eol = strchr( psz_bol, '"');
283 /* We are dealing with a html file with embedded
284 * video. We are looking for "<param name="filename"
285 * value=" html markups that begin with "http://" */
289 strncasecmp( psz_bol, "param", sizeof("param") - 1 ) )
292 if( !*psz_bol ) continue;
295 strncasecmp( psz_bol, "filename", sizeof("filename") - 1 ) )
298 if( !*psz_bol ) continue;
301 strncasecmp( psz_bol, "http://",
302 sizeof("http://") - 1 ) )
305 if( !*psz_bol ) continue;
307 psz_eol = strchr( psz_bol, '"');
316 * From now on, we know we've got a meaningful line
319 /* Check if the line has an absolute or relative path */
321 while( *psz_name && strncmp( psz_name, "://", sizeof("://") - 1 ) )
325 if( !*psz_name && *psz_bol != '/' )
327 /* the line doesn't specify a protocol name.
328 * If this line doesn't begin with a '/' then assume the path
329 * is relative to the path of the m3u file. */
330 char *psz_path = strdup( p_input->psz_name );
332 psz_name = strrchr( psz_path, '/' );
333 if( psz_name ) *psz_name = '\0';
334 else *psz_path = '\0';
335 psz_name = malloc( strlen(psz_path) + strlen(psz_bol) + 2 );
336 sprintf( psz_name, "%s/%s", psz_path, psz_bol );
341 psz_name = strdup( psz_bol );
344 playlist_Add( p_playlist, psz_name,
345 PLAYLIST_APPEND, PLAYLIST_END );
352 input_DeletePacket( p_input->p_method_data, p_data );
355 vlc_object_release( p_playlist );