Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

m3u.c

00001 /*****************************************************************************
00002  * m3u.c : M3U playlist format import
00003  *****************************************************************************
00004  * Copyright (C) 2004 the VideoLAN team
00005  * $Id: m3u.c 12836 2005-10-15 13:23:08Z sigmunau $
00006  *
00007  * Authors: Clément Stenac <[email protected]>
00008  *          Sigmund Augdal Helberg <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 /*****************************************************************************
00026  * Preamble
00027  *****************************************************************************/
00028 #include <stdlib.h>                                      /* malloc(), free() */
00029 
00030 #include <vlc/vlc.h>
00031 #include <vlc/input.h>
00032 #include <vlc/intf.h>
00033 
00034 #include <errno.h>                                                 /* ENOMEM */
00035 #include "playlist.h"
00036 
00037 struct demux_sys_t
00038 {
00039     char *psz_prefix;
00040 };
00041 
00042 /*****************************************************************************
00043  * Local prototypes
00044  *****************************************************************************/
00045 static int Demux( demux_t *p_demux);
00046 static int Control( demux_t *p_demux, int i_query, va_list args );
00047 static void parseEXTINF( char *psz_string, char **ppsz_artist, char **ppsz_name, int *pi_duration );
00048 
00049 /*****************************************************************************
00050  * Import_M3U: main import function
00051  *****************************************************************************/
00052 int E_(Import_M3U)( vlc_object_t *p_this )
00053 {
00054     demux_t *p_demux = (demux_t *)p_this;
00055 
00056     uint8_t *p_peek;
00057     char    *psz_ext;
00058 
00059     if( stream_Peek( p_demux->s , &p_peek, 7 ) < 7 )
00060     {
00061         return VLC_EGENERIC;
00062     }
00063     psz_ext = strrchr ( p_demux->psz_path, '.' );
00064 
00065     if( !strncmp( (char *)p_peek, "#EXTM3U", 7 ) )
00066     {
00067         ;
00068     }
00069     else if( ( psz_ext && !strcasecmp( psz_ext, ".m3u") ) ||
00070              ( psz_ext && !strcasecmp( psz_ext, ".ram") ) ||
00071              ( psz_ext && !strcasecmp( psz_ext, ".rm") ) ||
00072              /* A .ram file can contain a single rtsp link */
00073              ( p_demux->psz_demux && !strcmp(p_demux->psz_demux, "m3u") ) )
00074     {
00075         ;
00076     }
00077     else
00078     {
00079         return VLC_EGENERIC;
00080     }
00081     msg_Dbg( p_demux, "found valid M3U playlist file");
00082 
00083     p_demux->pf_control = Control;
00084     p_demux->pf_demux = Demux;
00085     p_demux->p_sys = malloc( sizeof(demux_sys_t) );
00086     if( p_demux->p_sys == NULL )
00087     {
00088         msg_Err( p_demux, "Out of memory" );
00089         return VLC_ENOMEM;
00090     }
00091     p_demux->p_sys->psz_prefix = E_(FindPrefix)( p_demux );
00092 
00093     return VLC_SUCCESS;
00094 }
00095 
00096 /*****************************************************************************
00097  * Deactivate: frees unused data
00098  *****************************************************************************/
00099 void E_(Close_M3U)( vlc_object_t *p_this )
00100 {
00101     demux_t *p_demux = (demux_t *)p_this;
00102 
00103     if( p_demux->p_sys->psz_prefix ) free( p_demux->p_sys->psz_prefix );
00104     free( p_demux->p_sys );
00105 }
00106 
00107 static int Demux( demux_t *p_demux )
00108 {
00109     playlist_t *p_playlist;
00110     char       *psz_line;
00111 
00112     char       *psz_name = NULL;
00113     char       *psz_artist = NULL;
00114     int        i_parsed_duration = 0;
00115     mtime_t    i_duration = -1;
00116     char       **ppsz_options = NULL;
00117     int        i_options = 0, i;
00118 
00119     playlist_item_t *p_item, *p_current;
00120 
00121     vlc_bool_t b_play;
00122 
00123     vlc_bool_t b_cleanup = VLC_FALSE;
00124 
00125     p_playlist = (playlist_t *) vlc_object_find( p_demux, VLC_OBJECT_PLAYLIST,
00126                                                  FIND_PARENT );
00127     if( !p_playlist )
00128     {
00129         msg_Err( p_demux, "can't find playlist" );
00130         return -1;
00131     }
00132 
00133     b_play = E_(FindItem)( p_demux, p_playlist, &p_current );
00134 
00135     playlist_ItemToNode( p_playlist, p_current );
00136     p_current->input.i_type = ITEM_TYPE_PLAYLIST;
00137 
00138     psz_line = stream_ReadLine( p_demux->s );
00139     while( psz_line )
00140     {
00141         char *psz_parse = psz_line;
00142 
00143         /* Skip leading tabs and spaces */
00144         while( *psz_parse == ' ' || *psz_parse == '\t' ||
00145                *psz_parse == '\n' || *psz_parse == '\r' ) psz_parse++;
00146 
00147         if( *psz_parse == '#' )
00148         {
00149             /* Parse extra info */
00150 
00151             /* Skip leading tabs and spaces */
00152             while( *psz_parse == ' ' || *psz_parse == '\t' ||
00153                    *psz_parse == '\n' || *psz_parse == '\r' ||
00154                    *psz_parse == '#' ) psz_parse++;
00155 
00156             if( !*psz_parse ) goto error;
00157 
00158             if( !strncasecmp( psz_parse, "EXTINF:", sizeof("EXTINF:") -1 ) )
00159             {
00160                 /* Extended info */
00161                 psz_parse += sizeof("EXTINF:") - 1;
00162                 parseEXTINF( psz_parse, &psz_artist, &psz_name, &i_parsed_duration );
00163                 if ( i_parsed_duration >= 0 )
00164                     i_duration = i_parsed_duration * 1000000;
00165                 if ( psz_name )
00166                     psz_name = strdup( psz_name );
00167                 if ( psz_artist )
00168                     psz_artist = strdup( psz_artist );
00169             }
00170             else if( !strncasecmp( psz_parse, "EXTVLCOPT:",
00171                                    sizeof("EXTVLCOPT:") -1 ) )
00172             {
00173                 /* VLC Option */
00174                 char *psz_option;
00175                 psz_parse += sizeof("EXTVLCOPT:") -1;
00176                 if( !*psz_parse ) goto error;
00177 
00178                 psz_option = strdup( psz_parse );
00179                 if( psz_option )
00180                     INSERT_ELEM( ppsz_options, i_options, i_options,
00181                                  psz_option );
00182             }
00183         }
00184         else if( *psz_parse )
00185         {
00186             char *psz_mrl;
00187             if( !psz_name || !*psz_name )
00188             {
00189                 /* Use filename as name for relative entries */
00190                 psz_name = strdup( psz_parse );
00191             }
00192 
00193             psz_mrl = E_(ProcessMRL)( psz_parse, p_demux->p_sys->psz_prefix );
00194 
00195             b_cleanup = VLC_TRUE;
00196             if( !psz_mrl ) goto error;
00197 
00198             EnsureUTF8( psz_name );
00199             EnsureUTF8( psz_mrl );
00200 
00201             p_item = playlist_ItemNew( p_playlist, psz_mrl, psz_name );
00202             for( i = 0; i< i_options; i++ )
00203             {
00204                 EnsureUTF8( ppsz_options[i] );
00205                 playlist_ItemAddOption( p_item, ppsz_options[i] );
00206             }
00207             p_item->input.i_duration = i_duration;
00208             if ( psz_artist && *psz_artist )
00209                 vlc_input_item_AddInfo( &p_item->input, _("Meta-information"),
00210                                         _("Artist"), "%s", psz_artist );
00211             playlist_NodeAddItem( p_playlist, p_item,
00212                                   p_current->pp_parents[0]->i_view,
00213                                   p_current, PLAYLIST_APPEND,
00214                                   PLAYLIST_END );
00215 
00216             /* We need to declare the parents of the node as the
00217              *                  * same of the parent's ones */
00218             playlist_CopyParents( p_current, p_item );
00219 
00220             vlc_input_item_CopyOptions( &p_current->input,
00221                                         &p_item->input );
00222 
00223             free( psz_mrl );
00224         }
00225 
00226  error:
00227 
00228         /* Fetch another line */
00229         free( psz_line );
00230         psz_line = stream_ReadLine( p_demux->s );
00231         if( !psz_line ) b_cleanup = VLC_TRUE;
00232 
00233         if( b_cleanup )
00234         {
00235             /* Cleanup state */
00236             while( i_options-- ) free( ppsz_options[i_options] );
00237             if( ppsz_options ) free( ppsz_options );
00238             ppsz_options = NULL; i_options = 0;
00239             if( psz_name ) free( psz_name );
00240             psz_name = NULL;
00241             if ( psz_artist ) free( psz_artist );
00242             psz_artist = NULL;
00243             i_parsed_duration = 0;
00244             i_duration = -1;
00245 
00246             b_cleanup = VLC_FALSE;
00247         }
00248     }
00249 
00250     /* Go back and play the playlist */
00251     if( b_play && p_playlist->status.p_item &&
00252         p_playlist->status.p_item->i_children > 0 )
00253     {
00254         playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
00255                           p_playlist->status.i_view,
00256                           p_playlist->status.p_item,
00257                           p_playlist->status.p_item->pp_children[0] );
00258     }
00259 
00260     vlc_object_release( p_playlist );
00261     return VLC_SUCCESS;
00262 }
00263 
00264 static int Control( demux_t *p_demux, int i_query, va_list args )
00265 {
00266     return VLC_EGENERIC;
00267 }
00268 
00269 static void parseEXTINF(char *psz_string, char **ppsz_artist, 
00270                         char **ppsz_name, int *pi_duration)
00271 {
00272     char *end = NULL;
00273     char *psz_item = NULL;
00274 
00275     end = psz_string + strlen( psz_string );
00276 
00277     /* ignore whitespaces */
00278     for (; psz_string < end && ( *psz_string == '\t' || *psz_string == ' ' ); 
00279          psz_string++ );
00280 
00281     /* duration: read to next comma */
00282     psz_item = psz_string;
00283     psz_string = strchr( psz_string, ',' );
00284     if ( psz_string )
00285     {
00286         *psz_string = '\0';
00287         *pi_duration = atoi( psz_item );
00288     }
00289     else
00290     {
00291         return;
00292     }
00293 
00294     if ( psz_string < end )               /* continue parsing if possible */
00295         psz_string++;
00296 
00297     /* analyse the remaining string */
00298     psz_item = strstr( psz_string, " - " );
00299 
00300     /* here we have the 0.8.2+ format with artist */
00301     if ( psz_item )
00302     {
00303         /* *** "EXTINF:time,artist - name" */
00304         *psz_item = '\0';
00305         *ppsz_artist = psz_string;
00306         *ppsz_name = psz_item + 3;          /* points directly after ' - ' */
00307         return;
00308     } 
00309 
00310     /* reaching this point means: 0.8.1- with artist or something without artist */
00311     if ( *psz_string == ',' )
00312     {
00313         /* *** "EXTINF:time,,name" */
00314         psz_string++;
00315         *ppsz_name = psz_string;
00316         return;
00317     } 
00318 
00319     psz_item = psz_string;
00320     psz_string = strchr( psz_string, ',' );
00321     if ( psz_string )
00322     {
00323         /* *** "EXTINF:time,artist,name" */
00324         *psz_string = '\0';
00325         *ppsz_artist = psz_item;
00326         *ppsz_name = psz_string+1;
00327     }
00328     else
00329     {
00330         /* *** "EXTINF:time,name" */
00331         *ppsz_name = psz_item;
00332     }
00333     return;
00334 }
00335 

Generated on Tue Dec 20 10:14:32 2005 for vlc-0.8.4a by  doxygen 1.4.2