dvdnav.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:39k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * dvdnav.c: DVD module using the dvdnav library.
  3.  *****************************************************************************
  4.  * Copyright (C) 2004 VideoLAN
  5.  * $Id: dvdnav.c 8768 2004-09-22 13:43:03Z gbazin $
  6.  *
  7.  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #include <stdlib.h>
  27. #include <vlc/vlc.h>
  28. #include <vlc/input.h>
  29. #ifdef HAVE_UNISTD_H
  30. #   include <unistd.h>
  31. #endif
  32. #ifdef HAVE_SYS_TYPES_H
  33. #   include <sys/types.h>
  34. #endif
  35. #ifdef HAVE_SYS_STAT_H
  36. #   include <sys/stat.h>
  37. #endif
  38. #ifdef HAVE_FCNTL_H
  39. #   include <fcntl.h>
  40. #endif
  41. #include "vlc_keys.h"
  42. #include "iso_lang.h"
  43. #include <dvdnav/dvdnav.h>
  44. #include "../demux/ps.h"
  45. /*****************************************************************************
  46.  * Module descriptor
  47.  *****************************************************************************/
  48. #define ANGLE_TEXT N_("DVD angle")
  49. #define ANGLE_LONGTEXT N_( 
  50.     "Allows you to select the default DVD angle." )
  51. #define CACHING_TEXT N_("Caching value in ms")
  52. #define CACHING_LONGTEXT N_( 
  53.     "Allows you to modify the default caching value for DVDnav streams. This "
  54.     "value should be set in millisecond units." )
  55. #define MENU_TEXT N_("Start directly in menu")
  56. #define MENU_LONGTEXT N_( 
  57.     "Allows you to start the DVD directly in the main menu. This "
  58.     "will try to skip all the useless warnings introductions." )
  59. static int  Open ( vlc_object_t * );
  60. static void Close( vlc_object_t * );
  61. vlc_module_begin();
  62.     set_description( _("DVDnav Input") );
  63.     add_integer( "dvdnav-angle", 1, NULL, ANGLE_TEXT,
  64.         ANGLE_LONGTEXT, VLC_FALSE );
  65.     add_integer( "dvdnav-caching", DEFAULT_PTS_DELAY / 1000, NULL,
  66.         CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
  67.     add_bool( "dvdnav-menu", VLC_TRUE, NULL,
  68.         MENU_TEXT, MENU_LONGTEXT, VLC_FALSE );
  69.     set_capability( "access_demux", 5 );
  70.     add_shortcut( "dvd" );
  71.     add_shortcut( "dvdnav" );
  72.     set_callbacks( Open, Close );
  73. vlc_module_end();
  74. /* Shall we use libdvdnav's read ahead cache? */
  75. #define DVD_READ_CACHE 1
  76. /*****************************************************************************
  77.  * Local prototypes
  78.  *****************************************************************************/
  79. typedef struct
  80. {
  81.     VLC_COMMON_MEMBERS
  82.     demux_t        *p_demux;
  83.     vlc_mutex_t     lock;
  84.     vlc_bool_t      b_moved;
  85.     vlc_bool_t      b_clicked;
  86.     vlc_bool_t      b_key;
  87.     vlc_bool_t      b_still;
  88.     int64_t         i_still_end;
  89. } event_thread_t;
  90. static int EventThread( vlc_object_t * );
  91. struct demux_sys_t
  92. {
  93.     dvdnav_t    *dvdnav;
  94.     /* track */
  95.     ps_track_t  tk[PS_TK_COUNT];
  96.     int         i_mux_rate;
  97.     /* for spu variables */
  98.     input_thread_t *p_input;
  99.     /* event */
  100.     event_thread_t *p_ev;
  101.     /* FIXME */
  102.     uint8_t     alpha[4];
  103.     uint32_t    clut[16];
  104.     /* */
  105.     int i_aspect;
  106.     int           i_title;
  107.     input_title_t **title;
  108. };
  109. static int Control( demux_t *, int, va_list );
  110. static int Demux( demux_t * );
  111. static int DemuxBlock( demux_t *, uint8_t *, int );
  112. static void DemuxTitles( demux_t * );
  113. static void ESSubtitleUpdate( demux_t * );
  114. static void ButtonUpdate( demux_t * );
  115. static void ESNew( demux_t *, int );
  116. static int ProbeDVD( demux_t *, char * );
  117. /*****************************************************************************
  118.  * DemuxOpen:
  119.  *****************************************************************************/
  120. static int Open( vlc_object_t *p_this )
  121. {
  122.     demux_t     *p_demux = (demux_t*)p_this;
  123.     demux_sys_t *p_sys;
  124.     dvdnav_t    *p_dvdnav;
  125.     int         i_angle;
  126.     char        *psz_name;
  127.     vlc_value_t val;
  128.     if( !p_demux->psz_path || !*p_demux->psz_path )
  129.     {
  130.         /* Only when selected */
  131.         if( !p_this->b_force ) return VLC_EGENERIC;
  132.         psz_name = var_CreateGetString( p_this, "dvd" );
  133.         if( !psz_name || !*psz_name )
  134.         {
  135.             if( psz_name ) free( psz_name );
  136.             return VLC_EGENERIC;
  137.         }
  138.     }
  139.     else psz_name = strdup( p_demux->psz_path );
  140. #ifdef WIN32
  141.     if( psz_name[0] && psz_name[1] == ':' &&
  142.         psz_name[2] == '\' && psz_name[3] == '' ) psz_name[2] = '';
  143. #endif
  144.     /* Try some simple probing to avoid going through dvdnav_open too often */
  145.     if( ProbeDVD( p_demux, psz_name ) != VLC_SUCCESS )
  146.     {
  147.         free( psz_name );
  148.         return VLC_EGENERIC;
  149.     }
  150.     /* Open dvdnav */
  151.     if( dvdnav_open( &p_dvdnav, psz_name ) != DVDNAV_STATUS_OK )
  152.     {
  153.         msg_Warn( p_demux, "cannot open dvdnav" );
  154.         free( psz_name );
  155.         return VLC_EGENERIC;
  156.     }
  157.     free( psz_name );
  158.     /* Fill p_demux field */
  159.     p_demux->pf_demux = Demux;
  160.     p_demux->pf_control = Control;
  161.     p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
  162.     memset( p_sys, 0, sizeof( demux_sys_t ) );
  163.     p_sys->dvdnav = p_dvdnav;
  164.     ps_track_init( p_sys->tk );
  165.     p_sys->i_aspect = -1;
  166.     p_sys->i_mux_rate = 0;
  167.     if( 1 )
  168.     {
  169.         // Hack for libdvdnav CVS.
  170.         // Without it dvdnav_get_number_of_titles() fails.
  171.         // Remove when fixed in libdvdnav CVS.
  172.         uint8_t buffer[DVD_VIDEO_LB_LEN];
  173.         int i_event, i_len;
  174.         if( dvdnav_get_next_block( p_sys->dvdnav, buffer, &i_event, &i_len )
  175.               == DVDNAV_STATUS_ERR )
  176.         {
  177.             msg_Warn( p_demux, "dvdnav_get_next_block failed" );
  178.         }
  179.         dvdnav_sector_search( p_sys->dvdnav, 0, SEEK_SET );
  180.     }
  181.     /* Configure dvdnav */
  182.     if( dvdnav_set_readahead_flag( p_sys->dvdnav, DVD_READ_CACHE ) !=
  183.           DVDNAV_STATUS_OK )
  184.     {
  185.         msg_Warn( p_demux, "cannot set read-a-head flag" );
  186.     }
  187.     if( dvdnav_set_PGC_positioning_flag( p_sys->dvdnav, 1 ) !=
  188.           DVDNAV_STATUS_OK )
  189.     {
  190.         msg_Warn( p_demux, "cannot set PGC positioning flag" );
  191.     }
  192.     if( dvdnav_menu_language_select (p_sys->dvdnav,"en") != DVDNAV_STATUS_OK ||
  193.         dvdnav_audio_language_select(p_sys->dvdnav,"en") != DVDNAV_STATUS_OK ||
  194.         dvdnav_spu_language_select  (p_sys->dvdnav,"en") != DVDNAV_STATUS_OK )
  195.     {
  196.         msg_Warn( p_demux, "something failed while setting en language (%s)",
  197.                   dvdnav_err_to_string( p_sys->dvdnav ) );
  198.     }
  199.     DemuxTitles( p_demux );
  200.     var_Create( p_demux, "dvdnav-menu", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
  201.     var_Get( p_demux, "dvdnav-menu", &val );
  202.     if( val.b_bool )
  203.     {
  204.         msg_Dbg( p_demux, "trying to go to dvd menu" );
  205.         if( dvdnav_title_play( p_sys->dvdnav, 1 ) != DVDNAV_STATUS_OK )
  206.         {
  207.             msg_Warn( p_demux, "cannot set title" );
  208.         }
  209.         if( dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Title ) !=
  210.             DVDNAV_STATUS_OK )
  211.         {
  212.             msg_Warn( p_demux, "cannot go to dvd menu" );
  213.         }
  214.     }
  215.     var_Create( p_demux, "dvdnav-angle", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
  216.     var_Get( p_demux, "dvdnav-angle", &val );
  217.     i_angle = val.i_int > 0 ? val.i_int : 1;
  218.     /* Update default_pts to a suitable value for dvdnav access */
  219.     var_Create( p_demux, "dvdnav-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
  220.     /* FIXME hack hack hack hack FIXME */
  221.     /* Get p_input and create variable */
  222.     p_sys->p_input = vlc_object_find( p_demux, VLC_OBJECT_INPUT, FIND_PARENT );
  223.     var_Create( p_sys->p_input, "x-start", VLC_VAR_INTEGER );
  224.     var_Create( p_sys->p_input, "y-start", VLC_VAR_INTEGER );
  225.     var_Create( p_sys->p_input, "x-end", VLC_VAR_INTEGER );
  226.     var_Create( p_sys->p_input, "y-end", VLC_VAR_INTEGER );
  227.     var_Create( p_sys->p_input, "color", VLC_VAR_ADDRESS );
  228.     var_Create( p_sys->p_input, "contrast", VLC_VAR_ADDRESS );
  229.     var_Create( p_sys->p_input, "highlight", VLC_VAR_BOOL );
  230.     var_Create( p_sys->p_input, "highlight-mutex", VLC_VAR_MUTEX );
  231.     /* Now create our event thread catcher */
  232.     p_sys->p_ev = vlc_object_create( p_demux, sizeof( event_thread_t ) );
  233.     p_sys->p_ev->p_demux = p_demux;
  234.     vlc_thread_create( p_sys->p_ev, "dvdnav event thread handler", EventThread,
  235.                        VLC_THREAD_PRIORITY_LOW, VLC_FALSE );
  236.     return VLC_SUCCESS;
  237. }
  238. /*****************************************************************************
  239.  * Close:
  240.  *****************************************************************************/
  241. static void Close( vlc_object_t *p_this )
  242. {
  243.     demux_t     *p_demux = (demux_t*)p_this;
  244.     demux_sys_t *p_sys = p_demux->p_sys;
  245.     int i;
  246.     /* stop the event handler */
  247.     p_sys->p_ev->b_die = VLC_TRUE;
  248.     vlc_thread_join( p_sys->p_ev );
  249.     vlc_object_destroy( p_sys->p_ev );
  250.     var_Destroy( p_sys->p_input, "highlight-mutex" );
  251.     var_Destroy( p_sys->p_input, "highlight" );
  252.     var_Destroy( p_sys->p_input, "x-start" );
  253.     var_Destroy( p_sys->p_input, "x-end" );
  254.     var_Destroy( p_sys->p_input, "y-start" );
  255.     var_Destroy( p_sys->p_input, "y-end" );
  256.     var_Destroy( p_sys->p_input, "color" );
  257.     var_Destroy( p_sys->p_input, "contrast" );
  258.     vlc_object_release( p_sys->p_input );
  259.     for( i = 0; i < PS_TK_COUNT; i++ )
  260.     {
  261.         ps_track_t *tk = &p_sys->tk[i];
  262.         if( tk->b_seen )
  263.         {
  264.             es_format_Clean( &tk->fmt );
  265.             if( tk->es ) es_out_Del( p_demux->out, tk->es );
  266.         }
  267.     }
  268.     dvdnav_close( p_sys->dvdnav );
  269.     free( p_sys );
  270. }
  271. /*****************************************************************************
  272.  * Control:
  273.  *****************************************************************************/
  274. static int Control( demux_t *p_demux, int i_query, va_list args )
  275. {
  276.     demux_sys_t *p_sys = p_demux->p_sys;
  277.     double f, *pf;
  278.     vlc_bool_t *pb;
  279.     int64_t *pi64;
  280.     input_title_t ***ppp_title;
  281.     int          *pi_int;
  282.     int i;
  283.     switch( i_query )
  284.     {
  285.         case DEMUX_SET_POSITION:
  286.         case DEMUX_GET_POSITION:
  287.         case DEMUX_GET_TIME:
  288.         case DEMUX_GET_LENGTH:
  289.         {
  290.             uint32_t pos, len;
  291.             if( dvdnav_get_position( p_sys->dvdnav, &pos, &len ) !=
  292.                   DVDNAV_STATUS_OK || len == 0 )
  293.             {
  294.                 return VLC_EGENERIC;
  295.             }
  296.             if( i_query == DEMUX_GET_POSITION )
  297.             {
  298.                 pf = (double*)va_arg( args, double* );
  299.                 *pf = (double)pos / (double)len;
  300.                 return VLC_SUCCESS;
  301.             }
  302.             else if( i_query == DEMUX_SET_POSITION )
  303.             {
  304.                 f = (double)va_arg( args, double );
  305.                 pos = f * len;
  306.                 if( dvdnav_sector_search( p_sys->dvdnav, pos, SEEK_SET ) ==
  307.                       DVDNAV_STATUS_OK )
  308.                 {
  309.                     return VLC_SUCCESS;
  310.                 }
  311.             }
  312.             else if( i_query == DEMUX_GET_TIME )
  313.             {
  314.                 pi64 = (int64_t*)va_arg( args, int64_t * );
  315.                 if( p_sys->i_mux_rate > 0 )
  316.                 {
  317.                     *pi64 = (int64_t)1000000 * 2048 * pos / 50 /
  318.                         p_sys->i_mux_rate;
  319.                     return VLC_SUCCESS;
  320.                 }
  321.             }
  322.             else if( i_query == DEMUX_GET_LENGTH )
  323.             {
  324.                 pi64 = (int64_t*)va_arg( args, int64_t * );
  325.                 if( p_sys->i_mux_rate > 0 )
  326.                 {
  327.                     *pi64 = (int64_t)1000000 * len * 2048 / 50 /
  328.                         p_sys->i_mux_rate;
  329.                     return VLC_SUCCESS;
  330.                 }
  331.             }
  332.             return VLC_EGENERIC;
  333.         }
  334.         /* Special for access_demux */
  335.         case DEMUX_CAN_PAUSE:
  336.         case DEMUX_CAN_CONTROL_PACE:
  337.             /* TODO */
  338.             pb = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
  339.             *pb = VLC_TRUE;
  340.             return VLC_SUCCESS;
  341.         case DEMUX_SET_PAUSE_STATE:
  342.             return VLC_SUCCESS;
  343.         case DEMUX_GET_TITLE_INFO:
  344.             ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
  345.             pi_int    = (int*)va_arg( args, int* );
  346.             *((int*)va_arg( args, int* )) = 0; /* Title offset */
  347.             *((int*)va_arg( args, int* )) = 1; /* Chapter offset */
  348.             /* Duplicate title infos */
  349.             *pi_int = p_sys->i_title;
  350.             *ppp_title = malloc( sizeof( input_title_t ** ) * p_sys->i_title );
  351.             for( i = 0; i < p_sys->i_title; i++ )
  352.             {
  353.                 (*ppp_title)[i] = vlc_input_title_Duplicate( p_sys->title[i] );
  354.             }
  355.             return VLC_SUCCESS;
  356.         case DEMUX_SET_TITLE:
  357.             i = (int)va_arg( args, int );
  358.             if( ( i == 0 && dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Root )
  359.                   != DVDNAV_STATUS_OK ) ||
  360.                 ( i != 0 && dvdnav_title_play( p_sys->dvdnav, i )
  361.                   != DVDNAV_STATUS_OK ) )
  362.             {
  363.                 msg_Warn( p_demux, "cannot set title/chapter" );
  364.                 return VLC_EGENERIC;
  365.             }
  366.             p_demux->info.i_update |=
  367.                 INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
  368.             p_demux->info.i_title = i;
  369.             p_demux->info.i_seekpoint = 0;
  370.             return VLC_SUCCESS;
  371.         case DEMUX_SET_SEEKPOINT:
  372.             i = (int)va_arg( args, int );
  373.             if( p_demux->info.i_title == 0 )
  374.             {
  375.                 int i_ret;
  376.                 /* Special case */
  377.                 switch( i )
  378.                 {
  379.                 case 0:
  380.                     i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Escape );
  381.                     break;
  382.                 case 1:
  383.                     i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Root );
  384.                     break;
  385.                 case 2:
  386.                     i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Title );
  387.                     break;
  388.                 case 3:
  389.                     i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Part );
  390.                     break;
  391.                 case 4:
  392.                     i_ret = dvdnav_menu_call( p_sys->dvdnav,
  393.                                               DVD_MENU_Subpicture );
  394.                     break;
  395.                 case 5:
  396.                     i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Audio );
  397.                     break;
  398.                 case 6:
  399.                     i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Angle );
  400.                     break;
  401.                 default:
  402.                     return VLC_EGENERIC;
  403.                 }
  404.                 if( i_ret != DVDNAV_STATUS_OK )
  405.                     return VLC_EGENERIC;
  406.             }
  407.             else if( dvdnav_part_play( p_sys->dvdnav, p_demux->info.i_title,
  408.                                        i + 1 ) != DVDNAV_STATUS_OK )
  409.             {
  410.                 msg_Warn( p_demux, "cannot set title/chapter" );
  411.                 return VLC_EGENERIC;
  412.             }
  413.             p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
  414.             p_demux->info.i_seekpoint = i;
  415.             return VLC_SUCCESS;
  416.         case DEMUX_GET_PTS_DELAY:
  417.             pi64 = (int64_t*)va_arg( args, int64_t * );
  418.             *pi64 = (int64_t)var_GetInteger( p_demux, "dvdnav-caching" ) *1000;
  419.             return VLC_SUCCESS;
  420.         /* TODO implement others */
  421.         default:
  422.             return VLC_EGENERIC;
  423.     }
  424. }
  425. /*****************************************************************************
  426.  * Demux:
  427.  *****************************************************************************/
  428. static int Demux( demux_t *p_demux )
  429. {
  430.     demux_sys_t *p_sys = p_demux->p_sys;
  431.     uint8_t buffer[DVD_VIDEO_LB_LEN];
  432.     uint8_t *packet = buffer;
  433.     int i_event;
  434.     int i_len;
  435. #if DVD_READ_CACHE
  436.     if( dvdnav_get_next_cache_block( p_sys->dvdnav, &packet, &i_event, &i_len )
  437.         == DVDNAV_STATUS_ERR )
  438. #else
  439.     if( dvdnav_get_next_block( p_sys->dvdnav, packet, &i_event, &i_len )
  440.         == DVDNAV_STATUS_ERR )
  441. #endif
  442.     {
  443.         msg_Warn( p_demux, "cannot get next block (%s)",
  444.                   dvdnav_err_to_string( p_sys->dvdnav ) );
  445.         return -1;
  446.     }
  447.     switch( i_event )
  448.     {
  449.     case DVDNAV_BLOCK_OK:   /* mpeg block */
  450.         DemuxBlock( p_demux, packet, i_len );
  451.         break;
  452.     case DVDNAV_NOP:    /* Nothing */
  453.         msg_Dbg( p_demux, "DVDNAV_NOP" );
  454.         break;
  455.     case DVDNAV_STILL_FRAME:
  456.     {
  457.         dvdnav_still_event_t *event = (dvdnav_still_event_t*)packet;
  458.         vlc_mutex_lock( &p_sys->p_ev->lock );
  459.         if( !p_sys->p_ev->b_still )
  460.         {
  461.             msg_Dbg( p_demux, "DVDNAV_STILL_FRAME" );
  462.             msg_Dbg( p_demux, "     - length=0x%x", event->length );
  463.             p_sys->p_ev->b_still = VLC_TRUE;
  464.             if( event->length == 0xff )
  465.             {
  466.                 p_sys->p_ev->i_still_end = 0;
  467.             }
  468.             else
  469.             {
  470.                 p_sys->p_ev->i_still_end = (int64_t)event->length *
  471.                     1000000 + mdate() + p_sys->p_input->i_pts_delay;
  472.             }
  473.         }
  474.         vlc_mutex_unlock( &p_sys->p_ev->lock );
  475.         msleep( 40000 );
  476.         break;
  477.     }
  478.     case DVDNAV_SPU_CLUT_CHANGE:
  479.     {
  480.         int i;
  481.         msg_Dbg( p_demux, "DVDNAV_SPU_CLUT_CHANGE" );
  482.         /* Update color lookup table (16 *uint32_t in packet) */
  483.         memcpy( p_sys->clut, packet, 16 * sizeof( uint32_t ) );
  484.         /* HACK to get the SPU tracks registered in the right order */
  485.         for( i = 0; i < 0x1f; i++ )
  486.         {
  487.             if( dvdnav_spu_stream_to_lang( p_sys->dvdnav, i ) != 0xffff )
  488.                 ESNew( p_demux, 0xbd20 + i );
  489.         }
  490.         /* END HACK */
  491.         break;
  492.     }
  493.     case DVDNAV_SPU_STREAM_CHANGE:
  494.     {
  495.         dvdnav_spu_stream_change_event_t *event =
  496.             (dvdnav_spu_stream_change_event_t*)packet;
  497.         int i;
  498.         msg_Dbg( p_demux, "DVDNAV_SPU_STREAM_CHANGE" );
  499.         msg_Dbg( p_demux, "     - physical_wide=%d",
  500.                  event->physical_wide );
  501.         msg_Dbg( p_demux, "     - physical_letterbox=%d",
  502.                  event->physical_letterbox);
  503.         msg_Dbg( p_demux, "     - physical_pan_scan=%d",
  504.                  event->physical_pan_scan );
  505.         ESSubtitleUpdate( p_demux );
  506.         /* HACK to get the SPU tracks registered in the right order */
  507.         for( i = 0; i < 0x1f; i++ )
  508.         {
  509.             if( dvdnav_spu_stream_to_lang( p_sys->dvdnav, i ) != 0xffff )
  510.                 ESNew( p_demux, 0xbd20 + i );
  511.         }
  512.         /* END HACK */
  513.         break;
  514.     }
  515.     case DVDNAV_AUDIO_STREAM_CHANGE:
  516.     {
  517.         dvdnav_audio_stream_change_event_t *event =
  518.             (dvdnav_audio_stream_change_event_t*)packet;
  519.         msg_Dbg( p_demux, "DVDNAV_AUDIO_STREAM_CHANGE" );
  520.         msg_Dbg( p_demux, "     - physical=%d", event->physical );
  521.         /* TODO */
  522.         break;
  523.     }
  524.     case DVDNAV_VTS_CHANGE:
  525.     {
  526.         int32_t i_title = 0;
  527.         int32_t i_part  = 0;
  528.         int i;
  529.         dvdnav_vts_change_event_t *event = (dvdnav_vts_change_event_t*)packet;
  530.         msg_Dbg( p_demux, "DVDNAV_VTS_CHANGE" );
  531.         msg_Dbg( p_demux, "     - vtsN=%d", event->new_vtsN );
  532.         msg_Dbg( p_demux, "     - domain=%d", event->new_domain );
  533.         /* dvdnav_get_video_aspect / dvdnav_get_video_scale_permission */
  534.         /* TODO check if we always have VTS and CELL */
  535.         p_sys->i_aspect = dvdnav_get_video_aspect( p_sys->dvdnav );
  536.         /* reset PCR */
  537.         es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
  538.         for( i = 0; i < PS_TK_COUNT; i++ )
  539.         {
  540.             ps_track_t *tk = &p_sys->tk[i];
  541.             if( tk->b_seen )
  542.             {
  543.                 es_format_Clean( &tk->fmt );
  544.                 if( tk->es ) es_out_Del( p_demux->out, tk->es );
  545.             }
  546.             tk->b_seen = VLC_FALSE;
  547.         }
  548.         if( dvdnav_current_title_info( p_sys->dvdnav, &i_title,
  549.                                        &i_part ) == DVDNAV_STATUS_OK )
  550.         {
  551.             if( i_title >= 0 && i_title < p_sys->i_title &&
  552.                 p_demux->info.i_title != i_title )
  553.             {
  554.                 p_demux->info.i_update |= INPUT_UPDATE_TITLE;
  555.                 p_demux->info.i_title = i_title;
  556.             }
  557.         }
  558.         break;
  559.     }
  560.     case DVDNAV_CELL_CHANGE:
  561.     {
  562.         int32_t i_title = 0;
  563.         int32_t i_part  = 0;
  564.         dvdnav_cell_change_event_t *event =
  565.             (dvdnav_cell_change_event_t*)packet;
  566.         msg_Dbg( p_demux, "DVDNAV_CELL_CHANGE" );
  567.         msg_Dbg( p_demux, "     - cellN=%d", event->cellN );
  568.         msg_Dbg( p_demux, "     - pgN=%d", event->pgN );
  569.         msg_Dbg( p_demux, "     - cell_length=%lld", event->cell_length );
  570.         msg_Dbg( p_demux, "     - pg_length=%lld", event->pg_length );
  571.         msg_Dbg( p_demux, "     - pgc_length=%lld", event->pgc_length );
  572.         msg_Dbg( p_demux, "     - cell_start=%lld", event->cell_start );
  573.         msg_Dbg( p_demux, "     - pg_start=%lld", event->pg_start );
  574.         /* FIXME is it correct or there is better way to know chapter change */
  575.         if( dvdnav_current_title_info( p_sys->dvdnav, &i_title,
  576.                                        &i_part ) == DVDNAV_STATUS_OK )
  577.         {
  578.             if( i_title >= 0 && i_title < p_sys->i_title &&
  579.                 i_part >= 1 && i_part <= p_sys->title[i_title]->i_seekpoint &&
  580.                 p_demux->info.i_seekpoint != i_part - 1 )
  581.             {
  582.                 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
  583.                 p_demux->info.i_seekpoint = i_part - 1;
  584.             }
  585.         }
  586.         break;
  587.     }
  588.     case DVDNAV_NAV_PACKET:
  589.     {
  590. #ifdef DVDNAV_DEBUG
  591.         msg_Dbg( p_demux, "DVDNAV_NAV_PACKET" );
  592. #endif
  593.         /* A lot of thing to do here :
  594.          *  - handle packet
  595.          *  - fetch pts (for time display)
  596.          *  - ...
  597.          */
  598.         DemuxBlock( p_demux, packet, i_len );
  599.         break;
  600.     }
  601.     case DVDNAV_STOP:   /* EOF */
  602.         msg_Dbg( p_demux, "DVDNAV_STOP" );
  603.         return 0;
  604.     case DVDNAV_HIGHLIGHT:
  605.     {
  606.         dvdnav_highlight_event_t *event = (dvdnav_highlight_event_t*)packet;
  607.         msg_Dbg( p_demux, "DVDNAV_HIGHLIGHT" );
  608.         msg_Dbg( p_demux, "     - display=%d", event->display );
  609.         msg_Dbg( p_demux, "     - buttonN=%d", event->buttonN );
  610.         ButtonUpdate( p_demux );
  611.         break;
  612.     }
  613.     case DVDNAV_HOP_CHANNEL:
  614.         msg_Dbg( p_demux, "DVDNAV_HOP_CHANNEL" );
  615.         /* We should try to flush all our internal buffer */
  616.         break;
  617.     case DVDNAV_WAIT:
  618.         msg_Dbg( p_demux, "DVDNAV_WAIT" );
  619.         dvdnav_wait_skip( p_sys->dvdnav );
  620.         break;
  621.     default:
  622.         msg_Warn( p_demux, "Unknown event (0x%x)", i_event );
  623.         break;
  624.     }
  625. #if DVD_READ_CACHE
  626.     dvdnav_free_cache_block( p_sys->dvdnav, packet );
  627. #endif
  628.     return 1;
  629. }
  630. static void DemuxTitles( demux_t *p_demux )
  631. {
  632.     demux_sys_t *p_sys = p_demux->p_sys;
  633.     input_title_t *t;
  634.     seekpoint_t *s;
  635.     int32_t i_titles;
  636.     int i;
  637.     /* Menu */
  638.     t = vlc_input_title_New();
  639.     t->b_menu = VLC_TRUE;
  640.     t->psz_name = strdup( "DVD Menu" );
  641.     s = vlc_seekpoint_New();
  642.     s->psz_name = strdup( "Resume" );
  643.     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
  644.     s = vlc_seekpoint_New();
  645.     s->psz_name = strdup( "Root" );
  646.     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
  647.     s = vlc_seekpoint_New();
  648.     s->psz_name = strdup( "Title" );
  649.     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
  650.     s = vlc_seekpoint_New();
  651.     s->psz_name = strdup( "Chapter" );
  652.     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
  653.     s = vlc_seekpoint_New();
  654.     s->psz_name = strdup( "Subtitle" );
  655.     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
  656.     s = vlc_seekpoint_New();
  657.     s->psz_name = strdup( "Audio" );
  658.     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
  659.     s = vlc_seekpoint_New();
  660.     s->psz_name = strdup( "Angle" );
  661.     TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
  662.     TAB_APPEND( p_sys->i_title, p_sys->title, t );
  663.     /* Find out number of titles/chapters */
  664.     dvdnav_get_number_of_titles( p_sys->dvdnav, &i_titles );
  665.     for( i = 1; i <= i_titles; i++ )
  666.     {
  667.         int32_t i_chapters = 0;
  668.         int j;
  669.         dvdnav_get_number_of_parts( p_sys->dvdnav, i, &i_chapters );
  670.         t = vlc_input_title_New();
  671.         for( j = 0; j < __MAX( i_chapters, 1 ); j++ )
  672.         {
  673.             s = vlc_seekpoint_New();
  674.             TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
  675.         }
  676.         TAB_APPEND( p_sys->i_title, p_sys->title, t );
  677.     }
  678. }
  679. /*****************************************************************************
  680.  * Update functions:
  681.  *****************************************************************************/
  682. static void ButtonUpdate( demux_t *p_demux )
  683. {
  684.     demux_sys_t *p_sys = p_demux->p_sys;
  685.     vlc_value_t val;
  686.     int32_t i_title, i_part;
  687.     dvdnav_current_title_info( p_sys->dvdnav, &i_title, &i_part );
  688.     if( var_Get( p_sys->p_input, "highlight-mutex", &val ) == VLC_SUCCESS )
  689.     {
  690.         vlc_mutex_t *p_mutex = val.p_address;
  691.         dvdnav_highlight_area_t hl;
  692.         int32_t i_button;
  693.         if( dvdnav_get_current_highlight( p_sys->dvdnav, &i_button )
  694.             != DVDNAV_STATUS_OK )
  695.         {
  696.             msg_Err( p_demux, "dvdnav_get_current_highlight failed" );
  697.             return;
  698.         }
  699.         if( i_button > 0 && i_title ==  0 )
  700.         {
  701.             pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );
  702.             dvdnav_get_highlight_area( pci, i_button, 1, &hl );
  703.             /* I fear it is plain wrong */
  704.             p_sys->alpha[0] = hl.palette&0x0f;
  705.             p_sys->alpha[1] = (hl.palette>>4)&0x0f;
  706.             p_sys->alpha[2] = (hl.palette>>8)&0x0f;
  707.             p_sys->alpha[3] = (hl.palette>>12)&0x0f;
  708.             vlc_mutex_lock( p_mutex );
  709.             val.i_int = hl.sx; var_Set( p_sys->p_input, "x-start", val );
  710.             val.i_int = hl.ex; var_Set( p_sys->p_input, "x-end", val );
  711.             val.i_int = hl.sy; var_Set( p_sys->p_input, "y-start", val );
  712.             val.i_int = hl.ey; var_Set( p_sys->p_input, "y-end", val );
  713.             val.p_address = (void *)p_sys->alpha;
  714.             var_Set( p_sys->p_input, "contrast", val );
  715.             val.b_bool = VLC_TRUE; var_Set( p_sys->p_input, "highlight", val );
  716.             vlc_mutex_unlock( p_mutex );
  717.             msg_Dbg( p_demux, "buttonUpdate %d", i_button );
  718.         }
  719.         else
  720.         {
  721.             msg_Dbg( p_demux, "buttonUpdate not done b=%d t=%d",
  722.                      i_button, i_title );
  723.             /* Show all */
  724.             vlc_mutex_lock( p_mutex );
  725.             val.b_bool = VLC_FALSE;
  726.             var_Set( p_sys->p_input, "highlight", val );
  727.             vlc_mutex_unlock( p_mutex );
  728.         }
  729.     }
  730. }
  731. static void ESSubtitleUpdate( demux_t *p_demux )
  732. {
  733.     demux_sys_t *p_sys = p_demux->p_sys;
  734.     int         i_spu = dvdnav_get_active_spu_stream( p_sys->dvdnav );
  735.     int32_t i_title, i_part;
  736.     ButtonUpdate( p_demux );
  737.     dvdnav_current_title_info( p_sys->dvdnav, &i_title, &i_part );
  738.     if( i_title > 0 ) return;
  739.     if( i_spu >= 0 && i_spu <= 0x1f )
  740.     {
  741.         ps_track_t *tk = &p_sys->tk[PS_ID_TO_TK(0xbd20 + i_spu)];
  742.         ESNew( p_demux, 0xbd20 + i_spu );
  743.         /* be sure to unselect it (reset) */
  744.         es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE, tk->es,
  745.                         (vlc_bool_t)VLC_FALSE );
  746.         /* now select it */
  747.         es_out_Control( p_demux->out, ES_OUT_SET_ES, tk->es );
  748.     }
  749.     else
  750.     {
  751.         for( i_spu = 0; i_spu <= 0x1F; i_spu++ )
  752.         {
  753.             ps_track_t *tk = &p_sys->tk[PS_ID_TO_TK(0xbd20 + i_spu)];
  754.             if( tk->b_seen )
  755.             {
  756.                 es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE, tk->es,
  757.                                 (vlc_bool_t)VLC_FALSE );
  758.             }
  759.         }
  760.     }
  761. }
  762. /*****************************************************************************
  763.  * DemuxBlock: demux a given block
  764.  *****************************************************************************/
  765. static int DemuxBlock( demux_t *p_demux, uint8_t *pkt, int i_pkt )
  766. {
  767.     demux_sys_t *p_sys = p_demux->p_sys;
  768.     uint8_t     *p = pkt;
  769.     while( p < &pkt[i_pkt] )
  770.     {
  771.         int i_size = ps_pkt_size( p, &pkt[i_pkt] - p );
  772.         block_t *p_pkt;
  773.         if( i_size <= 0 )
  774.         {
  775.             break;
  776.         }
  777.         /* Create a block */
  778.         p_pkt = block_New( p_demux, i_size );
  779.         memcpy( p_pkt->p_buffer, p, i_size);
  780.         /* Parse it and send it */
  781.         switch( 0x100 | p[3] )
  782.         {
  783.         case 0x1b9:
  784.         case 0x1bb:
  785.         case 0x1bc:
  786. #ifdef DVDNAV_DEBUG
  787.             if( p[3] == 0xbc )
  788.             {
  789.                 msg_Warn( p_demux, "received a PSM packet" );
  790.             }
  791.             else if( p[3] == 0xbb )
  792.             {
  793.                 msg_Warn( p_demux, "received a SYSTEM packet" );
  794.             }
  795. #endif
  796.             block_Release( p_pkt );
  797.             break;
  798.         case 0x1ba:
  799.         {
  800.             int64_t i_scr;
  801.             int i_mux_rate;
  802.             if( !ps_pkt_parse_pack( p_pkt, &i_scr, &i_mux_rate ) )
  803.             {
  804.                 es_out_Control( p_demux->out, ES_OUT_SET_PCR, i_scr );
  805.                 if( i_mux_rate > 0 ) p_sys->i_mux_rate = i_mux_rate;
  806.             }
  807.             block_Release( p_pkt );
  808.             break;
  809.         }
  810.         default:
  811.         {
  812.             int i_id = ps_pkt_id( p_pkt );
  813.             if( i_id >= 0xc0 )
  814.             {
  815.                 ps_track_t *tk = &p_sys->tk[PS_ID_TO_TK(i_id)];
  816.                 if( !tk->b_seen )
  817.                 {
  818.                     ESNew( p_demux, i_id );
  819.                 }
  820.                 if( tk->b_seen && tk->es &&
  821.                     !ps_pkt_parse_pes( p_pkt, tk->i_skip ) )
  822.                 {
  823.                     es_out_Send( p_demux->out, tk->es, p_pkt );
  824.                 }
  825.                 else
  826.                 {
  827.                     block_Release( p_pkt );
  828.                 }
  829.             }
  830.             else
  831.             {
  832.                 block_Release( p_pkt );
  833.             }
  834.             break;
  835.         }
  836.         }
  837.         p += i_size;
  838.     }
  839.     return VLC_SUCCESS;
  840. }
  841. /*****************************************************************************
  842.  * ESNew: register a new elementary stream
  843.  *****************************************************************************/
  844. static void ESNew( demux_t *p_demux, int i_id )
  845. {
  846.     demux_sys_t *p_sys = p_demux->p_sys;
  847.     ps_track_t  *tk = &p_sys->tk[PS_ID_TO_TK(i_id)];
  848.     vlc_bool_t  b_select = VLC_FALSE;
  849.     if( tk->b_seen ) return;
  850.     if( ps_track_fill( tk, 0, i_id ) )
  851.     {
  852.         msg_Warn( p_demux, "unknown codec for id=0x%x", i_id );
  853.         return;
  854.     }
  855.     /* Add a new ES */
  856.     if( tk->fmt.i_cat == VIDEO_ES )
  857.     {
  858.         if( p_sys->i_aspect >= 0 )
  859.         {
  860.             tk->fmt.video.i_aspect = p_sys->i_aspect;
  861.         }
  862.         b_select = VLC_TRUE;
  863.     }
  864.     else if( tk->fmt.i_cat == AUDIO_ES )
  865.     {
  866.         int i_audio = -1;
  867.         /* find the audio number PLEASE find another way */
  868.         if( (i_id&0xbdf8) == 0xbd88 )       /* dts */
  869.         {
  870.             i_audio = i_id&0x07;
  871.         }
  872.         else if( (i_id&0xbdf0) == 0xbd80 )  /* a52 */
  873.         {
  874.             i_audio = i_id&0xf;
  875.         }
  876.         else if( (i_id&0xbdf0) == 0xbda0 )  /* lpcm */
  877.         {
  878.             i_audio = i_id&0x1f;
  879.         }
  880.         else if( ( i_id&0xe0 ) == 0xc0 )    /* mpga */
  881.         {
  882.             i_audio = i_id&0x1f;
  883.         }
  884.         if( i_audio >= 0 )
  885.         {
  886.             int i_lang = dvdnav_audio_stream_to_lang( p_sys->dvdnav, i_audio );
  887.             if( i_lang != 0xffff )
  888.             {
  889.                 tk->fmt.psz_language = malloc( 3 );
  890.                 tk->fmt.psz_language[0] = (i_lang >> 8)&0xff;
  891.                 tk->fmt.psz_language[1] = (i_lang     )&0xff;
  892.                 tk->fmt.psz_language[2] = 0;
  893.             }
  894.             if( dvdnav_get_active_audio_stream( p_sys->dvdnav ) == i_audio )
  895.             {
  896.                 b_select = VLC_TRUE;
  897.             }
  898.         }
  899.     }
  900.     else if( tk->fmt.i_cat == SPU_ES )
  901.     {
  902.         int32_t i_title, i_part;
  903.         int i_lang = dvdnav_spu_stream_to_lang( p_sys->dvdnav, i_id&0x1f );
  904.         if( i_lang != 0xffff )
  905.         {
  906.             tk->fmt.psz_language = malloc( 3 );
  907.             tk->fmt.psz_language[0] = (i_lang >> 8)&0xff;
  908.             tk->fmt.psz_language[1] = (i_lang     )&0xff;
  909.             tk->fmt.psz_language[2] = 0;
  910.         }
  911.         /* Palette */
  912.         tk->fmt.subs.spu.palette[0] = 0xBeef;
  913.         memcpy( &tk->fmt.subs.spu.palette[1], p_sys->clut,
  914.                 16 * sizeof( uint32_t ) );
  915.         /* We select only when we are not in the menu */
  916.         dvdnav_current_title_info( p_sys->dvdnav, &i_title, &i_part );
  917.         if( i_title > 0 &&
  918.             dvdnav_get_active_spu_stream( p_sys->dvdnav ) == (i_id&0x1f) )
  919.         {
  920.             b_select = VLC_TRUE;
  921.         }
  922.     }
  923.     tk->es = es_out_Add( p_demux->out, &tk->fmt );
  924.     if( b_select )
  925.     {
  926.         es_out_Control( p_demux->out, ES_OUT_SET_ES, tk->es );
  927.     }
  928.     tk->b_seen = VLC_TRUE;
  929.     if( tk->fmt.i_cat == VIDEO_ES ) ButtonUpdate( p_demux );
  930. }
  931. /*****************************************************************************
  932.  * Event handler code
  933.  *****************************************************************************/
  934. static int  EventMouse( vlc_object_t *, char const *,
  935.                         vlc_value_t, vlc_value_t, void * );
  936. static int  EventKey  ( vlc_object_t *, char const *,
  937.                         vlc_value_t, vlc_value_t, void * );
  938. static int EventThread( vlc_object_t *p_this )
  939. {
  940.     event_thread_t *p_ev = (event_thread_t*)p_this;
  941.     demux_sys_t    *p_sys = p_ev->p_demux->p_sys;
  942.     vlc_object_t   *p_vout = NULL;
  943.     vlc_mutex_init( p_ev, &p_ev->lock );
  944.     p_ev->b_moved   = VLC_FALSE;
  945.     p_ev->b_clicked = VLC_FALSE;
  946.     p_ev->b_key     = VLC_FALSE;
  947.     p_ev->b_still   = VLC_FALSE;
  948.     /* catch all key event */
  949.     var_AddCallback( p_ev->p_vlc, "key-pressed", EventKey, p_ev );
  950.     /* main loop */
  951.     while( !p_ev->b_die )
  952.     {
  953.         vlc_bool_t b_activated = VLC_FALSE;
  954.         /* KEY part */
  955.         if( p_ev->b_key )
  956.         {
  957.             pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );
  958.             vlc_value_t valk;
  959.             struct hotkey *p_hotkeys = p_ev->p_vlc->p_hotkeys;
  960.             int i, i_action = -1;
  961.             vlc_mutex_lock( &p_ev->lock );
  962.             var_Get( p_ev->p_vlc, "key-pressed", &valk );
  963.             for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
  964.             {
  965.                 if( p_hotkeys[i].i_key == valk.i_int )
  966.                 {
  967.                     i_action = p_hotkeys[i].i_action;
  968.                 }
  969.             }
  970.             switch( i_action )
  971.             {
  972.             case ACTIONID_NAV_LEFT:
  973.                 dvdnav_left_button_select( p_sys->dvdnav, pci );
  974.                 break;
  975.             case ACTIONID_NAV_RIGHT:
  976.                 dvdnav_right_button_select( p_sys->dvdnav, pci );
  977.                 break;
  978.             case ACTIONID_NAV_UP:
  979.                 dvdnav_upper_button_select( p_sys->dvdnav, pci );
  980.                 break;
  981.             case ACTIONID_NAV_DOWN:
  982.                 dvdnav_lower_button_select( p_sys->dvdnav, pci );
  983.                 break;
  984.             case ACTIONID_NAV_ACTIVATE:
  985.                 b_activated = VLC_TRUE;
  986.                 dvdnav_button_activate( p_sys->dvdnav, pci );
  987.                 break;
  988.             default:
  989.                 break;
  990.             }
  991.             p_ev->b_key = VLC_FALSE;
  992.             vlc_mutex_unlock( &p_ev->lock );
  993.         }
  994.         /* VOUT part */
  995.         if( p_vout && ( p_ev->b_moved || p_ev->b_clicked ) )
  996.         {
  997.             pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );
  998.             vlc_value_t valx, valy;
  999.             vlc_mutex_lock( &p_ev->lock );
  1000.             var_Get( p_vout, "mouse-x", &valx );
  1001.             var_Get( p_vout, "mouse-y", &valy );
  1002.             if( p_ev->b_moved )
  1003.             {
  1004.                 dvdnav_mouse_select( p_sys->dvdnav, pci, valx.i_int,
  1005.                                      valy.i_int );
  1006.             }
  1007.             if( p_ev->b_clicked )
  1008.             {
  1009.                 b_activated = VLC_TRUE;
  1010.                 dvdnav_mouse_activate( p_sys->dvdnav, pci, valx.i_int,
  1011.                                        valy.i_int );
  1012.             }
  1013.             p_ev->b_moved = VLC_FALSE;
  1014.             p_ev->b_clicked = VLC_FALSE;
  1015.             vlc_mutex_unlock( &p_ev->lock );
  1016.         }
  1017.         if( p_vout && p_vout->b_die )
  1018.         {
  1019.             var_DelCallback( p_vout, "mouse-moved", EventMouse, p_ev );
  1020.             var_DelCallback( p_vout, "mouse-clicked", EventMouse, p_ev );
  1021.             vlc_object_release( p_vout );
  1022.             p_vout = NULL;
  1023.         }
  1024.         if( p_vout == NULL )
  1025.         {
  1026.             p_vout = vlc_object_find( p_sys->p_input, VLC_OBJECT_VOUT,
  1027.                                       FIND_CHILD );
  1028.             if( p_vout)
  1029.             {
  1030.                 var_AddCallback( p_vout, "mouse-moved", EventMouse, p_ev );
  1031.                 var_AddCallback( p_vout, "mouse-clicked", EventMouse, p_ev );
  1032.             }
  1033.         }
  1034.         /* Still part */
  1035.         vlc_mutex_lock( &p_ev->lock );
  1036.         if( p_ev->b_still )
  1037.         {
  1038.             if( /* b_activated || // This breaks menus */
  1039.                 ( p_ev->i_still_end > 0 && p_ev->i_still_end < mdate() ))
  1040.             {
  1041.                 p_ev->b_still = VLC_FALSE;
  1042.                 dvdnav_still_skip( p_sys->dvdnav );
  1043.             }
  1044.         }
  1045.         vlc_mutex_unlock( &p_ev->lock );
  1046.         /* Wait a bit */
  1047.         msleep( 10000 );
  1048.     }
  1049.     /* Release callback */
  1050.     if( p_vout )
  1051.     {
  1052.         var_DelCallback( p_vout, "mouse-moved", EventMouse, p_ev );
  1053.         var_DelCallback( p_vout, "mouse-clicked", EventMouse, p_ev );
  1054.         vlc_object_release( p_vout );
  1055.     }
  1056.     var_DelCallback( p_ev->p_vlc, "key-pressed", EventKey, p_ev );
  1057.     vlc_mutex_destroy( &p_ev->lock );
  1058.     return VLC_SUCCESS;
  1059. }
  1060. static int EventMouse( vlc_object_t *p_this, char const *psz_var,
  1061.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1062. {
  1063.     event_thread_t *p_ev = p_data;
  1064.     vlc_mutex_lock( &p_ev->lock );
  1065.     if( psz_var[6] == 'c' )
  1066.         p_ev->b_clicked = VLC_TRUE;
  1067.     else if( psz_var[6] == 'm' )
  1068.         p_ev->b_moved = VLC_TRUE;
  1069.     vlc_mutex_unlock( &p_ev->lock );
  1070.     return VLC_SUCCESS;
  1071. }
  1072. static int EventKey( vlc_object_t *p_this, char const *psz_var,
  1073.                      vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1074. {
  1075.     event_thread_t *p_ev = p_data;
  1076.     vlc_mutex_lock( &p_ev->lock );
  1077.     p_ev->b_key = VLC_TRUE;
  1078.     vlc_mutex_unlock( &p_ev->lock );
  1079.     return VLC_SUCCESS;
  1080. }
  1081. /*****************************************************************************
  1082.  * ProbeDVD: very weak probing that avoids going too often into a dvdnav_open()
  1083.  *****************************************************************************/
  1084. static int ProbeDVD( demux_t *p_demux, char *psz_name )
  1085. {
  1086. #ifdef HAVE_SYS_STAT_H
  1087.     struct stat stat_info;
  1088.     uint8_t pi_anchor[2];
  1089.     uint16_t i_tag_id = 0;
  1090.     int i_fd, i_ret;
  1091.     if( stat( psz_name, &stat_info ) || !S_ISREG( stat_info.st_mode ) )
  1092.     {
  1093.         /* Let dvdnav_open() do the probing */
  1094.         return VLC_SUCCESS;
  1095.     }
  1096.     if( (i_fd = open( psz_name, O_RDONLY )) == -1 )
  1097.     {
  1098.         /* Let dvdnav_open() do the probing */
  1099.         return VLC_SUCCESS;
  1100.     }
  1101.     /* Try to find the anchor (2 bytes at LBA 256) */
  1102.     i_ret = VLC_SUCCESS;
  1103.     if( lseek( i_fd, 256 * DVD_VIDEO_LB_LEN, SEEK_SET ) == -1 )
  1104.     {
  1105.         i_ret = VLC_EGENERIC;
  1106.     }
  1107.     if( read( i_fd, pi_anchor, 2 ) == 2 )
  1108.     {
  1109.         i_tag_id = GetWLE(pi_anchor);
  1110.         if( i_tag_id != 2 ) i_ret = VLC_EGENERIC; /* Not an anchor */
  1111.     }
  1112.     else
  1113.     {
  1114.         i_ret = VLC_EGENERIC;
  1115.     }
  1116.     close( i_fd );
  1117.     return i_ret;
  1118. #else
  1119.     return VLC_SUCCESS;
  1120. #endif
  1121. }