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