]> git.sesse.net Git - vlc/blob - modules/demux/playlist/m3u.c
e5df415b074df5877baaf6ce7190ad3edecdd16f
[vlc] / modules / demux / playlist / m3u.c
1 /*****************************************************************************
2  * m3u.c : M3U playlist format import
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id$
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
8  *          Sigmund Augdal <sigmunau@idi.ntnu.no>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>                                      /* malloc(), free() */
29
30 #include <vlc/vlc.h>
31 #include <vlc/input.h>
32 #include <vlc/intf.h>
33
34 #include <errno.h>                                                 /* ENOMEM */
35 #include "playlist.h"
36
37 struct demux_sys_t
38 {
39     char *psz_prefix;
40 };
41
42 /*****************************************************************************
43  * Local prototypes
44  *****************************************************************************/
45 static int Demux( demux_t *p_demux);
46 static int Control( demux_t *p_demux, int i_query, va_list args );
47
48 /*****************************************************************************
49  * Import_M3U: main import function
50  *****************************************************************************/
51 int Import_M3U( vlc_object_t *p_this )
52 {
53     demux_t *p_demux = (demux_t *)p_this;
54
55     uint8_t *p_peek;
56     char    *psz_ext;
57
58     if( stream_Peek( p_demux->s , &p_peek, 7 ) < 7 )
59     {
60         return VLC_EGENERIC;
61     }
62     psz_ext = strrchr ( p_demux->psz_path, '.' );
63
64     if( !strncmp( p_peek, "#EXTM3U", 7 ) )
65     {
66         ;
67     }
68     else if( ( psz_ext && !strcasecmp( psz_ext, ".m3u") ) ||
69              ( psz_ext && !strcasecmp( psz_ext, ".ram") ) ||
70              /* A .ram file can contain a single rtsp link */
71              ( p_demux->psz_demux && !strcmp(p_demux->psz_demux, "m3u") ) )
72     {
73         ;
74     }
75     else
76     {
77         return VLC_EGENERIC;
78     }
79     msg_Dbg( p_demux, "found valid M3U playlist file");
80
81     p_demux->pf_control = Control;
82     p_demux->pf_demux = Demux;
83     p_demux->p_sys = malloc( sizeof(demux_sys_t) );
84     if( p_demux->p_sys == NULL )
85     {
86         msg_Err( p_demux, "Out of memory" );
87         return VLC_ENOMEM;
88     }
89     p_demux->p_sys->psz_prefix = FindPrefix( p_demux );
90
91     return VLC_SUCCESS;
92 }
93
94 /*****************************************************************************
95  * Deactivate: frees unused data
96  *****************************************************************************/
97 void Close_M3U( vlc_object_t *p_this )
98 {
99     demux_t *p_demux = (demux_t *)p_this;
100
101     if( p_demux->p_sys->psz_prefix ) free( p_demux->p_sys->psz_prefix );
102     free( p_demux->p_sys );
103 }
104
105 static int Demux( demux_t *p_demux )
106 {
107     playlist_t *p_playlist;
108     char       *psz_line;
109
110     char *psz_name = NULL;
111     mtime_t i_duration = -1;
112     char **ppsz_options = NULL;
113     int i_options = 0, i;
114
115     playlist_item_t *p_item;
116
117     vlc_bool_t b_cleanup = VLC_FALSE;
118
119     p_playlist = (playlist_t *) vlc_object_find( p_demux, VLC_OBJECT_PLAYLIST,
120                                                  FIND_PARENT );
121     if( !p_playlist )
122     {
123         msg_Err( p_demux, "can't find playlist" );
124         return -1;
125     }
126
127     playlist_ItemToNode( p_playlist, p_playlist->status.p_item );
128     p_playlist->status.p_item->input.i_type = ITEM_TYPE_PLAYLIST;
129
130     psz_line = stream_ReadLine( p_demux->s );
131     while( psz_line )
132     {
133         char *psz_parse = psz_line;
134
135         /* Skip leading tabs and spaces */
136         while( *psz_parse == ' ' || *psz_parse == '\t' ||
137                *psz_parse == '\n' || *psz_parse == '\r' ) psz_parse++;
138
139         if( *psz_parse == '#' )
140         {
141             /* Parse extra info */
142
143             /* Skip leading tabs and spaces */
144             while( *psz_parse == ' ' || *psz_parse == '\t' ||
145                    *psz_parse == '\n' || *psz_parse == '\r' ||
146                    *psz_parse == '#' ) psz_parse++;
147
148             if( !*psz_parse ) goto error;
149
150             if( !strncasecmp( psz_parse, "EXTINF:", sizeof("EXTINF:") -1 ) )
151             {
152                 /* Extended info */
153                 char *psz_duration;
154                 psz_parse += sizeof("EXTINF:") - 1;
155                 while( *psz_parse == '\t' || *psz_parse == ' ' ) psz_parse++;
156
157                 psz_duration = psz_parse;
158                 psz_parse = strchr( psz_parse, ',' );
159                 if( psz_parse )
160                 {
161                     *psz_parse = '\0';
162                     psz_parse++;
163                     psz_name = strdup( psz_parse );
164                     i_duration = atoi( psz_duration );
165                     if( i_duration != -1 ) i_duration *= 1000000;
166                 }
167             }
168             else if( !strncasecmp( psz_parse, "EXTVLCOPT:",
169                                    sizeof("EXTVLCOPT:") -1 ) )
170
171             {
172                 /* VLC Option */
173                 char *psz_option;
174                 psz_parse += sizeof("EXTVLCOPT:") -1;
175                 if( !*psz_parse ) goto error;
176
177                 psz_option = strdup( psz_parse );
178                 if( psz_option )
179                     INSERT_ELEM( ppsz_options, i_options, i_options,
180                                  psz_option );
181             }
182         }
183         else if( *psz_parse )
184         {
185             char *psz_mrl =
186                 ProcessMRL( psz_parse, p_demux->p_sys->psz_prefix );
187
188             b_cleanup = VLC_TRUE;
189             if( !psz_mrl ) goto error;
190
191             p_item = playlist_ItemNew( p_playlist, psz_mrl, psz_name );
192             for( i = 0; i< i_options; i++ )
193             {
194                 playlist_ItemAddOption( p_item, ppsz_options[i] );
195             }
196             p_item->input.i_duration = i_duration;
197
198             playlist_NodeAddItem( p_playlist, p_item,
199                            p_playlist->status.p_item->pp_parents[0]->i_view,
200                            p_playlist->status.p_item, PLAYLIST_APPEND,
201                            PLAYLIST_END );
202
203             /* We need to declare the parents of the node as the
204              *                  * same of the parent's ones */
205             for( i= 1 ; i< p_playlist->status.p_item->i_parents; i ++ )
206             {
207                     playlist_ItemAddParent( p_item,
208                               p_playlist->status.p_item->pp_parents[i]->i_view,
209                               p_playlist->status.p_item );
210             }
211             free( psz_mrl );
212         }
213
214  error:
215
216         /* Fetch another line */
217         free( psz_line );
218         psz_line = stream_ReadLine( p_demux->s );
219         if( !psz_line ) b_cleanup = VLC_TRUE;
220
221         if( b_cleanup )
222         {
223             /* Cleanup state */
224             while( i_options-- ) free( ppsz_options[i_options] );
225             if( ppsz_options ) free( ppsz_options );
226             ppsz_options = NULL; i_options = 0;
227             if( psz_name ) free( psz_name );
228             psz_name = NULL;
229             i_duration = -1;
230
231             b_cleanup = VLC_FALSE;
232         }
233     }
234
235     /* Go back and play the playlist */
236     playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, p_playlist->status.i_view,
237                       p_playlist->status.p_item, NULL );
238
239     vlc_object_release( p_playlist );
240     return VLC_SUCCESS;
241 }
242
243 static int Control( demux_t *p_demux, int i_query, va_list args )
244 {
245     return VLC_EGENERIC;
246 }