Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

dvdnav.c

00001 /*****************************************************************************
00002  * dvdnav.c: DVD module using the dvdnav library.
00003  *****************************************************************************
00004  * Copyright (C) 2004 the VideoLAN team
00005  * $Id: dvdnav.c 12835 2005-10-15 12:15:06Z jpsaman $
00006  *
00007  * Authors: Laurent Aimar <[email protected]>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 /*****************************************************************************
00025  * Preamble
00026  *****************************************************************************/
00027 #include <stdlib.h>
00028 
00029 #include <vlc/vlc.h>
00030 #include <vlc/input.h>
00031 
00032 #ifdef HAVE_UNISTD_H
00033 #   include <unistd.h>
00034 #endif
00035 #ifdef HAVE_SYS_TYPES_H
00036 #   include <sys/types.h>
00037 #endif
00038 #ifdef HAVE_SYS_STAT_H
00039 #   include <sys/stat.h>
00040 #endif
00041 #ifdef HAVE_FCNTL_H
00042 #   include <fcntl.h>
00043 #endif
00044 
00045 #include "vlc_keys.h"
00046 #include "iso_lang.h"
00047 
00048 /* FIXME we should find a better way than including that */
00049 #include "../../src/misc/iso-639_def.h"
00050 
00051 
00052 #include <dvdnav/dvdnav.h>
00053 
00054 #include "../demux/ps.h"
00055 
00056 /*****************************************************************************
00057  * Module descriptor
00058  *****************************************************************************/
00059 #define ANGLE_TEXT N_("DVD angle")
00060 #define ANGLE_LONGTEXT N_( \
00061     "Allows you to select the default DVD angle." )
00062 
00063 #define CACHING_TEXT N_("Caching value in ms")
00064 #define CACHING_LONGTEXT N_( \
00065     "Allows you to modify the default caching value for DVDnav streams. This "\
00066     "value should be set in millisecond units." )
00067 #define MENU_TEXT N_("Start directly in menu")
00068 #define MENU_LONGTEXT N_( \
00069     "Allows you to start the DVD directly in the main menu. This "\
00070     "will try to skip all the useless warnings introductions." )
00071 
00072 #define LANGUAGE_DEFAULT ("en")
00073 
00074 static int  Open ( vlc_object_t * );
00075 static void Close( vlc_object_t * );
00076 
00077 vlc_module_begin();
00078     set_shortname( _("DVD with menus") );
00079     set_description( _("DVDnav Input") );
00080     set_category( CAT_INPUT );
00081     set_subcategory( SUBCAT_INPUT_ACCESS );
00082     add_integer( "dvdnav-angle", 1, NULL, ANGLE_TEXT,
00083         ANGLE_LONGTEXT, VLC_FALSE );
00084     add_integer( "dvdnav-caching", DEFAULT_PTS_DELAY / 1000, NULL,
00085         CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
00086     add_bool( "dvdnav-menu", VLC_TRUE, NULL,
00087         MENU_TEXT, MENU_LONGTEXT, VLC_FALSE );
00088     set_capability( "access_demux", 5 );
00089     add_shortcut( "dvd" );
00090     add_shortcut( "dvdnav" );
00091     set_callbacks( Open, Close );
00092 vlc_module_end();
00093 
00094 /* Shall we use libdvdnav's read ahead cache? */
00095 #define DVD_READ_CACHE 1
00096 
00097 /*****************************************************************************
00098  * Local prototypes
00099  *****************************************************************************/
00100 typedef struct
00101 {
00102     VLC_COMMON_MEMBERS
00103 
00104     demux_t        *p_demux;
00105     vlc_mutex_t     lock;
00106 
00107     vlc_bool_t      b_moved;
00108     vlc_bool_t      b_clicked;
00109     vlc_bool_t      b_key;
00110 
00111     vlc_bool_t      b_still;
00112     int64_t         i_still_end;
00113 
00114 } event_thread_t;
00115 
00116 static int EventThread( vlc_object_t * );
00117 
00118 struct demux_sys_t
00119 {
00120     dvdnav_t    *dvdnav;
00121 
00122     /* track */
00123     ps_track_t  tk[PS_TK_COUNT];
00124     int         i_mux_rate;
00125 
00126     /* for spu variables */
00127     input_thread_t *p_input;
00128 
00129     /* event */
00130     event_thread_t *p_ev;
00131 
00132     /* palette for menus */
00133     uint32_t clut[16];
00134     uint8_t  palette[4][4];
00135     vlc_bool_t b_spu_change;
00136 
00137     /* */
00138     int i_aspect;
00139 
00140     int           i_title;
00141     input_title_t **title;
00142 
00143     /* lenght of program group chain */
00144     mtime_t     i_pgc_length;
00145 };
00146 
00147 static int Control( demux_t *, int, va_list );
00148 static int Demux( demux_t * );
00149 static int DemuxBlock( demux_t *, uint8_t *, int );
00150 
00151 static void DemuxTitles( demux_t * );
00152 static void ESSubtitleUpdate( demux_t * );
00153 static void ButtonUpdate( demux_t *, vlc_bool_t );
00154 
00155 static void ESNew( demux_t *, int );
00156 static int ProbeDVD( demux_t *, char * );
00157 
00158 static char *DemuxGetLanguageCode( demux_t *p_demux, char *psz_var );
00159 
00160 /*****************************************************************************
00161  * DemuxOpen:
00162  *****************************************************************************/
00163 static int Open( vlc_object_t *p_this )
00164 {
00165     demux_t     *p_demux = (demux_t*)p_this;
00166     demux_sys_t *p_sys;
00167     dvdnav_t    *p_dvdnav;
00168     int         i_angle;
00169     char        *psz_name;
00170     char        *psz_code;
00171     vlc_value_t val;
00172 
00173     if( !p_demux->psz_path || !*p_demux->psz_path )
00174     {
00175         /* Only when selected */
00176         if( !p_this->b_force ) return VLC_EGENERIC;
00177 
00178         psz_name = var_CreateGetString( p_this, "dvd" );
00179         if( !psz_name )
00180         {
00181             psz_name = strdup("");
00182         }
00183     }
00184     else
00185         psz_name = strdup( p_demux->psz_path );
00186 
00187 #ifdef WIN32
00188     if( psz_name[0] && psz_name[1] == ':' &&
00189         psz_name[2] == '\\' && psz_name[3] == '\0' ) psz_name[2] = '\0';
00190 #endif
00191 
00192     /* Try some simple probing to avoid going through dvdnav_open too often */
00193     if( ProbeDVD( p_demux, psz_name ) != VLC_SUCCESS )
00194     {
00195         free( psz_name );
00196         return VLC_EGENERIC;
00197     }
00198 
00199     /* Open dvdnav */
00200     if( dvdnav_open( &p_dvdnav, psz_name ) != DVDNAV_STATUS_OK )
00201     {
00202         msg_Warn( p_demux, "cannot open dvdnav" );
00203         free( psz_name );
00204         return VLC_EGENERIC;
00205     }
00206     free( psz_name );
00207 
00208     /* Fill p_demux field */
00209     p_demux->pf_demux = Demux;
00210     p_demux->pf_control = Control;
00211     p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
00212     memset( p_sys, 0, sizeof( demux_sys_t ) );
00213     p_sys->dvdnav = p_dvdnav;
00214 
00215     ps_track_init( p_sys->tk );
00216     p_sys->i_aspect = -1;
00217     p_sys->i_mux_rate = 0;
00218     p_sys->i_pgc_length = 0;
00219     p_sys->b_spu_change = VLC_FALSE;
00220 
00221     if( 1 )
00222     {
00223         // Hack for libdvdnav CVS.
00224         // Without it dvdnav_get_number_of_titles() fails.
00225         // Remove when fixed in libdvdnav CVS.
00226         uint8_t buffer[DVD_VIDEO_LB_LEN];
00227         int i_event, i_len;
00228 
00229         if( dvdnav_get_next_block( p_sys->dvdnav, buffer, &i_event, &i_len )
00230               == DVDNAV_STATUS_ERR )
00231         {
00232             msg_Warn( p_demux, "dvdnav_get_next_block failed" );
00233         }
00234 
00235         dvdnav_sector_search( p_sys->dvdnav, 0, SEEK_SET );
00236     }
00237 
00238     /* Configure dvdnav */
00239     if( dvdnav_set_readahead_flag( p_sys->dvdnav, DVD_READ_CACHE ) !=
00240           DVDNAV_STATUS_OK )
00241     {
00242         msg_Warn( p_demux, "cannot set read-a-head flag" );
00243     }
00244 
00245     if( dvdnav_set_PGC_positioning_flag( p_sys->dvdnav, 1 ) !=
00246           DVDNAV_STATUS_OK )
00247     {
00248         msg_Warn( p_demux, "cannot set PGC positioning flag" );
00249     }
00250 
00251     /* Set menu language ("en")
00252      * XXX: maybe it would be better to set it like audio/spu
00253      * or to create a --menu-language option */
00254     if( dvdnav_menu_language_select( p_sys->dvdnav,LANGUAGE_DEFAULT ) !=
00255         DVDNAV_STATUS_OK )
00256     {
00257         msg_Warn( p_demux, "can't set menu language to '%s' (%s)",
00258                   LANGUAGE_DEFAULT, dvdnav_err_to_string( p_sys->dvdnav ) );
00259     }
00260 
00261     /* Set audio language */
00262     psz_code = DemuxGetLanguageCode( p_demux, "audio-language" );
00263     if( dvdnav_audio_language_select( p_sys->dvdnav, psz_code ) !=
00264         DVDNAV_STATUS_OK )
00265     {
00266         msg_Warn( p_demux, "can't set audio language to '%s' (%s)",
00267                   psz_code, dvdnav_err_to_string( p_sys->dvdnav ) );
00268         /* We try to fall back to 'en' */
00269         if( strcmp( psz_code, LANGUAGE_DEFAULT ) )
00270             dvdnav_audio_language_select( p_sys->dvdnav, LANGUAGE_DEFAULT );
00271     }
00272     free( psz_code );
00273 
00274     /* Set spu language */
00275     psz_code = DemuxGetLanguageCode( p_demux, "sub-language" );
00276     if( dvdnav_spu_language_select( p_sys->dvdnav, psz_code ) !=
00277         DVDNAV_STATUS_OK )
00278     {
00279         msg_Warn( p_demux, "can't set spu language to '%s' (%s)",
00280                   psz_code, dvdnav_err_to_string( p_sys->dvdnav ) );
00281         /* We try to fall back to 'en' */
00282         if( strcmp( psz_code, LANGUAGE_DEFAULT ) )
00283             dvdnav_spu_language_select(p_sys->dvdnav, LANGUAGE_DEFAULT );
00284     }
00285     free( psz_code );
00286 
00287     DemuxTitles( p_demux );
00288 
00289     var_Create( p_demux, "dvdnav-menu", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
00290     var_Get( p_demux, "dvdnav-menu", &val );
00291     if( val.b_bool )
00292     {
00293         msg_Dbg( p_demux, "trying to go to dvd menu" );
00294 
00295         if( dvdnav_title_play( p_sys->dvdnav, 1 ) != DVDNAV_STATUS_OK )
00296         {
00297             msg_Err( p_demux, "cannot set title (can't decrypt DVD?)" );
00298             dvdnav_close( p_sys->dvdnav );
00299             free( p_sys );
00300             return VLC_EGENERIC;
00301         }
00302 
00303         if( dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Title ) !=
00304             DVDNAV_STATUS_OK )
00305         {
00306             /* Try going to menu root */
00307             if( dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Root ) !=
00308                 DVDNAV_STATUS_OK )
00309                     msg_Warn( p_demux, "cannot go to dvd menu" );
00310         }
00311     }
00312 
00313     var_Create( p_demux, "dvdnav-angle", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
00314     var_Get( p_demux, "dvdnav-angle", &val );
00315     i_angle = val.i_int > 0 ? val.i_int : 1;
00316 
00317     /* Update default_pts to a suitable value for dvdnav access */
00318     var_Create( p_demux, "dvdnav-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
00319 
00320     /* FIXME hack hack hack hack FIXME */
00321     /* Get p_input and create variable */
00322     p_sys->p_input = vlc_object_find( p_demux, VLC_OBJECT_INPUT, FIND_PARENT );
00323     var_Create( p_sys->p_input, "x-start", VLC_VAR_INTEGER );
00324     var_Create( p_sys->p_input, "y-start", VLC_VAR_INTEGER );
00325     var_Create( p_sys->p_input, "x-end", VLC_VAR_INTEGER );
00326     var_Create( p_sys->p_input, "y-end", VLC_VAR_INTEGER );
00327     var_Create( p_sys->p_input, "color", VLC_VAR_ADDRESS );
00328     var_Create( p_sys->p_input, "menu-palette", VLC_VAR_ADDRESS );
00329     var_Create( p_sys->p_input, "highlight", VLC_VAR_BOOL );
00330     var_Create( p_sys->p_input, "highlight-mutex", VLC_VAR_MUTEX );
00331 
00332     /* Now create our event thread catcher */
00333     p_sys->p_ev = vlc_object_create( p_demux, sizeof( event_thread_t ) );
00334     p_sys->p_ev->p_demux = p_demux;
00335     vlc_thread_create( p_sys->p_ev, "dvdnav event thread handler", EventThread,
00336                        VLC_THREAD_PRIORITY_LOW, VLC_FALSE );
00337 
00338     return VLC_SUCCESS;
00339 }
00340 
00341 /*****************************************************************************
00342  * Close:
00343  *****************************************************************************/
00344 static void Close( vlc_object_t *p_this )
00345 {
00346     demux_t     *p_demux = (demux_t*)p_this;
00347     demux_sys_t *p_sys = p_demux->p_sys;
00348     int i;
00349 
00350     /* stop the event handler */
00351     p_sys->p_ev->b_die = VLC_TRUE;
00352     vlc_thread_join( p_sys->p_ev );
00353     vlc_object_destroy( p_sys->p_ev );
00354 
00355     var_Destroy( p_sys->p_input, "highlight-mutex" );
00356     var_Destroy( p_sys->p_input, "highlight" );
00357     var_Destroy( p_sys->p_input, "x-start" );
00358     var_Destroy( p_sys->p_input, "x-end" );
00359     var_Destroy( p_sys->p_input, "y-start" );
00360     var_Destroy( p_sys->p_input, "y-end" );
00361     var_Destroy( p_sys->p_input, "color" );
00362     var_Destroy( p_sys->p_input, "menu-palette" );
00363 
00364     vlc_object_release( p_sys->p_input );
00365 
00366     for( i = 0; i < PS_TK_COUNT; i++ )
00367     {
00368         ps_track_t *tk = &p_sys->tk[i];
00369         if( tk->b_seen )
00370         {
00371             es_format_Clean( &tk->fmt );
00372             if( tk->es ) es_out_Del( p_demux->out, tk->es );
00373         }
00374     }
00375 
00376     dvdnav_close( p_sys->dvdnav );
00377     free( p_sys );
00378 }
00379 
00380 /*****************************************************************************
00381  * Control:
00382  *****************************************************************************/
00383 static int Control( demux_t *p_demux, int i_query, va_list args )
00384 {
00385     demux_sys_t *p_sys = p_demux->p_sys;
00386     double f, *pf;
00387     vlc_bool_t *pb;
00388     int64_t *pi64;
00389     input_title_t ***ppp_title;
00390     int          *pi_int;
00391     int i;
00392 
00393     switch( i_query )
00394     {
00395         case DEMUX_SET_POSITION:
00396         case DEMUX_GET_POSITION:
00397         case DEMUX_GET_TIME:
00398         case DEMUX_GET_LENGTH:
00399         {
00400             uint32_t pos, len;
00401             if( dvdnav_get_position( p_sys->dvdnav, &pos, &len ) !=
00402                   DVDNAV_STATUS_OK || len == 0 )
00403             {
00404                 return VLC_EGENERIC;
00405             }
00406 
00407             if( i_query == DEMUX_GET_POSITION )
00408             {
00409                 pf = (double*)va_arg( args, double* );
00410                 *pf = (double)pos / (double)len;
00411                 return VLC_SUCCESS;
00412             }
00413             else if( i_query == DEMUX_SET_POSITION )
00414             {
00415                 f = (double)va_arg( args, double );
00416                 pos = f * len;
00417                 if( dvdnav_sector_search( p_sys->dvdnav, pos, SEEK_SET ) ==
00418                       DVDNAV_STATUS_OK )
00419                 {
00420                     return VLC_SUCCESS;
00421                 }
00422             }
00423             else if( i_query == DEMUX_GET_TIME )
00424             {
00425                 pi64 = (int64_t*)va_arg( args, int64_t * );
00426                 if( p_sys->i_pgc_length > 0 )
00427                 {
00428                     *pi64 = p_sys->i_pgc_length * pos / len;
00429                     return VLC_SUCCESS;
00430                 }
00431             }
00432             else if( i_query == DEMUX_GET_LENGTH )
00433             {
00434                 pi64 = (int64_t*)va_arg( args, int64_t * );
00435                 if( p_sys->i_pgc_length > 0 )
00436                 {
00437                     *pi64 = (int64_t)p_sys->i_pgc_length;
00438                     return VLC_SUCCESS;
00439                 }
00440             }
00441 
00442             return VLC_EGENERIC;
00443         }
00444 
00445         /* Special for access_demux */
00446         case DEMUX_CAN_PAUSE:
00447         case DEMUX_CAN_CONTROL_PACE:
00448             /* TODO */
00449             pb = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
00450             *pb = VLC_TRUE;
00451             return VLC_SUCCESS;
00452 
00453         case DEMUX_SET_PAUSE_STATE:
00454             return VLC_SUCCESS;
00455 
00456         case DEMUX_GET_TITLE_INFO:
00457             ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
00458             pi_int    = (int*)va_arg( args, int* );
00459             *((int*)va_arg( args, int* )) = 0; /* Title offset */
00460             *((int*)va_arg( args, int* )) = 1; /* Chapter offset */
00461 
00462             /* Duplicate title infos */
00463             *pi_int = p_sys->i_title;
00464             *ppp_title = malloc( sizeof( input_title_t ** ) * p_sys->i_title );
00465             for( i = 0; i < p_sys->i_title; i++ )
00466             {
00467                 (*ppp_title)[i] = vlc_input_title_Duplicate( p_sys->title[i] );
00468             }
00469             return VLC_SUCCESS;
00470 
00471         case DEMUX_SET_TITLE:
00472             i = (int)va_arg( args, int );
00473             if( ( i == 0 && dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Root )
00474                   != DVDNAV_STATUS_OK ) ||
00475                 ( i != 0 && dvdnav_title_play( p_sys->dvdnav, i )
00476                   != DVDNAV_STATUS_OK ) )
00477             {
00478                 msg_Warn( p_demux, "cannot set title/chapter" );
00479                 return VLC_EGENERIC;
00480             }
00481             p_demux->info.i_update |=
00482                 INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
00483             p_demux->info.i_title = i;
00484             p_demux->info.i_seekpoint = 0;
00485             return VLC_SUCCESS;
00486 
00487         case DEMUX_SET_SEEKPOINT:
00488             i = (int)va_arg( args, int );
00489             if( p_demux->info.i_title == 0 )
00490             {
00491                 int i_ret;
00492                 /* Special case */
00493                 switch( i )
00494                 {
00495                 case 0:
00496                     i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Escape );
00497                     break;
00498                 case 1:
00499                     i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Root );
00500                     break;
00501                 case 2:
00502                     i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Title );
00503                     break;
00504                 case 3:
00505                     i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Part );
00506                     break;
00507                 case 4:
00508                     i_ret = dvdnav_menu_call( p_sys->dvdnav,
00509                                               DVD_MENU_Subpicture );
00510                     break;
00511                 case 5:
00512                     i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Audio );
00513                     break;
00514                 case 6:
00515                     i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Angle );
00516                     break;
00517                 default:
00518                     return VLC_EGENERIC;
00519                 }
00520 
00521                 if( i_ret != DVDNAV_STATUS_OK )
00522                     return VLC_EGENERIC;
00523             }
00524             else if( dvdnav_part_play( p_sys->dvdnav, p_demux->info.i_title,
00525                                        i + 1 ) != DVDNAV_STATUS_OK )
00526             {
00527                 msg_Warn( p_demux, "cannot set title/chapter" );
00528                 return VLC_EGENERIC;
00529             }
00530             p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
00531             p_demux->info.i_seekpoint = i;
00532             return VLC_SUCCESS;
00533 
00534         case DEMUX_GET_PTS_DELAY:
00535             pi64 = (int64_t*)va_arg( args, int64_t * );
00536             *pi64 = (int64_t)var_GetInteger( p_demux, "dvdnav-caching" ) *1000;
00537             return VLC_SUCCESS;
00538 
00539         /* TODO implement others */
00540         default:
00541             return VLC_EGENERIC;
00542     }
00543 }
00544 
00545 /*****************************************************************************
00546  * Demux:
00547  *****************************************************************************/
00548 static int Demux( demux_t *p_demux )
00549 {
00550     demux_sys_t *p_sys = p_demux->p_sys;
00551 
00552     uint8_t buffer[DVD_VIDEO_LB_LEN];
00553     uint8_t *packet = buffer;
00554     int i_event;
00555     int i_len;
00556 
00557 #if DVD_READ_CACHE
00558     if( dvdnav_get_next_cache_block( p_sys->dvdnav, &packet, &i_event, &i_len )
00559         == DVDNAV_STATUS_ERR )
00560 #else
00561     if( dvdnav_get_next_block( p_sys->dvdnav, packet, &i_event, &i_len )
00562         == DVDNAV_STATUS_ERR )
00563 #endif
00564     {
00565         msg_Warn( p_demux, "cannot get next block (%s)",
00566                   dvdnav_err_to_string( p_sys->dvdnav ) );
00567         return -1;
00568     }
00569 
00570     switch( i_event )
00571     {
00572     case DVDNAV_BLOCK_OK:   /* mpeg block */
00573         DemuxBlock( p_demux, packet, i_len );
00574         break;
00575 
00576     case DVDNAV_NOP:    /* Nothing */
00577         msg_Dbg( p_demux, "DVDNAV_NOP" );
00578         break;
00579 
00580     case DVDNAV_STILL_FRAME:
00581     {
00582         dvdnav_still_event_t *event = (dvdnav_still_event_t*)packet;
00583         vlc_mutex_lock( &p_sys->p_ev->lock );
00584         if( !p_sys->p_ev->b_still )
00585         {
00586             msg_Dbg( p_demux, "DVDNAV_STILL_FRAME" );
00587             msg_Dbg( p_demux, "     - length=0x%x", event->length );
00588             p_sys->p_ev->b_still = VLC_TRUE;
00589             if( event->length == 0xff )
00590             {
00591                 p_sys->p_ev->i_still_end = 0;
00592             }
00593             else
00594             {
00595                 p_sys->p_ev->i_still_end = (int64_t)event->length *
00596                     1000000 + mdate() + p_sys->p_input->i_pts_delay;
00597             }
00598         }
00599         vlc_mutex_unlock( &p_sys->p_ev->lock );
00600         msleep( 40000 );
00601         break;
00602     }
00603 
00604     case DVDNAV_SPU_CLUT_CHANGE:
00605     {
00606         int i;
00607 
00608         msg_Dbg( p_demux, "DVDNAV_SPU_CLUT_CHANGE" );
00609         /* Update color lookup table (16 *uint32_t in packet) */
00610         memcpy( p_sys->clut, packet, 16 * sizeof( uint32_t ) );
00611 
00612         /* HACK to get the SPU tracks registered in the right order */
00613         for( i = 0; i < 0x1f; i++ )
00614         {
00615             if( dvdnav_spu_stream_to_lang( p_sys->dvdnav, i ) != 0xffff )
00616                 ESNew( p_demux, 0xbd20 + i );
00617         }
00618         /* END HACK */
00619         break;
00620     }
00621 
00622     case DVDNAV_SPU_STREAM_CHANGE:
00623     {
00624         dvdnav_spu_stream_change_event_t *event =
00625             (dvdnav_spu_stream_change_event_t*)packet;
00626         int i;
00627 
00628         msg_Dbg( p_demux, "DVDNAV_SPU_STREAM_CHANGE" );
00629         msg_Dbg( p_demux, "     - physical_wide=%d",
00630                  event->physical_wide );
00631         msg_Dbg( p_demux, "     - physical_letterbox=%d",
00632                  event->physical_letterbox);
00633         msg_Dbg( p_demux, "     - physical_pan_scan=%d",
00634                  event->physical_pan_scan );
00635 
00636         ESSubtitleUpdate( p_demux );
00637         p_sys->b_spu_change = VLC_TRUE;
00638 
00639         /* HACK to get the SPU tracks registered in the right order */
00640         for( i = 0; i < 0x1f; i++ )
00641         {
00642             if( dvdnav_spu_stream_to_lang( p_sys->dvdnav, i ) != 0xffff )
00643                 ESNew( p_demux, 0xbd20 + i );
00644         }
00645         /* END HACK */
00646         break;
00647     }
00648 
00649     case DVDNAV_AUDIO_STREAM_CHANGE:
00650     {
00651         dvdnav_audio_stream_change_event_t *event =
00652             (dvdnav_audio_stream_change_event_t*)packet;
00653         msg_Dbg( p_demux, "DVDNAV_AUDIO_STREAM_CHANGE" );
00654         msg_Dbg( p_demux, "     - physical=%d", event->physical );
00655         /* TODO */
00656         break;
00657     }
00658 
00659     case DVDNAV_VTS_CHANGE:
00660     {
00661         int32_t i_title = 0;
00662         int32_t i_part  = 0;
00663         int i;
00664 
00665         dvdnav_vts_change_event_t *event = (dvdnav_vts_change_event_t*)packet;
00666         msg_Dbg( p_demux, "DVDNAV_VTS_CHANGE" );
00667         msg_Dbg( p_demux, "     - vtsN=%d", event->new_vtsN );
00668         msg_Dbg( p_demux, "     - domain=%d", event->new_domain );
00669 
00670         /* dvdnav_get_video_aspect / dvdnav_get_video_scale_permission */
00671         /* TODO check if we always have VTS and CELL */
00672         p_sys->i_aspect = dvdnav_get_video_aspect( p_sys->dvdnav );
00673 
00674         /* reset PCR */
00675         es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
00676 
00677         for( i = 0; i < PS_TK_COUNT; i++ )
00678         {
00679             ps_track_t *tk = &p_sys->tk[i];
00680             if( tk->b_seen )
00681             {
00682                 es_format_Clean( &tk->fmt );
00683                 if( tk->es ) es_out_Del( p_demux->out, tk->es );
00684             }
00685             tk->b_seen = VLC_FALSE;
00686         }
00687 
00688         if( dvdnav_current_title_info( p_sys->dvdnav, &i_title,
00689                                        &i_part ) == DVDNAV_STATUS_OK )
00690         {
00691             if( i_title >= 0 && i_title < p_sys->i_title &&
00692                 p_demux->info.i_title != i_title )
00693             {
00694                 p_demux->info.i_update |= INPUT_UPDATE_TITLE;
00695                 p_demux->info.i_title = i_title;
00696             }
00697         }
00698         break;
00699     }
00700 
00701     case DVDNAV_CELL_CHANGE:
00702     {
00703         int32_t i_title = 0;
00704         int32_t i_part  = 0;
00705 
00706         dvdnav_cell_change_event_t *event =
00707             (dvdnav_cell_change_event_t*)packet;
00708         msg_Dbg( p_demux, "DVDNAV_CELL_CHANGE" );
00709         msg_Dbg( p_demux, "     - cellN=%d", event->cellN );
00710         msg_Dbg( p_demux, "     - pgN=%d", event->pgN );
00711         msg_Dbg( p_demux, "     - cell_length=%lld", event->cell_length );
00712         msg_Dbg( p_demux, "     - pg_length=%lld", event->pg_length );
00713         msg_Dbg( p_demux, "     - pgc_length=%lld", event->pgc_length );
00714         msg_Dbg( p_demux, "     - cell_start=%lld", event->cell_start );
00715         msg_Dbg( p_demux, "     - pg_start=%lld", event->pg_start );
00716 
00717         /* Store the lenght in time of the current PGC */
00718         p_sys->i_pgc_length = event->pgc_length / 90 * 1000;
00719 
00720         /* FIXME is it correct or there is better way to know chapter change */
00721         if( dvdnav_current_title_info( p_sys->dvdnav, &i_title,
00722                                        &i_part ) == DVDNAV_STATUS_OK )
00723         {
00724             if( i_title >= 0 && i_title < p_sys->i_title &&
00725                 i_part >= 1 && i_part <= p_sys->title[i_title]->i_seekpoint &&
00726                 p_demux->info.i_seekpoint != i_part - 1 )
00727             {
00728                 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
00729                 p_demux->info.i_seekpoint = i_part - 1;
00730             }
00731         }
00732         break;
00733     }
00734 
00735     case DVDNAV_NAV_PACKET:
00736     {
00737 #ifdef DVDNAV_DEBUG
00738         msg_Dbg( p_demux, "DVDNAV_NAV_PACKET" );
00739 #endif
00740         /* A lot of thing to do here :
00741          *  - handle packet
00742          *  - fetch pts (for time display)
00743          *  - ...
00744          */
00745         DemuxBlock( p_demux, packet, i_len );
00746         if( p_sys->b_spu_change ) 
00747         {
00748             ButtonUpdate( p_demux, VLC_FALSE );
00749             p_sys->b_spu_change = VLC_FALSE;
00750         }
00751         break;
00752     }
00753 
00754     case DVDNAV_STOP:   /* EOF */
00755         msg_Dbg( p_demux, "DVDNAV_STOP" );
00756 
00757 #if DVD_READ_CACHE
00758         dvdnav_free_cache_block( p_sys->dvdnav, packet );
00759 #endif
00760         return 0;
00761 
00762     case DVDNAV_HIGHLIGHT:
00763     {
00764         dvdnav_highlight_event_t *event = (dvdnav_highlight_event_t*)packet;
00765         msg_Dbg( p_demux, "DVDNAV_HIGHLIGHT" );
00766         msg_Dbg( p_demux, "     - display=%d", event->display );
00767         msg_Dbg( p_demux, "     - buttonN=%d", event->buttonN );
00768         ButtonUpdate( p_demux, VLC_FALSE );
00769         break;
00770     }
00771 
00772     case DVDNAV_HOP_CHANNEL:
00773         msg_Dbg( p_demux, "DVDNAV_HOP_CHANNEL" );
00774         /* We should try to flush all our internal buffer */
00775         break;
00776 
00777     case DVDNAV_WAIT:
00778         msg_Dbg( p_demux, "DVDNAV_WAIT" );
00779 
00780         /* reset PCR */
00781         es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
00782         dvdnav_wait_skip( p_sys->dvdnav );
00783         break;
00784 
00785     default:
00786         msg_Warn( p_demux, "Unknown event (0x%x)", i_event );
00787         break;
00788     }
00789 
00790 #if DVD_READ_CACHE
00791     dvdnav_free_cache_block( p_sys->dvdnav, packet );
00792 #endif
00793 
00794     return 1;
00795 }
00796 
00797 /* Get a 2 char code
00798  * FIXME: partiallyy duplicated from src/input/es_out.c
00799  */
00800 static char *DemuxGetLanguageCode( demux_t *p_demux, char *psz_var )
00801 {
00802     const iso639_lang_t *pl;
00803     char *psz_lang;
00804     char *p;
00805 
00806     psz_lang = var_CreateGetString( p_demux, psz_var );
00807     /* XXX: we will use only the first value
00808      * (and ignore other ones in case of a list) */
00809     if( ( p = strchr( psz_lang, ',' ) ) ) *p = '\0';
00810 
00811     for( pl = p_languages; pl->psz_iso639_1 != NULL; pl++ )
00812     {
00813         if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
00814             !strcasecmp( pl->psz_native_name, psz_lang ) ||
00815             !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
00816             !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
00817             !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
00818             break;
00819     }
00820 
00821     free( psz_lang );
00822 
00823     if( pl->psz_iso639_1 != NULL )
00824         return strdup( pl->psz_iso639_1 );
00825 
00826     return strdup(LANGUAGE_DEFAULT);
00827 }
00828 
00829 static void DemuxTitles( demux_t *p_demux )
00830 {
00831     demux_sys_t *p_sys = p_demux->p_sys;
00832     input_title_t *t;
00833     seekpoint_t *s;
00834     int32_t i_titles;
00835     int i;
00836 
00837     /* Menu */
00838     t = vlc_input_title_New();
00839     t->b_menu = VLC_TRUE;
00840     t->psz_name = strdup( "DVD Menu" );
00841 
00842     s = vlc_seekpoint_New();
00843     s->psz_name = strdup( "Resume" );
00844     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
00845 
00846     s = vlc_seekpoint_New();
00847     s->psz_name = strdup( "Root" );
00848     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
00849 
00850     s = vlc_seekpoint_New();
00851     s->psz_name = strdup( "Title" );
00852     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
00853 
00854     s = vlc_seekpoint_New();
00855     s->psz_name = strdup( "Chapter" );
00856     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
00857 
00858     s = vlc_seekpoint_New();
00859     s->psz_name = strdup( "Subtitle" );
00860     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
00861 
00862     s = vlc_seekpoint_New();
00863     s->psz_name = strdup( "Audio" );
00864     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
00865 
00866     s = vlc_seekpoint_New();
00867     s->psz_name = strdup( "Angle" );
00868     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
00869 
00870     TAB_APPEND( p_sys->i_title, p_sys->title, t );
00871 
00872     /* Find out number of titles/chapters */
00873     dvdnav_get_number_of_titles( p_sys->dvdnav, &i_titles );
00874     for( i = 1; i <= i_titles; i++ )
00875     {
00876         int32_t i_chapters = 0;
00877         int j;
00878 
00879         dvdnav_get_number_of_parts( p_sys->dvdnav, i, &i_chapters );
00880 
00881         t = vlc_input_title_New();
00882         for( j = 0; j < __MAX( i_chapters, 1 ); j++ )
00883         {
00884             s = vlc_seekpoint_New();
00885             TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
00886         }
00887 
00888         TAB_APPEND( p_sys->i_title, p_sys->title, t );
00889     }
00890 }
00891 
00892 /*****************************************************************************
00893  * Update functions:
00894  *****************************************************************************/
00895 static void ButtonUpdate( demux_t *p_demux, vlc_bool_t b_mode )
00896 {
00897     demux_sys_t *p_sys = p_demux->p_sys;
00898     vlc_value_t val;
00899     int32_t i_title, i_part;
00900 
00901     dvdnav_current_title_info( p_sys->dvdnav, &i_title, &i_part );
00902 
00903     if( var_Get( p_sys->p_input, "highlight-mutex", &val ) == VLC_SUCCESS )
00904     {
00905         vlc_mutex_t *p_mutex = val.p_address;
00906         dvdnav_highlight_area_t hl;
00907         int32_t i_button;
00908 
00909         if( dvdnav_get_current_highlight( p_sys->dvdnav, &i_button )
00910             != DVDNAV_STATUS_OK )
00911         {
00912             msg_Err( p_demux, "dvdnav_get_current_highlight failed" );
00913             return;
00914         }
00915 
00916         if( i_button > 0 && i_title ==  0 )
00917         {
00918             int i;
00919             pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );
00920 
00921             dvdnav_get_highlight_area( pci, i_button, b_mode, &hl );
00922 
00923             for( i = 0; i < 4; i++ )
00924             {
00925                 uint32_t i_yuv = p_sys->clut[(hl.palette>>(16+i*4))&0x0f];
00926                 uint8_t i_alpha = (hl.palette>>(i*4))&0x0f;
00927                 i_alpha = i_alpha == 0xf ? 0xff : i_alpha << 4;
00928 
00929                 p_sys->palette[i][0] = (i_yuv >> 16) & 0xff;
00930                 p_sys->palette[i][1] = (i_yuv >> 0) & 0xff;
00931                 p_sys->palette[i][2] = (i_yuv >> 8) & 0xff;
00932                 p_sys->palette[i][3] = i_alpha;
00933             }
00934 
00935             vlc_mutex_lock( p_mutex );
00936             val.i_int = hl.sx; var_Set( p_sys->p_input, "x-start", val );
00937             val.i_int = hl.ex; var_Set( p_sys->p_input, "x-end", val );
00938             val.i_int = hl.sy; var_Set( p_sys->p_input, "y-start", val );
00939             val.i_int = hl.ey; var_Set( p_sys->p_input, "y-end", val );
00940 
00941             val.p_address = (void *)p_sys->palette;
00942             var_Set( p_sys->p_input, "menu-palette", val );
00943 
00944             val.b_bool = VLC_TRUE; var_Set( p_sys->p_input, "highlight", val );
00945             vlc_mutex_unlock( p_mutex );
00946 
00947             msg_Dbg( p_demux, "buttonUpdate %d", i_button );
00948         }
00949         else
00950         {
00951             msg_Dbg( p_demux, "buttonUpdate not done b=%d t=%d",
00952                      i_button, i_title );
00953 
00954             /* Show all */
00955             vlc_mutex_lock( p_mutex );
00956             val.b_bool = VLC_FALSE;
00957             var_Set( p_sys->p_input, "highlight", val );
00958             vlc_mutex_unlock( p_mutex );
00959         }
00960     }
00961 }
00962 
00963 static void ESSubtitleUpdate( demux_t *p_demux )
00964 {
00965     demux_sys_t *p_sys = p_demux->p_sys;
00966     int         i_spu = dvdnav_get_active_spu_stream( p_sys->dvdnav );
00967     int32_t i_title, i_part;
00968 
00969     ButtonUpdate( p_demux, VLC_FALSE );
00970 
00971     dvdnav_current_title_info( p_sys->dvdnav, &i_title, &i_part );
00972     if( i_title > 0 ) return;
00973 
00974     if( i_spu >= 0 && i_spu <= 0x1f )
00975     {
00976         ps_track_t *tk = &p_sys->tk[PS_ID_TO_TK(0xbd20 + i_spu)];
00977 
00978         ESNew( p_demux, 0xbd20 + i_spu );
00979 
00980         /* be sure to unselect it (reset) */
00981         es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE, tk->es,
00982                         (vlc_bool_t)VLC_FALSE );
00983 
00984         /* now select it */
00985         es_out_Control( p_demux->out, ES_OUT_SET_ES, tk->es );
00986     }
00987     else
00988     {
00989         for( i_spu = 0; i_spu <= 0x1F; i_spu++ )
00990         {
00991             ps_track_t *tk = &p_sys->tk[PS_ID_TO_TK(0xbd20 + i_spu)];
00992             if( tk->b_seen )
00993             {
00994                 es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE, tk->es,
00995                                 (vlc_bool_t)VLC_FALSE );
00996             }
00997         }
00998     }
00999 }
01000 
01001 /*****************************************************************************
01002  * DemuxBlock: demux a given block
01003  *****************************************************************************/
01004 static int DemuxBlock( demux_t *p_demux, uint8_t *pkt, int i_pkt )
01005 {
01006     demux_sys_t *p_sys = p_demux->p_sys;
01007     uint8_t     *p = pkt;
01008 
01009     while( p < &pkt[i_pkt] )
01010     {
01011         int i_size = ps_pkt_size( p, &pkt[i_pkt] - p );
01012         block_t *p_pkt;
01013         if( i_size <= 0 )
01014         {
01015             break;
01016         }
01017 
01018         /* Create a block */
01019         p_pkt = block_New( p_demux, i_size );
01020         memcpy( p_pkt->p_buffer, p, i_size);
01021 
01022         /* Parse it and send it */
01023         switch( 0x100 | p[3] )
01024         {
01025         case 0x1b9:
01026         case 0x1bb:
01027         case 0x1bc:
01028 #ifdef DVDNAV_DEBUG
01029             if( p[3] == 0xbc )
01030             {
01031                 msg_Warn( p_demux, "received a PSM packet" );
01032             }
01033             else if( p[3] == 0xbb )
01034             {
01035                 msg_Warn( p_demux, "received a SYSTEM packet" );
01036             }
01037 #endif
01038             block_Release( p_pkt );
01039             break;
01040 
01041         case 0x1ba:
01042         {
01043             int64_t i_scr;
01044             int i_mux_rate;
01045             if( !ps_pkt_parse_pack( p_pkt, &i_scr, &i_mux_rate ) )
01046             {
01047                 es_out_Control( p_demux->out, ES_OUT_SET_PCR, i_scr );
01048                 if( i_mux_rate > 0 ) p_sys->i_mux_rate = i_mux_rate;
01049             }
01050             block_Release( p_pkt );
01051             break;
01052         }
01053         default:
01054         {
01055             int i_id = ps_pkt_id( p_pkt );
01056             if( i_id >= 0xc0 )
01057             {
01058                 ps_track_t *tk = &p_sys->tk[PS_ID_TO_TK(i_id)];
01059 
01060                 if( !tk->b_seen )
01061                 {
01062                     ESNew( p_demux, i_id );
01063                 }
01064                 if( tk->b_seen && tk->es &&
01065                     !ps_pkt_parse_pes( p_pkt, tk->i_skip ) )
01066                 {
01067                     es_out_Send( p_demux->out, tk->es, p_pkt );
01068                 }
01069                 else
01070                 {
01071                     block_Release( p_pkt );
01072                 }
01073             }
01074             else
01075             {
01076                 block_Release( p_pkt );
01077             }
01078             break;
01079         }
01080         }
01081 
01082         p += i_size;
01083     }
01084 
01085     return VLC_SUCCESS;
01086 }
01087 
01088 /*****************************************************************************
01089  * ESNew: register a new elementary stream
01090  *****************************************************************************/
01091 static void ESNew( demux_t *p_demux, int i_id )
01092 {
01093     demux_sys_t *p_sys = p_demux->p_sys;
01094     ps_track_t  *tk = &p_sys->tk[PS_ID_TO_TK(i_id)];
01095     vlc_bool_t  b_select = VLC_FALSE;
01096 
01097     if( tk->b_seen ) return;
01098 
01099     if( ps_track_fill( tk, 0, i_id ) )
01100     {
01101         msg_Warn( p_demux, "unknown codec for id=0x%x", i_id );
01102         return;
01103     }
01104 
01105     /* Add a new ES */
01106     if( tk->fmt.i_cat == VIDEO_ES )
01107     {
01108         if( p_sys->i_aspect >= 0 )
01109         {
01110             tk->fmt.video.i_aspect = p_sys->i_aspect;
01111         }
01112         b_select = VLC_TRUE;
01113     }
01114     else if( tk->fmt.i_cat == AUDIO_ES )
01115     {
01116         int i_audio = -1;
01117         /* find the audio number PLEASE find another way */
01118         if( (i_id&0xbdf8) == 0xbd88 )       /* dts */
01119         {
01120             i_audio = i_id&0x07;
01121         }
01122         else if( (i_id&0xbdf0) == 0xbd80 )  /* a52 */
01123         {
01124             i_audio = i_id&0xf;
01125         }
01126         else if( (i_id&0xbdf0) == 0xbda0 )  /* lpcm */
01127         {
01128             i_audio = i_id&0x1f;
01129         }
01130         else if( ( i_id&0xe0 ) == 0xc0 )    /* mpga */
01131         {
01132             i_audio = i_id&0x1f;
01133         }
01134         if( i_audio >= 0 )
01135         {
01136             int i_lang = dvdnav_audio_stream_to_lang( p_sys->dvdnav, i_audio );
01137             if( i_lang != 0xffff )
01138             {
01139                 tk->fmt.psz_language = malloc( 3 );
01140                 tk->fmt.psz_language[0] = (i_lang >> 8)&0xff;
01141                 tk->fmt.psz_language[1] = (i_lang     )&0xff;
01142                 tk->fmt.psz_language[2] = 0;
01143             }
01144             if( dvdnav_get_active_audio_stream( p_sys->dvdnav ) == i_audio )
01145             {
01146                 b_select = VLC_TRUE;
01147             }
01148         }
01149     }
01150     else if( tk->fmt.i_cat == SPU_ES )
01151     {
01152         int32_t i_title, i_part;
01153         int i_lang = dvdnav_spu_stream_to_lang( p_sys->dvdnav, i_id&0x1f );
01154         if( i_lang != 0xffff )
01155         {
01156             tk->fmt.psz_language = malloc( 3 );
01157             tk->fmt.psz_language[0] = (i_lang >> 8)&0xff;
01158             tk->fmt.psz_language[1] = (i_lang     )&0xff;
01159             tk->fmt.psz_language[2] = 0;
01160         }
01161 
01162         /* Palette */
01163         tk->fmt.subs.spu.palette[0] = 0xBeef;
01164         memcpy( &tk->fmt.subs.spu.palette[1], p_sys->clut,
01165                 16 * sizeof( uint32_t ) );
01166 
01167         /* We select only when we are not in the menu */
01168         dvdnav_current_title_info( p_sys->dvdnav, &i_title, &i_part );
01169         if( i_title > 0 &&
01170             dvdnav_get_active_spu_stream( p_sys->dvdnav ) == (i_id&0x1f) )
01171         {
01172             b_select = VLC_TRUE;
01173         }
01174     }
01175 
01176     tk->es = es_out_Add( p_demux->out, &tk->fmt );
01177     if( b_select )
01178     {
01179         es_out_Control( p_demux->out, ES_OUT_SET_ES, tk->es );
01180     }
01181     tk->b_seen = VLC_TRUE;
01182 
01183     if( tk->fmt.i_cat == VIDEO_ES ) ButtonUpdate( p_demux, VLC_FALSE );
01184 }
01185 
01186 /*****************************************************************************
01187  * Event handler code
01188  *****************************************************************************/
01189 static int  EventMouse( vlc_object_t *, char const *,
01190                         vlc_value_t, vlc_value_t, void * );
01191 static int  EventKey  ( vlc_object_t *, char const *,
01192                         vlc_value_t, vlc_value_t, void * );
01193 
01194 static int EventThread( vlc_object_t *p_this )
01195 {
01196     event_thread_t *p_ev = (event_thread_t*)p_this;
01197     demux_sys_t    *p_sys = p_ev->p_demux->p_sys;
01198     vlc_object_t   *p_vout = NULL;
01199 
01200     vlc_mutex_init( p_ev, &p_ev->lock );
01201     p_ev->b_moved   = VLC_FALSE;
01202     p_ev->b_clicked = VLC_FALSE;
01203     p_ev->b_key     = VLC_FALSE;
01204     p_ev->b_still   = VLC_FALSE;
01205 
01206     /* catch all key event */
01207     var_AddCallback( p_ev->p_vlc, "key-pressed", EventKey, p_ev );
01208 
01209     /* main loop */
01210     while( !p_ev->b_die )
01211     {
01212         vlc_bool_t b_activated = VLC_FALSE;
01213 
01214         /* KEY part */
01215         if( p_ev->b_key )
01216         {
01217             pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );
01218 
01219             vlc_value_t valk;
01220             struct hotkey *p_hotkeys = p_ev->p_vlc->p_hotkeys;
01221             int i, i_action = -1;
01222 
01223             vlc_mutex_lock( &p_ev->lock );
01224             var_Get( p_ev->p_vlc, "key-pressed", &valk );
01225             for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
01226             {
01227                 if( p_hotkeys[i].i_key == valk.i_int )
01228                 {
01229                     i_action = p_hotkeys[i].i_action;
01230                 }
01231             }
01232 
01233             switch( i_action )
01234             {
01235             case ACTIONID_NAV_LEFT:
01236                 dvdnav_left_button_select( p_sys->dvdnav, pci );
01237                 break;
01238             case ACTIONID_NAV_RIGHT:
01239                 dvdnav_right_button_select( p_sys->dvdnav, pci );
01240                 break;
01241             case ACTIONID_NAV_UP:
01242                 dvdnav_upper_button_select( p_sys->dvdnav, pci );
01243                 break;
01244             case ACTIONID_NAV_DOWN:
01245                 dvdnav_lower_button_select( p_sys->dvdnav, pci );
01246                 break;
01247             case ACTIONID_NAV_ACTIVATE:
01248                 b_activated = VLC_TRUE;
01249                 dvdnav_button_activate( p_sys->dvdnav, pci );
01250                 ButtonUpdate( p_ev->p_demux, VLC_TRUE );
01251                 break;
01252             default:
01253                 break;
01254             }
01255             p_ev->b_key = VLC_FALSE;
01256             vlc_mutex_unlock( &p_ev->lock );
01257         }
01258 
01259         /* VOUT part */
01260         if( p_vout && ( p_ev->b_moved || p_ev->b_clicked ) )
01261         {
01262             pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );
01263             vlc_value_t valx, valy;
01264 
01265             vlc_mutex_lock( &p_ev->lock );
01266             var_Get( p_vout, "mouse-x", &valx );
01267             var_Get( p_vout, "mouse-y", &valy );
01268 
01269             if( p_ev->b_moved )
01270             {
01271                 dvdnav_mouse_select( p_sys->dvdnav, pci, valx.i_int,
01272                                      valy.i_int );
01273             }
01274             if( p_ev->b_clicked )
01275             {
01276                 b_activated = VLC_TRUE;
01277                 dvdnav_mouse_activate( p_sys->dvdnav, pci, valx.i_int,
01278                                        valy.i_int );
01279                 ButtonUpdate( p_ev->p_demux, VLC_TRUE );
01280             }
01281 
01282             p_ev->b_moved = VLC_FALSE;
01283             p_ev->b_clicked = VLC_FALSE;
01284             vlc_mutex_unlock( &p_ev->lock );
01285         }
01286         if( p_vout && p_vout->b_die )
01287         {
01288             var_DelCallback( p_vout, "mouse-moved", EventMouse, p_ev );
01289             var_DelCallback( p_vout, "mouse-clicked", EventMouse, p_ev );
01290             vlc_object_release( p_vout );
01291             p_vout = NULL;
01292         }
01293         if( p_vout == NULL )
01294         {
01295             p_vout = vlc_object_find( p_sys->p_input, VLC_OBJECT_VOUT,
01296                                       FIND_CHILD );
01297             if( p_vout)
01298             {
01299                 var_AddCallback( p_vout, "mouse-moved", EventMouse, p_ev );
01300                 var_AddCallback( p_vout, "mouse-clicked", EventMouse, p_ev );
01301             }
01302         }
01303 
01304         /* Still part */
01305         vlc_mutex_lock( &p_ev->lock );
01306         if( p_ev->b_still )
01307         {
01308             if( /* b_activated || // This breaks menus */
01309                 ( p_ev->i_still_end > 0 && p_ev->i_still_end < mdate() ))
01310             {
01311                 p_ev->b_still = VLC_FALSE;
01312                 dvdnav_still_skip( p_sys->dvdnav );
01313             }
01314         }
01315         vlc_mutex_unlock( &p_ev->lock );
01316 
01317         /* Wait a bit */
01318         msleep( 10000 );
01319     }
01320 
01321     /* Release callback */
01322     if( p_vout )
01323     {
01324         var_DelCallback( p_vout, "mouse-moved", EventMouse, p_ev );
01325         var_DelCallback( p_vout, "mouse-clicked", EventMouse, p_ev );
01326         vlc_object_release( p_vout );
01327     }
01328     var_DelCallback( p_ev->p_vlc, "key-pressed", EventKey, p_ev );
01329 
01330     vlc_mutex_destroy( &p_ev->lock );
01331 
01332     return VLC_SUCCESS;
01333 }
01334 
01335 static int EventMouse( vlc_object_t *p_this, char const *psz_var,
01336                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
01337 {
01338     event_thread_t *p_ev = p_data;
01339     vlc_mutex_lock( &p_ev->lock );
01340     if( psz_var[6] == 'c' )
01341         p_ev->b_clicked = VLC_TRUE;
01342     else if( psz_var[6] == 'm' )
01343         p_ev->b_moved = VLC_TRUE;
01344     vlc_mutex_unlock( &p_ev->lock );
01345 
01346     return VLC_SUCCESS;
01347 }
01348 
01349 static int EventKey( vlc_object_t *p_this, char const *psz_var,
01350                      vlc_value_t oldval, vlc_value_t newval, void *p_data )
01351 {
01352     event_thread_t *p_ev = p_data;
01353     vlc_mutex_lock( &p_ev->lock );
01354     p_ev->b_key = VLC_TRUE;
01355     vlc_mutex_unlock( &p_ev->lock );
01356 
01357     return VLC_SUCCESS;
01358 }
01359 
01360 /*****************************************************************************
01361  * ProbeDVD: very weak probing that avoids going too often into a dvdnav_open()
01362  *****************************************************************************/
01363 static int ProbeDVD( demux_t *p_demux, char *psz_name )
01364 {
01365 #ifdef HAVE_SYS_STAT_H
01366     struct stat stat_info;
01367     uint8_t pi_anchor[2];
01368     uint16_t i_tag_id = 0;
01369     int i_fd, i_ret;
01370 
01371     if( !*psz_name )
01372     {
01373         /* Triggers libdvdcss autodetection */
01374         return VLC_SUCCESS;
01375     }
01376 
01377     if( stat( psz_name, &stat_info ) || !S_ISREG( stat_info.st_mode ) )
01378     {
01379         /* Let dvdnav_open() do the probing */
01380         return VLC_SUCCESS;
01381     }
01382 
01383     if( (i_fd = open( psz_name, O_RDONLY )) == -1 )
01384     {
01385         /* Let dvdnav_open() do the probing */
01386         return VLC_SUCCESS;
01387     }
01388 
01389     /* Try to find the anchor (2 bytes at LBA 256) */
01390     i_ret = VLC_SUCCESS;
01391     if( lseek( i_fd, 256 * DVD_VIDEO_LB_LEN, SEEK_SET ) == -1 )
01392     {
01393         i_ret = VLC_EGENERIC;
01394     }
01395 
01396     if( read( i_fd, pi_anchor, 2 ) == 2 )
01397     {
01398         i_tag_id = GetWLE(pi_anchor);
01399         if( i_tag_id != 2 ) i_ret = VLC_EGENERIC; /* Not an anchor */
01400     }
01401     else
01402     {
01403         i_ret = VLC_EGENERIC;
01404     }
01405 
01406     close( i_fd );
01407 
01408     return i_ret;
01409 #else
01410 
01411     return VLC_SUCCESS;
01412 #endif
01413 }

Generated on Tue Dec 20 10:14:24 2005 for vlc-0.8.4a by  doxygen 1.4.2