/*****************************************************************************
- * m3u.c: a meta demux to parse m3u and asx playlists
+ * m3u.c: a meta demux to parse pls, m3u and asx playlists
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: m3u.c,v 1.11 2003/01/16 21:14:23 babal Exp $
+ * $Id: m3u.c,v 1.18 2003/04/06 20:08:11 sigmunau Exp $
*
* Authors: Sigmund Augdal <sigmunau@idi.ntnu.no>
* Gildas Bazin <gbazin@netcourrier.com>
*****************************************************************************/
#define MAX_LINE 1024
+#define TYPE_UNKNOWN 0
#define TYPE_M3U 1
#define TYPE_ASX 2
#define TYPE_HTML 3
+#define TYPE_PLS 4
struct demux_sys_t
{
* Module descriptor
*****************************************************************************/
vlc_module_begin();
- set_description( "m3u/asx metademux" );
- set_capability( "demux", 10 );
+ set_description( _("playlist metademux") );
+ set_capability( "demux", 180 );
set_callbacks( Activate, Deactivate );
add_shortcut( "m3u" );
add_shortcut( "asx" );
add_shortcut( "html" );
+ add_shortcut( "pls" );
vlc_module_end();
/*****************************************************************************
input_thread_t *p_input = (input_thread_t *)p_this;
char *psz_ext;
demux_sys_t *p_m3u;
- int i_type = 0;
+ int i_type = 0;
+ int i_type2 = 0;
/* Initialize access plug-in structures. */
if( p_input->i_mtu == 0 )
p_input->pf_demux = Demux;
p_input->pf_rewind = NULL;
- /* Check for m3u/asx file extension */
+ /* Check for m3u/asx file extension or if the demux has been forced */
psz_ext = strrchr ( p_input->psz_name, '.' );
- if( !strcasecmp( psz_ext, ".m3u") ||
- ( p_input->psz_demux && !strncmp(p_input->psz_demux, "m3u", 3) ) )
+
+ if( ( psz_ext && !strcasecmp( psz_ext, ".m3u") ) ||
+ ( p_input->psz_demux && !strcmp(p_input->psz_demux, "m3u") ) )
{
i_type = TYPE_M3U;
}
- else if( !strcasecmp( psz_ext, ".asx") ||
- ( p_input->psz_demux && !strncmp(p_input->psz_demux, "asx", 3) ) )
+ else if( ( psz_ext && !strcasecmp( psz_ext, ".asx") ) ||
+ ( p_input->psz_demux && !strcmp(p_input->psz_demux, "asx") ) )
{
i_type = TYPE_ASX;
}
- else if( !strcasecmp( psz_ext, ".html") ||
- ( p_input->psz_demux && !strncmp(p_input->psz_demux, "html", 4) ) )
+ else if( ( psz_ext && !strcasecmp( psz_ext, ".html") ) ||
+ ( p_input->psz_demux && !strcmp(p_input->psz_demux, "html") ) )
{
i_type = TYPE_HTML;
}
+ else if( ( psz_ext && !strcasecmp( psz_ext, ".pls") ) ||
+ ( p_input->psz_demux && !strcmp(p_input->psz_demux, "pls") ) )
+ {
+ i_type = TYPE_PLS;
+ }
/* we had no luck looking at the file extention, so we have a look
* at the content. This is useful for .asp, .php and similar files
* that are actually html. Also useful for som asx files that have
* another extention */
- if( !i_type )
+ if( i_type != TYPE_M3U )
{
byte_t *p_peek;
int i_size = input_Peek( p_input, &p_peek, MAX_LINE );
- i_size -= sizeof("<html>") - 1;
+ i_size -= sizeof("[playlist]") - 1;
if ( i_size > 0 ) {
while ( i_size
+ && strncasecmp( p_peek, "[playlist]", sizeof("[playlist]") - 1 )
&& strncasecmp( p_peek, "<html>", sizeof("<html>") - 1 )
&& strncasecmp( p_peek, "<asx", sizeof("<asx") - 1 ) )
{
}
if ( !i_size )
{
- return -1;
+ ;
+ }
+ else if ( !strncasecmp( p_peek, "[playlist]", sizeof("[playlist]") -1 ) )
+ {
+ i_type2 = TYPE_PLS;
}
else if ( !strncasecmp( p_peek, "<html>", sizeof("<html>") -1 ) )
{
- i_type = TYPE_HTML;
+ i_type2 = TYPE_HTML;
}
else if ( !strncasecmp( p_peek, "<asx", sizeof("<asx") -1 ) )
{
- i_type = TYPE_ASX;
+ i_type2 = TYPE_ASX;
}
}
}
+ if ( !i_type && !i_type2 )
+ {
+ return -1;
+ }
+ if ( i_type && !i_type2 )
+ {
+ i_type = TYPE_M3U;
+ }
+ else
+ {
+ i_type = i_type2;
+ }
+
/* Allocate p_m3u */
if( !( p_m3u = malloc( sizeof( demux_sys_t ) ) ) )
{
}
/*****************************************************************************
- * Demux: reads and demuxes data packets
- *****************************************************************************
- * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ * ProcessLine: read a "line" from the file and add any entries found
+ * to the playlist. Return number of items added ( 0 or 1 )
*****************************************************************************/
-static void ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u
- , playlist_t *p_playlist , char psz_line[MAX_LINE] )
+static int ProcessLine ( input_thread_t *p_input , demux_sys_t *p_m3u
+ , playlist_t *p_playlist , char psz_line[MAX_LINE], int i_position )
{
char *psz_bol, *psz_name;
-
psz_bol = psz_line;
/* Remove unnecessary tabs or spaces at the beginning of line */
/* Check for comment line */
if( *psz_bol == '#' )
/*line is comment or extended info, ignored for now */
- return;
+ return 0;
+ }
+ else if ( p_m3u->i_type == TYPE_PLS )
+ {
+ /* We are dealing with .pls files from shoutcast
+ * We are looking for lines like "File1=http://..." */
+ if( !strncasecmp( psz_bol, "File", sizeof("File") - 1 ) )
+ {
+ psz_bol += sizeof("File") - 1;
+ psz_bol = strchr( psz_bol, '=' );
+ if ( !psz_bol ) return 0;
+ psz_bol++;
+ }
+ else
+ {
+ return 0;
+ }
}
else if ( p_m3u->i_type == TYPE_ASX )
{
strncasecmp( psz_bol, "ref", sizeof("ref") - 1 ) )
psz_bol++;
- if( !*psz_bol ) return;
+ if( !*psz_bol ) return 0;
while( *psz_bol &&
strncasecmp( psz_bol, "href", sizeof("href") - 1 ) )
psz_bol++;
- if( !*psz_bol ) return;
+ if( !*psz_bol ) return 0;
while( *psz_bol &&
strncasecmp( psz_bol, "mms://",
sizeof("mms://") - 1 ) &&
+ strncasecmp( psz_bol, "mmsu://",
+ sizeof("mmsu://") - 1 ) &&
+ strncasecmp( psz_bol, "mmst://",
+ sizeof("mmst://") - 1 ) &&
strncasecmp( psz_bol, "http://",
sizeof("http://") - 1 ) &&
strncasecmp( psz_bol, "file://",
sizeof("file://") - 1 ) )
psz_bol++;
- if( !*psz_bol ) return;
+ if( !*psz_bol ) return 0;
psz_eol = strchr( psz_bol, '"');
if( !psz_eol )
- return;
+ return 0;
*psz_eol = '\0';
}
- else
+ else if ( p_m3u->i_type == TYPE_HTML )
{
/* We are dealing with a html file with embedded
* video. We are looking for "<param name="filename"
strncasecmp( psz_bol, "param", sizeof("param") - 1 ) )
psz_bol++;
- if( !*psz_bol ) return;
+ if( !*psz_bol ) return 0;
while( *psz_bol &&
strncasecmp( psz_bol, "filename", sizeof("filename") - 1 ) )
psz_bol++;
- if( !*psz_bol ) return;
+ if( !*psz_bol ) return 0;
while( *psz_bol &&
strncasecmp( psz_bol, "http://",
sizeof("http://") - 1 ) )
psz_bol++;
- if( !*psz_bol ) return;
+ if( !*psz_bol ) return 0;
psz_eol = strchr( psz_bol, '"');
if( !psz_eol )
- return;
+ return 0;
*psz_eol = '\0';
}
+ else
+ {
+ msg_Warn( p_input, "unknown file type" );
+ return 0;
+ }
/* empty line */
- if ( !*psz_bol ) return;
+ if ( !*psz_bol ) return 0;
/*
* From now on, we know we've got a meaningful line
}
playlist_Add( p_playlist, psz_name,
- PLAYLIST_APPEND, PLAYLIST_END );
+ PLAYLIST_INSERT, i_position );
free( psz_name );
+ return 1;
}
+/*****************************************************************************
+ * Demux: reads and demuxes data packets
+ *****************************************************************************
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ *****************************************************************************/
static int Demux ( input_thread_t *p_input )
{
data_packet_t *p_data;
char *p_buf, psz_line[MAX_LINE], eol_tok;
int i_size, i_bufpos, i_linepos = 0;
playlist_t *p_playlist;
+ int i_position;
vlc_bool_t b_discard = VLC_FALSE;
demux_sys_t *p_m3u = (demux_sys_t *)p_input->p_demux_data;
}
p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;
+ i_position = p_playlist->i_index + 1;
/* Depending on wether we are dealing with an m3u/asf file, the end of
* line token will be different */
psz_line[i_linepos] = '\0';
i_linepos = 0;
- ProcessLine ( p_input, p_m3u , p_playlist , psz_line );
+ i_position += ProcessLine ( p_input, p_m3u , p_playlist ,
+ psz_line, i_position );
}
input_DeletePacket( p_input->p_method_data, p_data );
{
psz_line[i_linepos] = '\0';
i_linepos = 0;
- ProcessLine ( p_input, p_m3u , p_playlist , psz_line );
+ i_position += ProcessLine ( p_input, p_m3u , p_playlist , psz_line,
+ i_position );
}
vlc_object_release( p_playlist );