]> git.sesse.net Git - vlc/blob - modules/demux/playlist/qtl.c
413a8ca8611d63ae948ec70f7a2c8cc945556060
[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 <stdlib.h>                                      /* malloc(), free() */
51 #include <ctype.h>                                              /* isspace() */
52
53 #include <vlc/vlc.h>
54 #include <vlc/input.h>
55 #include <vlc/intf.h>
56
57 #include <errno.h>                                                 /* ENOMEM */
58 #include "playlist.h"
59 #include "vlc_xml.h"
60
61 struct demux_sys_t
62 {
63     playlist_t *p_playlist;
64     playlist_item_t *p_current;
65     playlist_item_t *p_item_in_category;
66     int i_parent_id;
67
68     xml_t *p_xml;
69     xml_reader_t *p_xml_reader;
70 };
71
72 typedef enum { FULLSCREEN_NORMAL,
73                FULLSCREEN_DOUBLE,
74                FULLSCREEN_HALF,
75                FULLSCREEN_CURRENT,
76                FULLSCREEN_FULL } qtl_fullscreen_t;
77 char* ppsz_fullscreen[] = { "normal", "double", "half", "current", "full" };
78 typedef enum { LOOP_TRUE,
79                LOOP_FALSE,
80                LOOP_PALINDROME } qtl_loop_t;
81 char* ppsz_loop[] = { "true", "false", "palindrome" };
82
83 /*****************************************************************************
84  * Local prototypes
85  *****************************************************************************/
86 static int Demux( demux_t *p_demux);
87 static int Control( demux_t *p_demux, int i_query, va_list args );
88
89 /*****************************************************************************
90  * Import_QTL: main import function
91  *****************************************************************************/
92 int E_(Import_QTL)( vlc_object_t *p_this )
93 {
94     demux_t *p_demux = (demux_t *)p_this;
95     demux_sys_t *p_sys;
96
97     char    *psz_ext;
98
99     psz_ext = strrchr ( p_demux->psz_path, '.' );
100
101     if( strcmp( psz_ext, ".qtl" ) )
102     {
103         return VLC_EGENERIC;
104     }
105     msg_Dbg( p_demux, "using QuickTime Media Link playlist import");
106
107     p_demux->pf_control = Control;
108     p_demux->pf_demux = Demux;
109     p_demux->p_sys = p_sys = malloc( sizeof(demux_sys_t) );
110     if( p_sys == NULL )
111     {
112         msg_Err( p_demux, "out of memory" );
113         return VLC_ENOMEM;
114     }
115
116     p_sys->p_playlist = NULL;
117     p_sys->p_xml = NULL;
118     p_sys->p_xml_reader = NULL;
119
120     return VLC_SUCCESS;
121 }
122
123 /*****************************************************************************
124  * Deactivate: frees unused data
125  *****************************************************************************/
126 void E_(Close_QTL)( vlc_object_t *p_this )
127 {
128     demux_t *p_demux = (demux_t *)p_this;
129     demux_sys_t *p_sys = p_demux->p_sys;
130
131     if( p_sys->p_playlist )
132         vlc_object_release( p_sys->p_playlist );
133     if( p_sys->p_xml_reader )
134         xml_ReaderDelete( p_sys->p_xml, p_sys->p_xml_reader );
135     if( p_sys->p_xml )
136         xml_Delete( p_sys->p_xml );
137     free( p_sys );
138 }
139
140 #define FREE( a ) if( a ) free( a );
141
142 static int Demux( demux_t *p_demux )
143 {
144     demux_sys_t *p_sys = p_demux->p_sys;
145     xml_t *p_xml;
146     xml_reader_t *p_xml_reader;
147     char *psz_eltname = NULL;
148
149     /* List of all possible attributes. The only required one is "src" */
150     vlc_bool_t b_autoplay = VLC_FALSE;
151     vlc_bool_t b_controler = VLC_TRUE;
152     qtl_fullscreen_t fullscreen = VLC_FALSE;
153     char *psz_href = NULL;
154     vlc_bool_t b_kioskmode = VLC_FALSE;
155     qtl_loop_t loop = LOOP_FALSE;
156     int i_movieid = -1;
157     char *psz_moviename = NULL;
158     vlc_bool_t b_playeveryframe = VLC_FALSE;
159     char *psz_qtnext = NULL;
160     vlc_bool_t b_quitwhendone = VLC_FALSE;
161     char *psz_src = NULL;
162     char *psz_mimetype = NULL;
163     int i_volume = 100;
164
165     INIT_PLAYLIST_STUFF;
166
167     p_sys->p_playlist = p_playlist;
168     p_sys->p_current = p_current;
169     p_sys->i_parent_id = i_parent_id;
170     p_sys->p_item_in_category = p_item_in_category;
171
172     p_xml = p_sys->p_xml = xml_Create( p_demux );
173     if( !p_xml ) return -1;
174
175     p_xml_reader = xml_ReaderCreate( p_xml, p_demux->s );
176     if( !p_xml_reader ) return -1;
177     p_sys->p_xml_reader = p_xml_reader;
178
179     /* check root node */
180     if( xml_ReaderRead( p_xml_reader ) != 1 )
181     {
182         msg_Err( p_demux, "invalid file (no root node)" );
183         return -1;
184     }
185
186     if( xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM ||
187         ( psz_eltname = xml_ReaderName( p_xml_reader ) ) == NULL ||
188         strcmp( psz_eltname, "embed" ) )
189     {
190         msg_Err( p_demux, "invalid root node %i, %s",
191                  xml_ReaderNodeType( p_xml_reader ), psz_eltname );
192         FREE( psz_eltname );
193
194         /* second line has <?quicktime tag ... so we try to skip it */
195         msg_Dbg( p_demux, "trying to read one more node" );
196         xml_ReaderRead( p_xml_reader );
197         if( xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM ||
198             ( psz_eltname = xml_ReaderName( p_xml_reader ) ) == NULL ||
199             strcmp( psz_eltname, "embed" ) )
200         {
201             msg_Err( p_demux, "invalid root node %i, %s",
202                      xml_ReaderNodeType( p_xml_reader ), psz_eltname );
203             FREE( psz_eltname );
204             return -1;
205         }
206     }
207     FREE( psz_eltname );
208
209     while( xml_ReaderNextAttr( p_sys->p_xml_reader ) == VLC_SUCCESS )
210     {
211         char *psz_attrname = xml_ReaderName( p_sys->p_xml_reader );
212         char *psz_attrvalue = xml_ReaderValue( p_sys->p_xml_reader );
213
214         if( !psz_attrname || !psz_attrvalue )
215         {
216             FREE( psz_attrname );
217             FREE( psz_attrvalue );
218             return -1;
219         }
220
221         if( !strcmp( psz_attrname, "autoplay" ) )
222         {
223             if( !strcmp( psz_attrvalue, "true" ) )
224             {
225                 b_autoplay = VLC_TRUE;
226             }
227             else
228             {
229                 b_autoplay = VLC_FALSE;
230             }
231         }
232         else if( !strcmp( psz_attrname, "controler" ) )
233         {
234             if( !strcmp( psz_attrvalue, "false" ) )
235             {
236                 b_controler = VLC_FALSE;
237             }
238             else
239             {
240                 b_controler = VLC_TRUE;
241             }
242         }
243         else if( !strcmp( psz_attrname, "fullscreen" ) )
244         {
245             if( !strcmp( psz_attrvalue, "double" ) )
246             {
247                 fullscreen = FULLSCREEN_DOUBLE;
248             }
249             else if( !strcmp( psz_attrvalue, "half" ) )
250             {
251                 fullscreen = FULLSCREEN_HALF;
252             }
253             else if( !strcmp( psz_attrvalue, "current" ) )
254             {
255                 fullscreen = FULLSCREEN_CURRENT;
256             }
257             else if( !strcmp( psz_attrvalue, "full" ) )
258             {
259                 fullscreen = FULLSCREEN_FULL;
260             }
261             else
262             {
263                 fullscreen = FULLSCREEN_NORMAL;
264             }
265         }
266         else if( !strcmp( psz_attrname, "href" ) )
267         {
268             psz_href = psz_attrvalue;
269             psz_attrvalue = NULL;
270         }
271         else if( !strcmp( psz_attrname, "kioskmode" ) )
272         {
273             if( !strcmp( psz_attrvalue, "true" ) )
274             {
275                 b_kioskmode = VLC_TRUE;
276             }
277             else
278             {
279                 b_kioskmode = VLC_FALSE;
280             }
281         }
282         else if( !strcmp( psz_attrname, "loop" ) )
283         {
284             if( !strcmp( psz_attrvalue, "true" ) )
285             {
286                 loop = LOOP_TRUE;
287             }
288             else if( !strcmp( psz_attrvalue, "palindrome" ) )
289             {
290                 loop = LOOP_PALINDROME;
291             }
292             else
293             {
294                 loop = LOOP_FALSE;
295             }
296         }
297         else if( !strcmp( psz_attrname, "movieid" ) )
298         {
299             i_movieid = atoi( psz_attrvalue );
300         }
301         else if( !strcmp( psz_attrname, "moviename" ) )
302         {
303             psz_moviename = psz_attrvalue;
304             psz_attrvalue = NULL;
305         }
306         else if( !strcmp( psz_attrname, "playeveryframe" ) )
307         {
308             if( !strcmp( psz_attrvalue, "true" ) )
309             {
310                 b_playeveryframe = VLC_TRUE;
311             }
312             else
313             {
314                 b_playeveryframe = VLC_FALSE;
315             }
316         }
317         else if( !strcmp( psz_attrname, "qtnext" ) )
318         {
319             psz_qtnext = psz_attrvalue;
320             psz_attrvalue = NULL;
321         }
322         else if( !strcmp( psz_attrname, "quitwhendone" ) )
323         {
324             if( !strcmp( psz_attrvalue, "true" ) )
325             {
326                 b_quitwhendone = VLC_TRUE;
327             }
328             else
329             {
330                 b_quitwhendone = VLC_FALSE;
331             }
332         }
333         else if( !strcmp( psz_attrname, "src" ) )
334         {
335             psz_src = psz_attrvalue;
336             psz_attrvalue = NULL;
337         }
338         else if( !strcmp( psz_attrname, "mimetype" ) )
339         {
340             psz_mimetype = psz_attrvalue;
341             psz_attrvalue = NULL;
342         }
343         else if( !strcmp( psz_attrname, "volume" ) )
344         {
345             i_volume = atoi( psz_attrvalue );
346         }
347         else
348         {
349             msg_Dbg( p_demux, "Attribute %s with value %s isn't valid",
350                      psz_attrname, psz_attrvalue );
351         }
352         FREE( psz_attrname );
353         FREE( psz_attrvalue );
354     }
355
356     msg_Dbg( p_demux, "autoplay: %s (unused by VLC)",
357              b_autoplay==VLC_TRUE ? "true": "false" );
358     msg_Dbg( p_demux, "controler: %s (unused by VLC)",
359              b_controler==VLC_TRUE?"true": "false" );
360     msg_Dbg( p_demux, "fullscreen: %s (unused by VLC)",
361              ppsz_fullscreen[fullscreen] );
362     msg_Dbg( p_demux, "href: %s", psz_href );
363     msg_Dbg( p_demux, "kioskmode: %s (unused by VLC)",
364              b_kioskmode==VLC_TRUE?"true":"false" );
365     msg_Dbg( p_demux, "loop: %s (unused by VLC)", ppsz_loop[loop] );
366     msg_Dbg( p_demux, "movieid: %d (unused by VLC)", i_movieid );
367     msg_Dbg( p_demux, "moviename: %s", psz_moviename );
368     msg_Dbg( p_demux, "playeverframe: %s (unused by VLC)",
369              b_playeveryframe==VLC_TRUE?"true":"false" );
370     msg_Dbg( p_demux, "qtnext: %s", psz_qtnext );
371     msg_Dbg( p_demux, "quitwhendone: %s (unused by VLC)",
372              b_quitwhendone==VLC_TRUE?"true":"false" );
373     msg_Dbg( p_demux, "src: %s", psz_src );
374     msg_Dbg( p_demux, "mimetype: %s", psz_mimetype );
375     msg_Dbg( p_demux, "volume: %d (unused by VLC)", i_volume );
376
377
378     if( !psz_src )
379     {
380         msg_Err( p_demux, "Mandatory attribute 'src' not found" );
381     }
382     else
383     {
384         p_input = input_ItemNewExt( p_sys->p_playlist,
385                                 psz_src, psz_moviename, 0, NULL, -1 );
386 #define SADD_INFO( type, field ) if( field ) { vlc_input_item_AddInfo( \
387                     p_input, _("QuickTime Media Link"), _(type), "%s", field ) ; }
388         SADD_INFO( "href", psz_href );
389         SADD_INFO( "mime type", psz_mimetype );
390         playlist_AddWhereverNeeded( p_sys->p_playlist, p_input,
391                             p_sys->p_current, p_sys->p_item_in_category,
392                             (p_sys->i_parent_id > 0 ) ? VLC_TRUE: VLC_FALSE,
393                             PLAYLIST_APPEND );
394
395         if( psz_qtnext )
396         {
397             p_input = input_ItemNewExt( p_sys->p_playlist,
398                                         psz_qtnext, psz_qtnext, 0, NULL, -1 );
399             playlist_AddWhereverNeeded( p_sys->p_playlist, p_input,
400                             p_sys->p_current, p_sys->p_item_in_category,
401                             (p_sys->i_parent_id > 0 ) ? VLC_TRUE: VLC_FALSE,
402                             PLAYLIST_APPEND );
403         }
404     }
405
406     HANDLE_PLAY_AND_RELEASE;
407
408     p_sys->p_playlist = NULL;
409
410     FREE( psz_href );
411     FREE( psz_moviename );
412     FREE( psz_qtnext );
413     FREE( psz_src );
414     FREE( psz_mimetype );
415
416     return VLC_SUCCESS;
417 }
418
419 static int Control( demux_t *p_demux, int i_query, va_list args )
420 {
421     return VLC_EGENERIC;
422 }