Qt: Change almost all icons
[vlc.git] / modules / access / dvdnav.c
1 /*****************************************************************************
2  * dvdnav.c: DVD module using the dvdnav library.
3  *****************************************************************************
4  * Copyright (C) 2004-2009 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * NOTA BENE: this module requires the linking against a library which is
26  * known to require licensing under the GNU General Public License version 2
27  * (or later). Therefore, the result of compiling this module will normally
28  * be subject to the terms of that later license.
29  *****************************************************************************/
30
31
32 /*****************************************************************************
33  * Preamble
34  *****************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 # include "config.h"
38 #endif
39
40 #include <assert.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #include <errno.h>
44 #include <unistd.h>     /* close() */
45
46 #include <vlc_common.h>
47 #include <vlc_plugin.h>
48 #include <vlc_input.h>
49 #include <vlc_access.h>
50 #include <vlc_demux.h>
51 #include <vlc_charset.h>
52 #include <vlc_fs.h>
53 #include <vlc_vout.h>
54 #include <vlc_dialog.h>
55 #include <vlc_iso_lang.h>
56
57 /* FIXME we should find a better way than including that */
58 #include "../../src/text/iso-639_def.h"
59
60
61 #include <dvdnav/dvdnav.h>
62
63 #include "../demux/mpeg/pes.h"
64 #include "../demux/mpeg/ps.h"
65
66 /*****************************************************************************
67  * Module descriptor
68  *****************************************************************************/
69 #define ANGLE_TEXT N_("DVD angle")
70 #define ANGLE_LONGTEXT N_( \
71      "Default DVD angle." )
72
73 #define MENU_TEXT N_("Start directly in menu")
74 #define MENU_LONGTEXT N_( \
75     "Start the DVD directly in the main menu. This "\
76     "will try to skip all the useless warning introductions." )
77
78 #define LANGUAGE_DEFAULT ("en")
79
80 static int  AccessDemuxOpen ( vlc_object_t * );
81 static void Close( vlc_object_t * );
82
83 #if DVDREAD_VERSION >= 50300 && defined( HAVE_STREAM_CB_IN_DVDNAV_H )
84 #define HAVE_DVDNAV_DEMUX
85 static int  DemuxOpen ( vlc_object_t * );
86 #endif
87
88 vlc_module_begin ()
89     set_shortname( N_("DVD with menus") )
90     set_description( N_("DVDnav Input") )
91     set_category( CAT_INPUT )
92     set_subcategory( SUBCAT_INPUT_ACCESS )
93     add_integer( "dvdnav-angle", 1, ANGLE_TEXT,
94         ANGLE_LONGTEXT, false )
95     add_bool( "dvdnav-menu", true,
96         MENU_TEXT, MENU_LONGTEXT, false )
97     set_capability( "access_demux", 5 )
98     add_shortcut( "dvd", "dvdnav", "file" )
99     set_callbacks( AccessDemuxOpen, Close )
100 #ifdef HAVE_DVDNAV_DEMUX
101     add_submodule()
102         set_description( N_("DVDnav demuxer") )
103         set_category( CAT_INPUT )
104         set_subcategory( SUBCAT_INPUT_DEMUX )
105         set_capability( "demux", 5 )
106         set_callbacks( DemuxOpen, Close )
107         add_shortcut( "dvd", "iso" )
108 #endif
109 vlc_module_end ()
110
111 /* Shall we use libdvdnav's read ahead cache? */
112 #ifdef __OS2__
113 #define DVD_READ_CACHE 0
114 #else
115 #define DVD_READ_CACHE 1
116 #endif
117
118 /*****************************************************************************
119  * Local prototypes
120  *****************************************************************************/
121 struct demux_sys_t
122 {
123     dvdnav_t    *dvdnav;
124
125     /* */
126     bool        b_reset_pcr;
127     bool        b_readahead;
128
129     struct
130     {
131         bool         b_created;
132         bool         b_enabled;
133         vlc_mutex_t  lock;
134         vlc_timer_t  timer;
135     } still;
136
137     /* track */
138     ps_track_t  tk[PS_TK_COUNT];
139     int         i_mux_rate;
140
141     /* event */
142     vout_thread_t *p_vout;
143
144     /* palette for menus */
145     uint32_t clut[16];
146     uint8_t  palette[4][4];
147     bool b_spu_change;
148
149     /* Aspect ration */
150     struct {
151         unsigned i_num;
152         unsigned i_den;
153     } sar;
154
155     /* */
156     int           i_title;
157     input_title_t **title;
158
159     /* length of program group chain */
160     mtime_t     i_pgc_length;
161     int         i_vobu_index;
162     int         i_vobu_flush;
163 };
164
165 static int Control( demux_t *, int, va_list );
166 static int Demux( demux_t * );
167 static int DemuxBlock( demux_t *, const uint8_t *, int );
168 static void DemuxForceStill( demux_t * );
169
170 static void DemuxTitles( demux_t * );
171 static void ESSubtitleUpdate( demux_t * );
172 static void ButtonUpdate( demux_t *, bool );
173
174 static void ESNew( demux_t *, int );
175 static int ProbeDVD( const char * );
176
177 static char *DemuxGetLanguageCode( demux_t *p_demux, const char *psz_var );
178
179 static int ControlInternal( demux_t *, int, ... );
180
181 static void StillTimer( void * );
182
183 static int EventMouse( vlc_object_t *, char const *,
184                        vlc_value_t, vlc_value_t, void * );
185 static int EventIntf( vlc_object_t *, char const *,
186                       vlc_value_t, vlc_value_t, void * );
187
188 /*****************************************************************************
189  * CommonOpen:
190  *****************************************************************************/
191 static int CommonOpen( vlc_object_t *p_this,
192                        dvdnav_t *p_dvdnav, bool b_readahead )
193 {
194     demux_t     *p_demux = (demux_t*)p_this;
195     demux_sys_t *p_sys;
196     int         i_angle;
197     char        *psz_code;
198
199     assert( p_dvdnav );
200
201     /* Fill p_demux field */
202     DEMUX_INIT_COMMON(); p_sys = p_demux->p_sys;
203     p_sys->dvdnav = p_dvdnav;
204     p_sys->b_reset_pcr = false;
205
206     ps_track_init( p_sys->tk );
207     p_sys->sar.i_num = 0;
208     p_sys->sar.i_den = 0;
209     p_sys->i_mux_rate = 0;
210     p_sys->i_pgc_length = 0;
211     p_sys->b_spu_change = false;
212     p_sys->i_vobu_index = 0;
213     p_sys->i_vobu_flush = 0;
214     p_sys->b_readahead = b_readahead;
215
216     if( 1 )
217     {
218         // Hack for libdvdnav CVS.
219         // Without it dvdnav_get_number_of_titles() fails.
220         // Remove when fixed in libdvdnav CVS.
221         uint8_t buffer[DVD_VIDEO_LB_LEN];
222         int i_event, i_len;
223
224         if( dvdnav_get_next_block( p_sys->dvdnav, buffer, &i_event, &i_len )
225               == DVDNAV_STATUS_ERR )
226         {
227             msg_Warn( p_demux, "dvdnav_get_next_block failed" );
228         }
229
230         dvdnav_sector_search( p_sys->dvdnav, 0, SEEK_SET );
231     }
232
233     /* Configure dvdnav */
234     if( dvdnav_set_readahead_flag( p_sys->dvdnav, p_sys->b_readahead ) !=
235           DVDNAV_STATUS_OK )
236     {
237         msg_Warn( p_demux, "cannot set read-a-head flag" );
238     }
239
240     if( dvdnav_set_PGC_positioning_flag( p_sys->dvdnav, 1 ) !=
241           DVDNAV_STATUS_OK )
242     {
243         msg_Warn( p_demux, "cannot set PGC positioning flag" );
244     }
245
246     /* Set menu language */
247     psz_code = DemuxGetLanguageCode( p_demux, "menu-language" );
248     if( dvdnav_menu_language_select( p_sys->dvdnav, psz_code ) !=
249         DVDNAV_STATUS_OK )
250     {
251         msg_Warn( p_demux, "can't set menu language to '%s' (%s)",
252                   psz_code, dvdnav_err_to_string( p_sys->dvdnav ) );
253         /* We try to fall back to 'en' */
254         if( strcmp( psz_code, LANGUAGE_DEFAULT ) )
255             dvdnav_menu_language_select( p_sys->dvdnav, (char*)LANGUAGE_DEFAULT );
256     }
257     free( psz_code );
258
259     /* Set audio language */
260     psz_code = DemuxGetLanguageCode( p_demux, "audio-language" );
261     if( dvdnav_audio_language_select( p_sys->dvdnav, psz_code ) !=
262         DVDNAV_STATUS_OK )
263     {
264         msg_Warn( p_demux, "can't set audio language to '%s' (%s)",
265                   psz_code, dvdnav_err_to_string( p_sys->dvdnav ) );
266         /* We try to fall back to 'en' */
267         if( strcmp( psz_code, LANGUAGE_DEFAULT ) )
268             dvdnav_audio_language_select( p_sys->dvdnav, (char*)LANGUAGE_DEFAULT );
269     }
270     free( psz_code );
271
272     /* Set spu language */
273     psz_code = DemuxGetLanguageCode( p_demux, "sub-language" );
274     if( dvdnav_spu_language_select( p_sys->dvdnav, psz_code ) !=
275         DVDNAV_STATUS_OK )
276     {
277         msg_Warn( p_demux, "can't set spu language to '%s' (%s)",
278                   psz_code, dvdnav_err_to_string( p_sys->dvdnav ) );
279         /* We try to fall back to 'en' */
280         if( strcmp( psz_code, LANGUAGE_DEFAULT ) )
281             dvdnav_spu_language_select(p_sys->dvdnav, (char*)LANGUAGE_DEFAULT );
282     }
283     free( psz_code );
284
285     DemuxTitles( p_demux );
286
287     if( var_CreateGetBool( p_demux, "dvdnav-menu" ) )
288     {
289         msg_Dbg( p_demux, "trying to go to dvd menu" );
290
291         if( dvdnav_title_play( p_sys->dvdnav, 1 ) != DVDNAV_STATUS_OK )
292         {
293             msg_Err( p_demux, "cannot set title (can't decrypt DVD?)" );
294             vlc_dialog_display_error( p_demux, _("Playback failure"), "%s",
295                 _("VLC cannot set the DVD's title. It possibly "
296                   "cannot decrypt the entire disc.") );
297             free( p_sys );
298             return VLC_EGENERIC;
299         }
300
301         if( dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Title ) !=
302             DVDNAV_STATUS_OK )
303         {
304             /* Try going to menu root */
305             if( dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Root ) !=
306                 DVDNAV_STATUS_OK )
307                     msg_Warn( p_demux, "cannot go to dvd menu" );
308         }
309     }
310
311     i_angle = var_CreateGetInteger( p_demux, "dvdnav-angle" );
312     if( i_angle <= 0 ) i_angle = 1;
313
314     /* FIXME hack hack hack hack FIXME */
315     /* Get p_input and create variable */
316     var_Create( p_demux->p_input, "x-start", VLC_VAR_INTEGER );
317     var_Create( p_demux->p_input, "y-start", VLC_VAR_INTEGER );
318     var_Create( p_demux->p_input, "x-end", VLC_VAR_INTEGER );
319     var_Create( p_demux->p_input, "y-end", VLC_VAR_INTEGER );
320     var_Create( p_demux->p_input, "color", VLC_VAR_ADDRESS );
321     var_Create( p_demux->p_input, "menu-palette", VLC_VAR_ADDRESS );
322     var_Create( p_demux->p_input, "highlight", VLC_VAR_BOOL );
323
324     /* catch vout creation event */
325     var_AddCallback( p_demux->p_input, "intf-event", EventIntf, p_demux );
326
327     p_sys->still.b_enabled = false;
328     vlc_mutex_init( &p_sys->still.lock );
329     if( !vlc_timer_create( &p_sys->still.timer, StillTimer, p_sys ) )
330         p_sys->still.b_created = true;
331
332     return VLC_SUCCESS;
333 }
334
335 /*****************************************************************************
336  * AccessDemuxOpen:
337  *****************************************************************************/
338 static int AccessDemuxOpen ( vlc_object_t *p_this )
339 {
340     demux_t *p_demux = (demux_t*)p_this;
341     dvdnav_t *p_dvdnav = NULL;
342     char *psz_file = NULL;
343     const char *psz_path = NULL;
344     int i_ret = VLC_EGENERIC;
345     bool forced = false;
346
347     if( !strncmp(p_demux->psz_access, "dvd", 3) )
348         forced = true;
349
350     if( !p_demux->psz_file || !*p_demux->psz_file )
351     {
352         /* Only when selected */
353         if( !forced )
354             return VLC_EGENERIC;
355
356         psz_file = var_InheritString( p_this, "dvd" );
357     }
358     else
359         psz_file = strdup( p_demux->psz_file );
360
361 #if defined( _WIN32 ) || defined( __OS2__ )
362     if( psz_file != NULL )
363     {
364         /* Remove trailing backslash, otherwise dvdnav_open will fail */
365         size_t flen = strlen( psz_file );
366         if( flen > 0 && psz_file[flen - 1] == '\\' )
367             psz_file[flen - 1] = '\0';
368     }
369     else
370         psz_file = strdup("");
371 #endif
372
373     if( unlikely(psz_file == NULL) )
374         return VLC_EGENERIC;
375
376     /* Try some simple probing to avoid going through dvdnav_open too often */
377     if( !forced && ProbeDVD( psz_file ) != VLC_SUCCESS )
378         goto bailout;
379
380     /* Open dvdnav */
381     psz_path = ToLocale( psz_file );
382     if( dvdnav_open( &p_dvdnav, psz_path ) != DVDNAV_STATUS_OK )
383     {
384         msg_Warn( p_demux, "cannot open DVD (%s)", psz_file);
385         goto bailout;
386     }
387
388     i_ret = CommonOpen( p_this, p_dvdnav, !!DVD_READ_CACHE );
389     if( i_ret != VLC_SUCCESS )
390         dvdnav_close( p_dvdnav );
391
392 bailout:
393     free( psz_file );
394     if( psz_path )
395         LocaleFree( psz_path );
396     return i_ret;
397 }
398
399 #ifdef HAVE_DVDNAV_DEMUX
400 /*****************************************************************************
401  * StreamProbeDVD: very weak probing that avoids going too often into a dvdnav_open()
402  *****************************************************************************/
403 static int StreamProbeDVD( stream_t *s )
404 {
405     /* first sector should be filled with zeros */
406     ssize_t i_peek;
407     const uint8_t *p_peek;
408     i_peek = vlc_stream_Peek( s, &p_peek, 2048 );
409     if( i_peek < 512 ) {
410         return VLC_EGENERIC;
411     }
412     while (i_peek > 0) {
413         if (p_peek[ --i_peek ]) {
414             return VLC_EGENERIC;
415         }
416     }
417
418     /* ISO 9660 volume descriptor */
419     char iso_dsc[6];
420     if( vlc_stream_Seek( s, 0x8000 + 1 ) != VLC_SUCCESS
421      || vlc_stream_Read( s, iso_dsc, sizeof (iso_dsc) ) < (int)sizeof (iso_dsc)
422      || memcmp( iso_dsc, "CD001\x01", 6 ) )
423         return VLC_EGENERIC;
424
425     /* Try to find the anchor (2 bytes at LBA 256) */
426     uint16_t anchor;
427
428     if( vlc_stream_Seek( s, 256 * DVD_VIDEO_LB_LEN ) == VLC_SUCCESS
429      && vlc_stream_Read( s, &anchor, 2 ) == 2
430      && GetWLE( &anchor ) == 2 )
431         return VLC_SUCCESS;
432     else
433         return VLC_EGENERIC;
434 }
435
436 /*****************************************************************************
437  * dvdnav stream callbacks
438  *****************************************************************************/
439 static int stream_cb_seek( void *s, uint64_t pos )
440 {
441     return vlc_stream_Seek( (stream_t *)s, pos );
442 }
443
444 static int stream_cb_read( void *s, void* buffer, int size )
445 {
446     return vlc_stream_Read( (stream_t *)s, buffer, size );
447 }
448
449 /*****************************************************************************
450  * DemuxOpen:
451  *****************************************************************************/
452 static int DemuxOpen ( vlc_object_t *p_this )
453 {
454     demux_t *p_demux = (demux_t*)p_this;
455     dvdnav_t *p_dvdnav = NULL;
456     bool forced = false, b_seekable = false;
457
458     if( p_demux->psz_demux != NULL
459      && !strncmp(p_demux->psz_demux, "dvd", 3) )
460         forced = true;
461
462     /* StreamProbeDVD need FASTSEEK, but if dvd is forced, we don't probe thus
463      * don't need fastseek */
464     vlc_stream_Control( p_demux->s, forced ? STREAM_CAN_SEEK : STREAM_CAN_FASTSEEK,
465                     &b_seekable );
466     if( !b_seekable )
467         return VLC_EGENERIC;
468
469     /* Try some simple probing to avoid going through dvdnav_open too often */
470     if( !forced && StreamProbeDVD( p_demux->s ) != VLC_SUCCESS )
471         return VLC_EGENERIC;
472
473     static dvdnav_stream_cb stream_cb =
474     {
475         .pf_seek = stream_cb_seek,
476         .pf_read = stream_cb_read,
477         .pf_readv = NULL,
478     };
479
480     /* Open dvdnav with stream callbacks */
481     if( dvdnav_open_stream( &p_dvdnav, p_demux->s,
482                             &stream_cb ) != DVDNAV_STATUS_OK )
483     {
484         msg_Warn( p_demux, "cannot open DVD with open_stream" );
485         return VLC_EGENERIC;
486     }
487
488     int i_ret = CommonOpen( p_this, p_dvdnav, false );
489     if( i_ret != VLC_SUCCESS )
490         dvdnav_close( p_dvdnav );
491     return i_ret;
492 }
493 #endif
494
495 /*****************************************************************************
496  * Close:
497  *****************************************************************************/
498 static void Close( vlc_object_t *p_this )
499 {
500     demux_t     *p_demux = (demux_t*)p_this;
501     demux_sys_t *p_sys = p_demux->p_sys;
502
503     /* Stop vout event handler */
504     var_DelCallback( p_demux->p_input, "intf-event", EventIntf, p_demux );
505     if( p_sys->p_vout != NULL )
506     {   /* Should not happen, but better be safe than sorry. */
507         msg_Warn( p_sys->p_vout, "removing dangling mouse DVD callbacks" );
508         var_DelCallback( p_sys->p_vout, "mouse-moved", EventMouse, p_demux );
509         var_DelCallback( p_sys->p_vout, "mouse-clicked", EventMouse, p_demux );
510     }
511
512     /* Stop still image handler */
513     if( p_sys->still.b_created )
514         vlc_timer_destroy( p_sys->still.timer );
515     vlc_mutex_destroy( &p_sys->still.lock );
516
517     var_Destroy( p_demux->p_input, "highlight" );
518     var_Destroy( p_demux->p_input, "x-start" );
519     var_Destroy( p_demux->p_input, "x-end" );
520     var_Destroy( p_demux->p_input, "y-start" );
521     var_Destroy( p_demux->p_input, "y-end" );
522     var_Destroy( p_demux->p_input, "color" );
523     var_Destroy( p_demux->p_input, "menu-palette" );
524
525     for( int i = 0; i < PS_TK_COUNT; i++ )
526     {
527         ps_track_t *tk = &p_sys->tk[i];
528         if( tk->b_configured )
529         {
530             es_format_Clean( &tk->fmt );
531             if( tk->es ) es_out_Del( p_demux->out, tk->es );
532         }
533     }
534
535     /* Free the array of titles */
536     for( int i = 0; i < p_sys->i_title; i++ )
537         vlc_input_title_Delete( p_sys->title[i] );
538     TAB_CLEAN( p_sys->i_title, p_sys->title );
539
540     dvdnav_close( p_sys->dvdnav );
541     free( p_sys );
542 }
543
544 /*****************************************************************************
545  * Control:
546  *****************************************************************************/
547 static int Control( demux_t *p_demux, int i_query, va_list args )
548 {
549     demux_sys_t *p_sys = p_demux->p_sys;
550     input_title_t ***ppp_title;
551     int i;
552
553     switch( i_query )
554     {
555         case DEMUX_SET_POSITION:
556         case DEMUX_GET_POSITION:
557         case DEMUX_GET_TIME:
558         case DEMUX_GET_LENGTH:
559         {
560             uint32_t pos, len;
561             if( dvdnav_get_position( p_sys->dvdnav, &pos, &len ) !=
562                   DVDNAV_STATUS_OK || len == 0 )
563             {
564                 return VLC_EGENERIC;
565             }
566
567             switch( i_query )
568             {
569             case DEMUX_GET_POSITION:
570                 *va_arg( args, double* ) = (double)pos / (double)len;
571                 return VLC_SUCCESS;
572
573             case DEMUX_SET_POSITION:
574                 pos = va_arg( args, double ) * len;
575                 if( dvdnav_sector_search( p_sys->dvdnav, pos, SEEK_SET ) ==
576                       DVDNAV_STATUS_OK )
577                 {
578                     return VLC_SUCCESS;
579                 }
580                 break;
581
582             case DEMUX_GET_TIME:
583                 if( p_sys->i_pgc_length > 0 )
584                 {
585                     *va_arg( args, int64_t * ) = p_sys->i_pgc_length*pos/len;
586                     return VLC_SUCCESS;
587                 }
588                 break;
589
590             case DEMUX_GET_LENGTH:
591                 if( p_sys->i_pgc_length > 0 )
592                 {
593                     *va_arg( args, int64_t * ) = (int64_t)p_sys->i_pgc_length;
594                     return VLC_SUCCESS;
595                 }
596                 break;
597             }
598             return VLC_EGENERIC;
599         }
600
601         /* Special for access_demux */
602         case DEMUX_CAN_PAUSE:
603         case DEMUX_CAN_SEEK:
604         case DEMUX_CAN_CONTROL_PACE:
605             /* TODO */
606             *va_arg( args, bool * ) = true;
607             return VLC_SUCCESS;
608
609         case DEMUX_SET_PAUSE_STATE:
610             return VLC_SUCCESS;
611
612         case DEMUX_GET_TITLE_INFO:
613             ppp_title = va_arg( args, input_title_t*** );
614             *va_arg( args, int* ) = p_sys->i_title;
615             *va_arg( args, int* ) = 0; /* Title offset */
616             *va_arg( args, int* ) = 1; /* Chapter offset */
617
618             /* Duplicate title infos */
619             *ppp_title = malloc( p_sys->i_title * sizeof( input_title_t * ) );
620             for( i = 0; i < p_sys->i_title; i++ )
621             {
622                 (*ppp_title)[i] = vlc_input_title_Duplicate( p_sys->title[i] );
623             }
624             return VLC_SUCCESS;
625
626         case DEMUX_SET_TITLE:
627             i = va_arg( args, int );
628             if( i == 0 && dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Root )
629                   != DVDNAV_STATUS_OK )
630             {
631                 msg_Warn( p_demux, "cannot set title/chapter" );
632                 return VLC_EGENERIC;
633             }
634
635             if( i != 0 )
636             {
637                 dvdnav_still_skip( p_sys->dvdnav );
638                 if( dvdnav_title_play( p_sys->dvdnav, i ) != DVDNAV_STATUS_OK )
639                 {
640                     msg_Warn( p_demux, "cannot set title/chapter" );
641                     return VLC_EGENERIC;
642                 }
643             }
644
645             p_demux->info.i_update |=
646                 INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
647             p_demux->info.i_title = i;
648             p_demux->info.i_seekpoint = 0;
649             return VLC_SUCCESS;
650
651         case DEMUX_SET_SEEKPOINT:
652             i = va_arg( args, int );
653             if( p_demux->info.i_title == 0 )
654             {
655                 static const int argtab[] = {
656                     DVD_MENU_Escape,
657                     DVD_MENU_Root,
658                     DVD_MENU_Title,
659                     DVD_MENU_Part,
660                     DVD_MENU_Subpicture,
661                     DVD_MENU_Audio,
662                     DVD_MENU_Angle
663                 };
664                 enum { numargs = sizeof(argtab)/sizeof(int) };
665                 if( (unsigned)i >= numargs || DVDNAV_STATUS_OK !=
666                            dvdnav_menu_call(p_sys->dvdnav,argtab[i]) )
667                     return VLC_EGENERIC;
668             }
669             else if( dvdnav_part_play( p_sys->dvdnav, p_demux->info.i_title,
670                                        i + 1 ) != DVDNAV_STATUS_OK )
671             {
672                 msg_Warn( p_demux, "cannot set title/chapter" );
673                 return VLC_EGENERIC;
674             }
675             p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
676             p_demux->info.i_seekpoint = i;
677             return VLC_SUCCESS;
678
679         case DEMUX_GET_PTS_DELAY:
680             *va_arg( args, int64_t * ) =
681                 INT64_C(1000) * var_InheritInteger( p_demux, "disc-caching" );
682             return VLC_SUCCESS;
683
684         case DEMUX_GET_META:
685         {
686             const char *title_name = NULL;
687
688             dvdnav_get_title_string(p_sys->dvdnav, &title_name);
689             if( (NULL != title_name) && ('\0' != title_name[0]) )
690             {
691                 vlc_meta_t *p_meta = va_arg( args, vlc_meta_t* );
692                 vlc_meta_Set( p_meta, vlc_meta_Title, title_name );
693                 return VLC_SUCCESS;
694             }
695             return VLC_EGENERIC;
696         }
697
698         case DEMUX_NAV_ACTIVATE:
699         {
700             pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );
701
702             ButtonUpdate( p_demux, true );
703             dvdnav_button_activate( p_sys->dvdnav, pci );
704             break;
705         }
706
707         case DEMUX_NAV_UP:
708         {
709             pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );
710
711             dvdnav_upper_button_select( p_sys->dvdnav, pci );
712             break;
713         }
714
715         case DEMUX_NAV_DOWN:
716         {
717             pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );
718
719             dvdnav_lower_button_select( p_sys->dvdnav, pci );
720             break;
721         }
722
723         case DEMUX_NAV_LEFT:
724         {
725             pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );
726
727             dvdnav_left_button_select( p_sys->dvdnav, pci );
728             break;
729         }
730
731         case DEMUX_NAV_RIGHT:
732         {
733             pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );
734
735             dvdnav_right_button_select( p_sys->dvdnav, pci );
736             break;
737         }
738
739         case DEMUX_NAV_MENU:
740         {
741             if( dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Title )
742                 != DVDNAV_STATUS_OK )
743             {
744                 msg_Warn( p_demux, "cannot select Title menu" );
745                 if( dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Root )
746                     != DVDNAV_STATUS_OK )
747                 {
748                     msg_Warn( p_demux, "cannot select Root menu" );
749                     return VLC_EGENERIC;
750                 }
751             }
752             p_demux->info.i_update |=
753                 INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
754             p_demux->info.i_title = 0;
755             p_demux->info.i_seekpoint = 2;
756             break;
757         }
758
759         /* TODO implement others */
760         default:
761             return VLC_EGENERIC;
762     }
763
764     return VLC_SUCCESS;
765 }
766
767 static int ControlInternal( demux_t *p_demux, int i_query, ... )
768 {
769     va_list args;
770     int     i_result;
771
772     va_start( args, i_query );
773     i_result = Control( p_demux, i_query, args );
774     va_end( args );
775
776     return i_result;
777 }
778 /*****************************************************************************
779  * Demux:
780  *****************************************************************************/
781 static int Demux( demux_t *p_demux )
782 {
783     demux_sys_t *p_sys = p_demux->p_sys;
784
785     uint8_t buffer[DVD_VIDEO_LB_LEN];
786     uint8_t *packet = buffer;
787     int i_event;
788     int i_len;
789     dvdnav_status_t status;
790
791     if( p_sys->b_readahead )
792         status = dvdnav_get_next_cache_block( p_sys->dvdnav, &packet, &i_event,
793                                               &i_len );
794     else
795         status = dvdnav_get_next_block( p_sys->dvdnav, packet, &i_event,
796                                         &i_len );
797     if( status == DVDNAV_STATUS_ERR )
798     {
799         msg_Warn( p_demux, "cannot get next block (%s)",
800                   dvdnav_err_to_string( p_sys->dvdnav ) );
801         if( p_demux->info.i_title == 0 )
802         {
803             msg_Dbg( p_demux, "jumping to first title" );
804             return ControlInternal( p_demux, DEMUX_SET_TITLE, 1 ) == VLC_SUCCESS ? 1 : -1;
805         }
806         return -1;
807     }
808
809     switch( i_event )
810     {
811     case DVDNAV_BLOCK_OK:   /* mpeg block */
812         vlc_mutex_lock( &p_sys->still.lock );
813         vlc_timer_schedule( p_sys->still.timer, false, 0, 0 );
814         p_sys->still.b_enabled = false;
815         vlc_mutex_unlock( &p_sys->still.lock );
816         if( p_sys->b_reset_pcr )
817         {
818             es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
819             p_sys->b_reset_pcr = false;
820         }
821         DemuxBlock( p_demux, packet, i_len );
822         if( p_sys->i_vobu_index > 0 )
823         {
824             if( p_sys->i_vobu_flush == p_sys->i_vobu_index )
825                 DemuxForceStill( p_demux );
826             p_sys->i_vobu_index++;
827         }
828         break;
829
830     case DVDNAV_NOP:    /* Nothing */
831         msg_Dbg( p_demux, "DVDNAV_NOP" );
832         break;
833
834     case DVDNAV_STILL_FRAME:
835     {
836         dvdnav_still_event_t *event = (dvdnav_still_event_t*)packet;
837         bool b_still_init = false;
838
839         vlc_mutex_lock( &p_sys->still.lock );
840         if( !p_sys->still.b_enabled )
841         {
842             msg_Dbg( p_demux, "DVDNAV_STILL_FRAME" );
843             msg_Dbg( p_demux, "     - length=0x%x", event->length );
844             p_sys->still.b_enabled = true;
845
846             if( event->length != 0xff && p_sys->still.b_created )
847             {
848                 mtime_t delay = event->length * CLOCK_FREQ;
849                 vlc_timer_schedule( p_sys->still.timer, false, delay, 0 );
850             }
851
852             b_still_init = true;
853         }
854         vlc_mutex_unlock( &p_sys->still.lock );
855
856         if( b_still_init )
857         {
858             DemuxForceStill( p_demux );
859             p_sys->b_reset_pcr = true;
860         }
861         msleep( 40000 );
862         break;
863     }
864
865     case DVDNAV_SPU_CLUT_CHANGE:
866     {
867         int i;
868
869         msg_Dbg( p_demux, "DVDNAV_SPU_CLUT_CHANGE" );
870         /* Update color lookup table (16 *uint32_t in packet) */
871         memcpy( p_sys->clut, packet, 16 * sizeof( uint32_t ) );
872
873         /* HACK to get the SPU tracks registered in the right order */
874         for( i = 0; i < 0x1f; i++ )
875         {
876             if( dvdnav_spu_stream_to_lang( p_sys->dvdnav, i ) != 0xffff )
877                 ESNew( p_demux, 0xbd20 + i );
878         }
879         /* END HACK */
880         break;
881     }
882
883     case DVDNAV_SPU_STREAM_CHANGE:
884     {
885         dvdnav_spu_stream_change_event_t *event =
886             (dvdnav_spu_stream_change_event_t*)packet;
887         int i;
888
889         msg_Dbg( p_demux, "DVDNAV_SPU_STREAM_CHANGE" );
890         msg_Dbg( p_demux, "     - physical_wide=%d",
891                  event->physical_wide );
892         msg_Dbg( p_demux, "     - physical_letterbox=%d",
893                  event->physical_letterbox);
894         msg_Dbg( p_demux, "     - physical_pan_scan=%d",
895                  event->physical_pan_scan );
896
897         ESSubtitleUpdate( p_demux );
898         p_sys->b_spu_change = true;
899
900         /* HACK to get the SPU tracks registered in the right order */
901         for( i = 0; i < 0x1f; i++ )
902         {
903             if( dvdnav_spu_stream_to_lang( p_sys->dvdnav, i ) != 0xffff )
904                 ESNew( p_demux, 0xbd20 + i );
905         }
906         /* END HACK */
907         break;
908     }
909
910     case DVDNAV_AUDIO_STREAM_CHANGE:
911     {
912         dvdnav_audio_stream_change_event_t *event =
913             (dvdnav_audio_stream_change_event_t*)packet;
914         msg_Dbg( p_demux, "DVDNAV_AUDIO_STREAM_CHANGE" );
915         msg_Dbg( p_demux, "     - physical=%d", event->physical );
916         /* TODO */
917         break;
918     }
919
920     case DVDNAV_VTS_CHANGE:
921     {
922         int32_t i_title = 0;
923         int32_t i_part  = 0;
924
925         dvdnav_vts_change_event_t *event = (dvdnav_vts_change_event_t*)packet;
926         msg_Dbg( p_demux, "DVDNAV_VTS_CHANGE" );
927         msg_Dbg( p_demux, "     - vtsN=%d", event->new_vtsN );
928         msg_Dbg( p_demux, "     - domain=%d", event->new_domain );
929
930         /* reset PCR */
931         es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
932
933         for( int i = 0; i < PS_TK_COUNT; i++ )
934         {
935             ps_track_t *tk = &p_sys->tk[i];
936             if( tk->b_configured )
937             {
938                 es_format_Clean( &tk->fmt );
939                 if( tk->es ) es_out_Del( p_demux->out, tk->es );
940             }
941             tk->b_configured = false;
942         }
943
944         uint32_t i_width, i_height;
945         if( dvdnav_get_video_resolution( p_sys->dvdnav,
946                                          &i_width, &i_height ) )
947             i_width = i_height = 0;
948         switch( dvdnav_get_video_aspect( p_sys->dvdnav ) )
949         {
950         case 0:
951             p_sys->sar.i_num = 4 * i_height;
952             p_sys->sar.i_den = 3 * i_width;
953             break;
954         case 3:
955             p_sys->sar.i_num = 16 * i_height;
956             p_sys->sar.i_den =  9 * i_width;
957             break;
958         default:
959             p_sys->sar.i_num = 0;
960             p_sys->sar.i_den = 0;
961             break;
962         }
963
964         if( dvdnav_current_title_info( p_sys->dvdnav, &i_title,
965                                        &i_part ) == DVDNAV_STATUS_OK )
966         {
967             if( i_title >= 0 && i_title < p_sys->i_title &&
968                 p_demux->info.i_title != i_title )
969             {
970                 p_demux->info.i_update |= INPUT_UPDATE_TITLE;
971                 p_demux->info.i_title = i_title;
972             }
973         }
974         break;
975     }
976
977     case DVDNAV_CELL_CHANGE:
978     {
979         int32_t i_title = 0;
980         int32_t i_part  = 0;
981
982         dvdnav_cell_change_event_t *event =
983             (dvdnav_cell_change_event_t*)packet;
984         msg_Dbg( p_demux, "DVDNAV_CELL_CHANGE" );
985         msg_Dbg( p_demux, "     - cellN=%d", event->cellN );
986         msg_Dbg( p_demux, "     - pgN=%d", event->pgN );
987         msg_Dbg( p_demux, "     - cell_length=%"PRId64, event->cell_length );
988         msg_Dbg( p_demux, "     - pg_length=%"PRId64, event->pg_length );
989         msg_Dbg( p_demux, "     - pgc_length=%"PRId64, event->pgc_length );
990         msg_Dbg( p_demux, "     - cell_start=%"PRId64, event->cell_start );
991         msg_Dbg( p_demux, "     - pg_start=%"PRId64, event->pg_start );
992
993         /* Store the length in time of the current PGC */
994         p_sys->i_pgc_length = event->pgc_length / 90 * 1000;
995         p_sys->i_vobu_index = 0;
996         p_sys->i_vobu_flush = 0;
997
998         /* FIXME is it correct or there is better way to know chapter change */
999         if( dvdnav_current_title_info( p_sys->dvdnav, &i_title,
1000                                        &i_part ) == DVDNAV_STATUS_OK )
1001         {
1002             if( i_title >= 0 && i_title < p_sys->i_title )
1003             {
1004                 p_demux->info.i_update |= INPUT_UPDATE_TITLE;
1005                 p_demux->info.i_title = i_title;
1006
1007                 if( i_part >= 1 && i_part <= p_sys->title[i_title]->i_seekpoint )
1008                 {
1009                     p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
1010                     p_demux->info.i_seekpoint = i_part - 1;
1011                 }
1012             }
1013         }
1014         break;
1015     }
1016
1017     case DVDNAV_NAV_PACKET:
1018     {
1019         p_sys->i_vobu_index = 1;
1020         p_sys->i_vobu_flush = 0;
1021
1022         /* Look if we have need to force a flush (and when) */
1023         const pci_gi_t *p_pci_gi = &dvdnav_get_current_nav_pci( p_sys->dvdnav )->pci_gi;
1024         if( p_pci_gi->vobu_se_e_ptm != 0 && p_pci_gi->vobu_se_e_ptm < p_pci_gi->vobu_e_ptm )
1025         {
1026             const dsi_gi_t *p_dsi_gi = &dvdnav_get_current_nav_dsi( p_sys->dvdnav )->dsi_gi;
1027             if( p_dsi_gi->vobu_3rdref_ea != 0 )
1028                 p_sys->i_vobu_flush = p_dsi_gi->vobu_3rdref_ea;
1029             else if( p_dsi_gi->vobu_2ndref_ea != 0 )
1030                 p_sys->i_vobu_flush = p_dsi_gi->vobu_2ndref_ea;
1031             else if( p_dsi_gi->vobu_1stref_ea != 0 )
1032                 p_sys->i_vobu_flush = p_dsi_gi->vobu_1stref_ea;
1033         }
1034
1035 #ifdef DVDNAV_DEBUG
1036         msg_Dbg( p_demux, "DVDNAV_NAV_PACKET" );
1037 #endif
1038         /* A lot of thing to do here :
1039          *  - handle packet
1040          *  - fetch pts (for time display)
1041          *  - ...
1042          */
1043         DemuxBlock( p_demux, packet, i_len );
1044         if( p_sys->b_spu_change )
1045         {
1046             ButtonUpdate( p_demux, false );
1047             p_sys->b_spu_change = false;
1048         }
1049         break;
1050     }
1051
1052     case DVDNAV_STOP:   /* EOF */
1053         msg_Dbg( p_demux, "DVDNAV_STOP" );
1054
1055         if( p_sys->b_readahead )
1056             dvdnav_free_cache_block( p_sys->dvdnav, packet );
1057         return 0;
1058
1059     case DVDNAV_HIGHLIGHT:
1060     {
1061         dvdnav_highlight_event_t *event = (dvdnav_highlight_event_t*)packet;
1062         msg_Dbg( p_demux, "DVDNAV_HIGHLIGHT" );
1063         msg_Dbg( p_demux, "     - display=%d", event->display );
1064         msg_Dbg( p_demux, "     - buttonN=%d", event->buttonN );
1065         ButtonUpdate( p_demux, false );
1066         break;
1067     }
1068
1069     case DVDNAV_HOP_CHANNEL:
1070         msg_Dbg( p_demux, "DVDNAV_HOP_CHANNEL" );
1071         p_sys->i_vobu_index = 0;
1072         p_sys->i_vobu_flush = 0;
1073         es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
1074         break;
1075
1076     case DVDNAV_WAIT:
1077         msg_Dbg( p_demux, "DVDNAV_WAIT" );
1078
1079         bool b_empty;
1080         es_out_Control( p_demux->out, ES_OUT_GET_EMPTY, &b_empty );
1081         if( !b_empty )
1082         {
1083             msleep( 40*1000 );
1084         }
1085         else
1086         {
1087             dvdnav_wait_skip( p_sys->dvdnav );
1088             p_sys->b_reset_pcr = true;
1089         }
1090         break;
1091
1092     default:
1093         msg_Warn( p_demux, "Unknown event (0x%x)", i_event );
1094         break;
1095     }
1096
1097     if( p_sys->b_readahead )
1098         dvdnav_free_cache_block( p_sys->dvdnav, packet );
1099
1100     return 1;
1101 }
1102
1103 /* Get a 2 char code
1104  * FIXME: partiallyy duplicated from src/input/es_out.c
1105  */
1106 static char *DemuxGetLanguageCode( demux_t *p_demux, const char *psz_var )
1107 {
1108     const iso639_lang_t *pl;
1109     char *psz_lang;
1110     char *p;
1111
1112     psz_lang = var_CreateGetString( p_demux, psz_var );
1113     if( !psz_lang )
1114         return strdup(LANGUAGE_DEFAULT);
1115
1116     /* XXX: we will use only the first value
1117      * (and ignore other ones in case of a list) */
1118     if( ( p = strchr( psz_lang, ',' ) ) )
1119         *p = '\0';
1120
1121     for( pl = p_languages; pl->psz_eng_name != NULL; pl++ )
1122     {
1123         if( *psz_lang == '\0' )
1124             continue;
1125         if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
1126             !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
1127             !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
1128             !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
1129             break;
1130     }
1131
1132     free( psz_lang );
1133
1134     if( pl->psz_eng_name != NULL )
1135         return strdup( pl->psz_iso639_1 );
1136
1137     return strdup(LANGUAGE_DEFAULT);
1138 }
1139
1140 static void DemuxTitles( demux_t *p_demux )
1141 {
1142     demux_sys_t *p_sys = p_demux->p_sys;
1143     input_title_t *t;
1144     seekpoint_t *s;
1145     int32_t i_titles;
1146
1147     /* Menu */
1148     t = vlc_input_title_New();
1149     t->i_flags = INPUT_TITLE_MENU | INPUT_TITLE_INTERACTIVE;
1150     t->psz_name = strdup( "DVD Menu" );
1151
1152     s = vlc_seekpoint_New();
1153     s->psz_name = strdup( "Resume" );
1154     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
1155
1156     s = vlc_seekpoint_New();
1157     s->psz_name = strdup( "Root" );
1158     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
1159
1160     s = vlc_seekpoint_New();
1161     s->psz_name = strdup( "Title" );
1162     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
1163
1164     s = vlc_seekpoint_New();
1165     s->psz_name = strdup( "Chapter" );
1166     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
1167
1168     s = vlc_seekpoint_New();
1169     s->psz_name = strdup( "Subtitle" );
1170     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
1171
1172     s = vlc_seekpoint_New();
1173     s->psz_name = strdup( "Audio" );
1174     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
1175
1176     s = vlc_seekpoint_New();
1177     s->psz_name = strdup( "Angle" );
1178     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
1179
1180     TAB_APPEND( p_sys->i_title, p_sys->title, t );
1181
1182     /* Find out number of titles/chapters */
1183     dvdnav_get_number_of_titles( p_sys->dvdnav, &i_titles );
1184
1185     if( i_titles > 90 )
1186         msg_Err( p_demux, "This is probably an Arccos Protected DVD. This could take time..." );
1187
1188     for( int i = 1; i <= i_titles; i++ )
1189     {
1190         uint64_t i_title_length;
1191         uint64_t *p_chapters_time;
1192
1193         int32_t i_chapters = dvdnav_describe_title_chapters( p_sys->dvdnav, i,
1194                                                             &p_chapters_time,
1195                                                             &i_title_length );
1196         if( i_chapters < 1 )
1197         {
1198             i_title_length = 0;
1199             p_chapters_time = NULL;
1200         }
1201         t = vlc_input_title_New();
1202         t->i_length = i_title_length * 1000 / 90;
1203         for( int j = 0; j < __MAX( i_chapters, 1 ); j++ )
1204         {
1205             s = vlc_seekpoint_New();
1206             if( p_chapters_time )
1207                 s->i_time_offset = p_chapters_time[j] * 1000 / 90;
1208             TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
1209         }
1210         free( p_chapters_time );
1211         TAB_APPEND( p_sys->i_title, p_sys->title, t );
1212     }
1213 }
1214
1215 /*****************************************************************************
1216  * Update functions:
1217  *****************************************************************************/
1218 static void ButtonUpdate( demux_t *p_demux, bool b_mode )
1219 {
1220     demux_sys_t *p_sys = p_demux->p_sys;
1221     int32_t i_title, i_part;
1222
1223     dvdnav_current_title_info( p_sys->dvdnav, &i_title, &i_part );
1224
1225     dvdnav_highlight_area_t hl;
1226     int32_t i_button;
1227     bool    b_button_ok;
1228
1229     if( dvdnav_get_current_highlight( p_sys->dvdnav, &i_button )
1230         != DVDNAV_STATUS_OK )
1231     {
1232         msg_Err( p_demux, "dvdnav_get_current_highlight failed" );
1233         return;
1234     }
1235
1236     b_button_ok = false;
1237     if( i_button > 0 && i_title ==  0 )
1238     {
1239         pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );
1240
1241         b_button_ok = DVDNAV_STATUS_OK ==
1242                   dvdnav_get_highlight_area( pci, i_button, b_mode, &hl );
1243     }
1244
1245     if( b_button_ok )
1246     {
1247         for( unsigned i = 0; i < 4; i++ )
1248         {
1249             uint32_t i_yuv = p_sys->clut[(hl.palette>>(16+i*4))&0x0f];
1250             uint8_t i_alpha = ( (hl.palette>>(i*4))&0x0f ) * 0xff / 0xf;
1251
1252             p_sys->palette[i][0] = (i_yuv >> 16) & 0xff;
1253             p_sys->palette[i][1] = (i_yuv >> 0) & 0xff;
1254             p_sys->palette[i][2] = (i_yuv >> 8) & 0xff;
1255             p_sys->palette[i][3] = i_alpha;
1256         }
1257
1258         vlc_global_lock( VLC_HIGHLIGHT_MUTEX );
1259         var_SetInteger( p_demux->p_input, "x-start", hl.sx );
1260         var_SetInteger( p_demux->p_input, "x-end",  hl.ex );
1261         var_SetInteger( p_demux->p_input, "y-start", hl.sy );
1262         var_SetInteger( p_demux->p_input, "y-end", hl.ey );
1263
1264         var_SetAddress( p_demux->p_input, "menu-palette", p_sys->palette );
1265         var_SetBool( p_demux->p_input, "highlight", true );
1266
1267         msg_Dbg( p_demux, "buttonUpdate %d", i_button );
1268     }
1269     else
1270     {
1271         msg_Dbg( p_demux, "buttonUpdate not done b=%d t=%d",
1272                  i_button, i_title );
1273
1274         /* Show all */
1275         vlc_global_lock( VLC_HIGHLIGHT_MUTEX );
1276         var_SetBool( p_demux->p_input, "highlight", false );
1277     }
1278     vlc_global_unlock( VLC_HIGHLIGHT_MUTEX );
1279 }
1280
1281 static void ESSubtitleUpdate( demux_t *p_demux )
1282 {
1283     demux_sys_t *p_sys = p_demux->p_sys;
1284     int         i_spu = dvdnav_get_active_spu_stream( p_sys->dvdnav );
1285     int32_t i_title, i_part;
1286
1287     ButtonUpdate( p_demux, false );
1288
1289     dvdnav_current_title_info( p_sys->dvdnav, &i_title, &i_part );
1290     if( i_title > 0 ) return;
1291
1292     /* dvdnav_get_active_spu_stream sets (in)visibility flag as 0xF0 */
1293     if( i_spu >= 0 && i_spu <= 0x1f )
1294     {
1295         ps_track_t *tk = &p_sys->tk[ps_id_to_tk(0xbd20 + i_spu)];
1296
1297         ESNew( p_demux, 0xbd20 + i_spu );
1298
1299         /* be sure to unselect it (reset) */
1300         if( tk->es )
1301         {
1302             es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE, tk->es,
1303                             (bool)false );
1304
1305             /* now select it */
1306             es_out_Control( p_demux->out, ES_OUT_SET_ES, tk->es );
1307         }
1308     }
1309     else
1310     {
1311         for( i_spu = 0; i_spu <= 0x1F; i_spu++ )
1312         {
1313             ps_track_t *tk = &p_sys->tk[ps_id_to_tk(0xbd20 + i_spu)];
1314             if( tk->es )
1315             {
1316                 es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE, tk->es,
1317                                 (bool)false );
1318             }
1319         }
1320     }
1321 }
1322
1323 /*****************************************************************************
1324  * DemuxBlock: demux a given block
1325  *****************************************************************************/
1326 static int DemuxBlock( demux_t *p_demux, const uint8_t *p, int len )
1327 {
1328     demux_sys_t *p_sys = p_demux->p_sys;
1329
1330     while( len > 0 )
1331     {
1332         int i_size = ps_pkt_size( p, len );
1333         if( i_size <= 0 || i_size > len )
1334         {
1335             break;
1336         }
1337
1338         /* Create a block */
1339         block_t *p_pkt = block_Alloc( i_size );
1340         memcpy( p_pkt->p_buffer, p, i_size);
1341
1342         /* Parse it and send it */
1343         switch( 0x100 | p[3] )
1344         {
1345         case 0x1b9:
1346         case 0x1bb:
1347         case 0x1bc:
1348 #ifdef DVDNAV_DEBUG
1349             if( p[3] == 0xbc )
1350             {
1351                 msg_Warn( p_demux, "received a PSM packet" );
1352             }
1353             else if( p[3] == 0xbb )
1354             {
1355                 msg_Warn( p_demux, "received a SYSTEM packet" );
1356             }
1357 #endif
1358             block_Release( p_pkt );
1359             break;
1360
1361         case 0x1ba:
1362         {
1363             int64_t i_scr;
1364             int i_mux_rate;
1365             if( !ps_pkt_parse_pack( p_pkt, &i_scr, &i_mux_rate ) )
1366             {
1367                 es_out_Control( p_demux->out, ES_OUT_SET_PCR, i_scr + 1 );
1368                 if( i_mux_rate > 0 ) p_sys->i_mux_rate = i_mux_rate;
1369             }
1370             block_Release( p_pkt );
1371             break;
1372         }
1373         default:
1374         {
1375             int i_id = ps_pkt_id( p_pkt );
1376             if( i_id >= 0xc0 )
1377             {
1378                 ps_track_t *tk = &p_sys->tk[ps_id_to_tk(i_id)];
1379
1380                 if( !tk->b_configured )
1381                 {
1382                     ESNew( p_demux, i_id );
1383                 }
1384                 if( tk->es &&
1385                     !ps_pkt_parse_pes( VLC_OBJECT(p_demux), p_pkt, tk->i_skip ) )
1386                 {
1387                     es_out_Send( p_demux->out, tk->es, p_pkt );
1388                 }
1389                 else
1390                 {
1391                     block_Release( p_pkt );
1392                 }
1393             }
1394             else
1395             {
1396                 block_Release( p_pkt );
1397             }
1398             break;
1399         }
1400         }
1401
1402         p += i_size;
1403         len -= i_size;
1404     }
1405
1406     return VLC_SUCCESS;
1407 }
1408
1409 /*****************************************************************************
1410  * Force still images to be displayed by sending EOS and stopping buffering.
1411  *****************************************************************************/
1412 static void DemuxForceStill( demux_t *p_demux )
1413 {
1414     static const uint8_t buffer[] = {
1415         0x00, 0x00, 0x01, 0xe0, 0x00, 0x07,
1416         0x80, 0x00, 0x00,
1417         0x00, 0x00, 0x01, 0xB7,
1418     };
1419     DemuxBlock( p_demux, buffer, sizeof(buffer) );
1420
1421     bool b_empty;
1422     es_out_Control( p_demux->out, ES_OUT_GET_EMPTY, &b_empty );
1423 }
1424
1425 /*****************************************************************************
1426  * ESNew: register a new elementary stream
1427  *****************************************************************************/
1428 static void ESNew( demux_t *p_demux, int i_id )
1429 {
1430     demux_sys_t *p_sys = p_demux->p_sys;
1431     ps_track_t  *tk = &p_sys->tk[ps_id_to_tk(i_id)];
1432     bool  b_select = false;
1433
1434     if( tk->b_configured ) return;
1435
1436     if( ps_track_fill( tk, 0, i_id, NULL, true ) )
1437     {
1438         msg_Warn( p_demux, "unknown codec for id=0x%x", i_id );
1439         return;
1440     }
1441
1442     /* Add a new ES */
1443     if( tk->fmt.i_cat == VIDEO_ES )
1444     {
1445         tk->fmt.video.i_sar_num = p_sys->sar.i_num;
1446         tk->fmt.video.i_sar_den = p_sys->sar.i_den;
1447         b_select = true;
1448     }
1449     else if( tk->fmt.i_cat == AUDIO_ES )
1450     {
1451         int i_audio = -1;
1452         /* find the audio number PLEASE find another way */
1453         if( (i_id&0xbdf8) == 0xbd88 )       /* dts */
1454         {
1455             i_audio = i_id&0x07;
1456         }
1457         else if( (i_id&0xbdf0) == 0xbd80 )  /* a52 */
1458         {
1459             i_audio = i_id&0xf;
1460         }
1461         else if( (i_id&0xbdf0) == 0xbda0 )  /* lpcm */
1462         {
1463             i_audio = i_id&0x1f;
1464         }
1465         else if( ( i_id&0xe0 ) == 0xc0 )    /* mpga */
1466         {
1467             i_audio = i_id&0x1f;
1468         }
1469         if( i_audio >= 0 )
1470         {
1471             int i_lang = dvdnav_audio_stream_to_lang( p_sys->dvdnav, i_audio );
1472             if( i_lang != 0xffff )
1473             {
1474                 tk->fmt.psz_language = malloc( 3 );
1475                 tk->fmt.psz_language[0] = (i_lang >> 8)&0xff;
1476                 tk->fmt.psz_language[1] = (i_lang     )&0xff;
1477                 tk->fmt.psz_language[2] = 0;
1478             }
1479             if( dvdnav_get_active_audio_stream( p_sys->dvdnav ) == i_audio )
1480             {
1481                 b_select = true;
1482             }
1483         }
1484     }
1485     else if( tk->fmt.i_cat == SPU_ES )
1486     {
1487         int32_t i_title, i_part;
1488         int i_lang = dvdnav_spu_stream_to_lang( p_sys->dvdnav, i_id&0x1f );
1489         if( i_lang != 0xffff )
1490         {
1491             tk->fmt.psz_language = malloc( 3 );
1492             tk->fmt.psz_language[0] = (i_lang >> 8)&0xff;
1493             tk->fmt.psz_language[1] = (i_lang     )&0xff;
1494             tk->fmt.psz_language[2] = 0;
1495         }
1496
1497         /* Palette */
1498         tk->fmt.subs.spu.palette[0] = SPU_PALETTE_DEFINED;
1499         memcpy( &tk->fmt.subs.spu.palette[1], p_sys->clut,
1500                 16 * sizeof( uint32_t ) );
1501
1502         /* We select only when we are not in the menu */
1503         dvdnav_current_title_info( p_sys->dvdnav, &i_title, &i_part );
1504         if( i_title > 0 &&
1505             dvdnav_get_active_spu_stream( p_sys->dvdnav ) == (i_id&0x1f) )
1506         {
1507             b_select = true;
1508         }
1509     }
1510
1511     tk->fmt.i_id = i_id;
1512     tk->es = es_out_Add( p_demux->out, &tk->fmt );
1513     if( b_select && tk->es )
1514     {
1515         es_out_Control( p_demux->out, ES_OUT_SET_ES, tk->es );
1516     }
1517     tk->b_configured = true;
1518
1519     if( tk->fmt.i_cat == VIDEO_ES ) ButtonUpdate( p_demux, false );
1520 }
1521
1522 /*****************************************************************************
1523  * Still image end
1524  *****************************************************************************/
1525 static void StillTimer( void *p_data )
1526 {
1527     demux_sys_t    *p_sys = p_data;
1528
1529     vlc_mutex_lock( &p_sys->still.lock );
1530     if( likely(p_sys->still.b_enabled) )
1531     {
1532         p_sys->still.b_enabled = false;
1533         dvdnav_still_skip( p_sys->dvdnav );
1534     }
1535     vlc_mutex_unlock( &p_sys->still.lock );
1536 }
1537
1538 static int EventMouse( vlc_object_t *p_vout, char const *psz_var,
1539                        vlc_value_t oldval, vlc_value_t val, void *p_data )
1540 {
1541     demux_t *p_demux = p_data;
1542     demux_sys_t *p_sys = p_demux->p_sys;
1543
1544     /* FIXME? PCI usage thread safe? */
1545     pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );
1546     int x = val.coords.x;
1547     int y = val.coords.y;
1548
1549     if( psz_var[6] == 'm' ) /* mouse-moved */
1550         dvdnav_mouse_select( p_sys->dvdnav, pci, x, y );
1551     else
1552     {
1553         assert( psz_var[6] == 'c' ); /* mouse-clicked */
1554
1555         ButtonUpdate( p_demux, true );
1556         dvdnav_mouse_activate( p_sys->dvdnav, pci, x, y );
1557     }
1558     (void)p_vout;
1559     (void)oldval;
1560     return VLC_SUCCESS;
1561 }
1562
1563 static int EventIntf( vlc_object_t *p_input, char const *psz_var,
1564                       vlc_value_t oldval, vlc_value_t val, void *p_data )
1565 {
1566     demux_t *p_demux = p_data;
1567     demux_sys_t *p_sys = p_demux->p_sys;
1568
1569     if (val.i_int == INPUT_EVENT_VOUT)
1570     {
1571         if( p_sys->p_vout != NULL )
1572         {
1573             var_DelCallback( p_sys->p_vout, "mouse-moved", EventMouse, p_demux );
1574             var_DelCallback( p_sys->p_vout, "mouse-clicked", EventMouse, p_demux );
1575             vlc_object_release( p_sys->p_vout );
1576         }
1577
1578         p_sys->p_vout = input_GetVout( (input_thread_t *)p_input );
1579         if( p_sys->p_vout != NULL )
1580         {
1581             var_AddCallback( p_sys->p_vout, "mouse-moved", EventMouse, p_demux );
1582             var_AddCallback( p_sys->p_vout, "mouse-clicked", EventMouse, p_demux );
1583         }
1584     }
1585     (void) psz_var; (void) oldval;
1586     return VLC_SUCCESS;
1587 }
1588
1589 /*****************************************************************************
1590  * ProbeDVD: very weak probing that avoids going too often into a dvdnav_open()
1591  *****************************************************************************/
1592 static int ProbeDVD( const char *psz_name )
1593 {
1594     if( !*psz_name )
1595         /* Triggers libdvdcss autodetection */
1596         return VLC_SUCCESS;
1597
1598     int fd = vlc_open( psz_name, O_RDONLY | O_NONBLOCK );
1599     if( fd == -1 )
1600 #ifdef HAVE_FDOPENDIR
1601         return VLC_EGENERIC;
1602 #else
1603         return (errno == ENOENT) ? VLC_EGENERIC : VLC_SUCCESS;
1604 #endif
1605
1606     int ret = VLC_EGENERIC;
1607     struct stat stat_info;
1608
1609     if( fstat( fd, &stat_info ) == -1 )
1610          goto bailout;
1611     if( !S_ISREG( stat_info.st_mode ) )
1612     {
1613         if( S_ISDIR( stat_info.st_mode ) || S_ISBLK( stat_info.st_mode ) )
1614             ret = VLC_SUCCESS; /* Let dvdnav_open() do the probing */
1615         goto bailout;
1616     }
1617
1618     /* ISO 9660 volume descriptor */
1619     char iso_dsc[6];
1620     if( lseek( fd, 0x8000 + 1, SEEK_SET ) == -1
1621      || read( fd, iso_dsc, sizeof (iso_dsc) ) < (int)sizeof (iso_dsc)
1622      || memcmp( iso_dsc, "CD001\x01", 6 ) )
1623         goto bailout;
1624
1625     /* Try to find the anchor (2 bytes at LBA 256) */
1626     uint16_t anchor;
1627
1628     if( lseek( fd, 256 * DVD_VIDEO_LB_LEN, SEEK_SET ) != -1
1629      && read( fd, &anchor, 2 ) == 2
1630      && GetWLE( &anchor ) == 2 )
1631         ret = VLC_SUCCESS; /* Found a potential anchor */
1632 bailout:
1633     vlc_close( fd );
1634     return ret;
1635 }