]> git.sesse.net Git - vlc/blob - modules/demux/playlist/qtl.c
Untested workarround for buggy asx files with an end of line char at the end of the...
[vlc] / modules / demux / playlist / qtl.c
1 /*****************************************************************************
2  * qtl.c: QuickTime Media Link Importer
3  *****************************************************************************
4  * Copyright (C) 2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea -@t- videolan -Dot- org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*
25 See
26 http://developer.apple.com/documentation/QuickTime/QT6WhatsNew/Chap1/chapter_1_section_54.html
27 and
28 http://developer.apple.com/documentation/QuickTime/WhatsNewQT5/QT5NewChapt1/chapter_1_section_39.html
29
30 autoplay - true/false
31 controller - true/false
32 fullscreen - normal/double/half/current/full
33 href - url
34 kioskmode - true/false
35 loop - true/false/palindrome
36 movieid - integer
37 moviename - string
38 playeveryframe - true/false
39 qtnext - url
40 quitwhendone - true/false
41 src - url (required)
42 type - mime type
43 volume - 0 (mute) - 100 (max)
44
45 */
46
47 /*****************************************************************************
48  * Preamble
49  *****************************************************************************/
50 #include <ctype.h>                                              /* isspace() */
51
52 #include <vlc/vlc.h>
53 #include <vlc_demux.h>
54
55 #include "playlist.h"
56 #include "vlc_xml.h"
57
58 struct demux_sys_t
59 {
60     playlist_t *p_playlist;
61     playlist_item_t *p_current;
62     playlist_item_t *p_item_in_category;
63
64     xml_t *p_xml;
65     xml_reader_t *p_xml_reader;
66 };
67
68 typedef enum { FULLSCREEN_NORMAL,
69                FULLSCREEN_DOUBLE,
70                FULLSCREEN_HALF,
71                FULLSCREEN_CURRENT,
72                FULLSCREEN_FULL } qtl_fullscreen_t;
73 const char* ppsz_fullscreen[] = { "normal", "double", "half", "current", "full" };
74 typedef enum { LOOP_TRUE,
75                LOOP_FALSE,
76                LOOP_PALINDROME } qtl_loop_t;
77 const char* ppsz_loop[] = { "true", "false", "palindrome" };
78
79 /*****************************************************************************
80  * Local prototypes
81  *****************************************************************************/
82 static int Demux( demux_t *p_demux);
83 static int Control( demux_t *p_demux, int i_query, va_list args );
84
85 /*****************************************************************************
86  * Import_QTL: main import function
87  *****************************************************************************/
88 int E_(Import_QTL)( vlc_object_t *p_this )
89 {
90     DEMUX_BY_EXTENSION_MSG( ".qtl", "using QuickTime Media Link reader" );
91     p_demux->p_sys->p_playlist = NULL;
92     p_demux->p_sys->p_xml = NULL;
93     p_demux->p_sys->p_xml_reader = NULL;
94     return VLC_SUCCESS;
95 }
96
97 /*****************************************************************************
98  * Deactivate: frees unused data
99  *****************************************************************************/
100 void E_(Close_QTL)( vlc_object_t *p_this )
101 {
102     demux_t *p_demux = (demux_t *)p_this;
103     demux_sys_t *p_sys = p_demux->p_sys;
104
105     if( p_sys->p_playlist )
106         vlc_object_release( p_sys->p_playlist );
107     if( p_sys->p_xml_reader )
108         xml_ReaderDelete( p_sys->p_xml, p_sys->p_xml_reader );
109     if( p_sys->p_xml )
110         xml_Delete( p_sys->p_xml );
111     free( p_sys );
112 }
113
114 static int Demux( demux_t *p_demux )
115 {
116     demux_sys_t *p_sys = p_demux->p_sys;
117     xml_t *p_xml;
118     xml_reader_t *p_xml_reader;
119     char *psz_eltname = NULL;
120     input_item_t *p_input;
121
122     /* List of all possible attributes. The only required one is "src" */
123     vlc_bool_t b_autoplay = VLC_FALSE;
124     vlc_bool_t b_controler = VLC_TRUE;
125     qtl_fullscreen_t fullscreen = VLC_FALSE;
126     char *psz_href = NULL;
127     vlc_bool_t b_kioskmode = VLC_FALSE;
128     qtl_loop_t loop = LOOP_FALSE;
129     int i_movieid = -1;
130     char *psz_moviename = NULL;
131     vlc_bool_t b_playeveryframe = VLC_FALSE;
132     char *psz_qtnext = NULL;
133     vlc_bool_t b_quitwhendone = VLC_FALSE;
134     char *psz_src = NULL;
135     char *psz_mimetype = NULL;
136     int i_volume = 100;
137
138     INIT_PLAYLIST_STUFF;
139
140     p_sys->p_playlist = p_playlist;
141     p_sys->p_current = p_current;
142     p_sys->p_item_in_category = p_item_in_category;
143
144     p_xml = p_sys->p_xml = xml_Create( p_demux );
145     if( !p_xml ) return -1;
146
147     p_xml_reader = xml_ReaderCreate( p_xml, p_demux->s );
148     if( !p_xml_reader ) return -1;
149     p_sys->p_xml_reader = p_xml_reader;
150
151     /* check root node */
152     if( xml_ReaderRead( p_xml_reader ) != 1 )
153     {
154         msg_Err( p_demux, "invalid file (no root node)" );
155         return -1;
156     }
157
158     if( xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM ||
159         ( psz_eltname = xml_ReaderName( p_xml_reader ) ) == NULL ||
160         strcmp( psz_eltname, "embed" ) )
161     {
162         msg_Err( p_demux, "invalid root node %i, %s",
163                  xml_ReaderNodeType( p_xml_reader ), psz_eltname );
164         FREE( psz_eltname );
165
166         /* second line has <?quicktime tag ... so we try to skip it */
167         msg_Dbg( p_demux, "trying to read one more node" );
168         xml_ReaderRead( p_xml_reader );
169         if( xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM ||
170             ( psz_eltname = xml_ReaderName( p_xml_reader ) ) == NULL ||
171             strcmp( psz_eltname, "embed" ) )
172         {
173             msg_Err( p_demux, "invalid root node %i, %s",
174                      xml_ReaderNodeType( p_xml_reader ), psz_eltname );
175             FREE( psz_eltname );
176             return -1;
177         }
178     }
179     FREE( psz_eltname );
180
181     while( xml_ReaderNextAttr( p_sys->p_xml_reader ) == VLC_SUCCESS )
182     {
183         char *psz_attrname = xml_ReaderName( p_sys->p_xml_reader );
184         char *psz_attrvalue = xml_ReaderValue( p_sys->p_xml_reader );
185
186         if( !psz_attrname || !psz_attrvalue )
187         {
188             FREE( psz_attrname );
189             FREE( psz_attrvalue );
190             return -1;
191         }
192
193         if( !strcmp( psz_attrname, "autoplay" ) )
194         {
195             if( !strcmp( psz_attrvalue, "true" ) )
196             {
197                 b_autoplay = VLC_TRUE;
198             }
199             else
200             {
201                 b_autoplay = VLC_FALSE;
202             }
203         }
204         else if( !strcmp( psz_attrname, "controler" ) )
205         {
206             if( !strcmp( psz_attrvalue, "false" ) )
207             {
208                 b_controler = VLC_FALSE;
209             }
210             else
211             {
212                 b_controler = VLC_TRUE;
213             }
214         }
215         else if( !strcmp( psz_attrname, "fullscreen" ) )
216         {
217             if( !strcmp( psz_attrvalue, "double" ) )
218             {
219                 fullscreen = FULLSCREEN_DOUBLE;
220             }
221             else if( !strcmp( psz_attrvalue, "half" ) )
222             {
223                 fullscreen = FULLSCREEN_HALF;
224             }
225             else if( !strcmp( psz_attrvalue, "current" ) )
226             {
227                 fullscreen = FULLSCREEN_CURRENT;
228             }
229             else if( !strcmp( psz_attrvalue, "full" ) )
230             {
231                 fullscreen = FULLSCREEN_FULL;
232             }
233             else
234             {
235                 fullscreen = FULLSCREEN_NORMAL;
236             }
237         }
238         else if( !strcmp( psz_attrname, "href" ) )
239         {
240             psz_href = psz_attrvalue;
241             psz_attrvalue = NULL;
242         }
243         else if( !strcmp( psz_attrname, "kioskmode" ) )
244         {
245             if( !strcmp( psz_attrvalue, "true" ) )
246             {
247                 b_kioskmode = VLC_TRUE;
248             }
249             else
250             {
251                 b_kioskmode = VLC_FALSE;
252             }
253         }
254         else if( !strcmp( psz_attrname, "loop" ) )
255         {
256             if( !strcmp( psz_attrvalue, "true" ) )
257             {
258                 loop = LOOP_TRUE;
259             }
260             else if( !strcmp( psz_attrvalue, "palindrome" ) )
261             {
262                 loop = LOOP_PALINDROME;
263             }
264             else
265             {
266                 loop = LOOP_FALSE;
267             }
268         }
269         else if( !strcmp( psz_attrname, "movieid" ) )
270         {
271             i_movieid = atoi( psz_attrvalue );
272         }
273         else if( !strcmp( psz_attrname, "moviename" ) )
274         {
275             psz_moviename = psz_attrvalue;
276             psz_attrvalue = NULL;
277         }
278         else if( !strcmp( psz_attrname, "playeveryframe" ) )
279         {
280             if( !strcmp( psz_attrvalue, "true" ) )
281             {
282                 b_playeveryframe = VLC_TRUE;
283             }
284             else
285             {
286                 b_playeveryframe = VLC_FALSE;
287             }
288         }
289         else if( !strcmp( psz_attrname, "qtnext" ) )
290         {
291             psz_qtnext = psz_attrvalue;
292             psz_attrvalue = NULL;
293         }
294         else if( !strcmp( psz_attrname, "quitwhendone" ) )
295         {
296             if( !strcmp( psz_attrvalue, "true" ) )
297             {
298                 b_quitwhendone = VLC_TRUE;
299             }
300             else
301             {
302                 b_quitwhendone = VLC_FALSE;
303             }
304         }
305         else if( !strcmp( psz_attrname, "src" ) )
306         {
307             psz_src = psz_attrvalue;
308             psz_attrvalue = NULL;
309         }
310         else if( !strcmp( psz_attrname, "mimetype" ) )
311         {
312             psz_mimetype = psz_attrvalue;
313             psz_attrvalue = NULL;
314         }
315         else if( !strcmp( psz_attrname, "volume" ) )
316         {
317             i_volume = atoi( psz_attrvalue );
318         }
319         else
320         {
321             msg_Dbg( p_demux, "Attribute %s with value %s isn't valid",
322                      psz_attrname, psz_attrvalue );
323         }
324         FREE( psz_attrname );
325         FREE( psz_attrvalue );
326     }
327
328     msg_Dbg( p_demux, "autoplay: %s (unused by VLC)",
329              b_autoplay==VLC_TRUE ? "true": "false" );
330     msg_Dbg( p_demux, "controler: %s (unused by VLC)",
331              b_controler==VLC_TRUE?"true": "false" );
332     msg_Dbg( p_demux, "fullscreen: %s (unused by VLC)",
333              ppsz_fullscreen[fullscreen] );
334     msg_Dbg( p_demux, "href: %s", psz_href );
335     msg_Dbg( p_demux, "kioskmode: %s (unused by VLC)",
336              b_kioskmode==VLC_TRUE?"true":"false" );
337     msg_Dbg( p_demux, "loop: %s (unused by VLC)", ppsz_loop[loop] );
338     msg_Dbg( p_demux, "movieid: %d (unused by VLC)", i_movieid );
339     msg_Dbg( p_demux, "moviename: %s", psz_moviename );
340     msg_Dbg( p_demux, "playeverframe: %s (unused by VLC)",
341              b_playeveryframe==VLC_TRUE?"true":"false" );
342     msg_Dbg( p_demux, "qtnext: %s", psz_qtnext );
343     msg_Dbg( p_demux, "quitwhendone: %s (unused by VLC)",
344              b_quitwhendone==VLC_TRUE?"true":"false" );
345     msg_Dbg( p_demux, "src: %s", psz_src );
346     msg_Dbg( p_demux, "mimetype: %s", psz_mimetype );
347     msg_Dbg( p_demux, "volume: %d (unused by VLC)", i_volume );
348
349
350     if( !psz_src )
351     {
352         msg_Err( p_demux, "Mandatory attribute 'src' not found" );
353     }
354     else
355     {
356         p_input = input_ItemNewExt( p_sys->p_playlist,
357                                 psz_src, psz_moviename, 0, NULL, -1 );
358 #define SADD_INFO( type, field ) if( field ) { input_ItemAddInfo( \
359                     p_input, "QuickTime Media Link", _(type), "%s", field ) ; }
360         SADD_INFO( "href", psz_href );
361         SADD_INFO( "mime type", psz_mimetype );
362         playlist_BothAddInput( p_sys->p_playlist, p_input,
363                                p_sys->p_item_in_category,
364                                PLAYLIST_APPEND | PLAYLIST_SPREPARSE,
365                                PLAYLIST_END, NULL, NULL, VLC_FALSE );
366         if( psz_qtnext )
367         {
368             p_input = input_ItemNewExt( p_sys->p_playlist,
369                                         psz_qtnext, NULL, 0, NULL, -1 );
370             playlist_BothAddInput( p_sys->p_playlist, p_input,
371                                    p_sys->p_item_in_category,
372                                    PLAYLIST_APPEND | PLAYLIST_SPREPARSE,
373                                    PLAYLIST_END, NULL, NULL, VLC_FALSE );
374         }
375     }
376
377     HANDLE_PLAY_AND_RELEASE;
378
379     p_sys->p_playlist = NULL;
380
381     FREE( psz_href );
382     FREE( psz_moviename );
383     FREE( psz_qtnext );
384     FREE( psz_src );
385     FREE( psz_mimetype );
386
387     return -1; /* Needed for correct operation of go back */
388 }
389
390 static int Control( demux_t *p_demux, int i_query, va_list args )
391 {
392     return VLC_EGENERIC;
393 }