📄 dvdnav.c
字号:
/***************************************************************************** * dvdnav.c: DVD module using the dvdnav library. ***************************************************************************** * Copyright (C) 2004 the VideoLAN team * $Id: 9c4677044631e76949f3215e11403e37eedee506 $ * * Authors: Laurent Aimar <fenrir@via.ecp.fr> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <vlc_plugin.h>#include <vlc_input.h>#include <vlc_access.h>#include <vlc_demux.h>#include <vlc_charset.h>#include <vlc_interface.h>#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#ifdef HAVE_SYS_TYPES_H# include <sys/types.h>#endif#ifdef HAVE_SYS_STAT_H# include <sys/stat.h>#endif#ifdef HAVE_FCNTL_H# include <fcntl.h>#endif#include "vlc_keys.h"#include "vlc_iso_lang.h"/* FIXME we should find a better way than including that */#include "../../src/text/iso-639_def.h"#include <dvdnav/dvdnav.h>#include "../demux/ps.h"/***************************************************************************** * Module descriptor *****************************************************************************/#define ANGLE_TEXT N_("DVD angle")#define ANGLE_LONGTEXT N_( \ "Default DVD angle." )#define CACHING_TEXT N_("Caching value in ms")#define CACHING_LONGTEXT N_( \ "Caching value for DVDs. This "\ "value should be set in milliseconds." )#define MENU_TEXT N_("Start directly in menu")#define MENU_LONGTEXT N_( \ "Start the DVD directly in the main menu. This "\ "will try to skip all the useless warning introductions." )#define LANGUAGE_DEFAULT ("en")static int Open ( vlc_object_t * );static void Close( vlc_object_t * );vlc_module_begin(); set_shortname( N_("DVD with menus") ); set_description( N_("DVDnav Input") ); set_category( CAT_INPUT ); set_subcategory( SUBCAT_INPUT_ACCESS ); add_integer( "dvdnav-angle", 1, NULL, ANGLE_TEXT, ANGLE_LONGTEXT, false ); add_integer( "dvdnav-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, true ); add_bool( "dvdnav-menu", true, NULL, MENU_TEXT, MENU_LONGTEXT, false ); set_capability( "access_demux", 5 ); add_shortcut( "dvd" ); add_shortcut( "dvdnav" ); set_callbacks( Open, Close );vlc_module_end();/* Shall we use libdvdnav's read ahead cache? */#define DVD_READ_CACHE 1/***************************************************************************** * Local prototypes *****************************************************************************/typedef struct{ VLC_COMMON_MEMBERS demux_t *p_demux; vlc_mutex_t lock; bool b_moved; bool b_clicked; int i_key_action; bool b_still; int64_t i_still_end;} event_thread_t;static void* EventThread( vlc_object_t * );struct demux_sys_t{ dvdnav_t *dvdnav; /* track */ ps_track_t tk[PS_TK_COUNT]; int i_mux_rate; /* for spu variables */ input_thread_t *p_input; /* event */ event_thread_t *p_ev; /* palette for menus */ uint32_t clut[16]; uint8_t palette[4][4]; bool b_spu_change; /* */ int i_aspect; int i_title; input_title_t **title; /* lenght of program group chain */ mtime_t i_pgc_length;};static int Control( demux_t *, int, va_list );static int Demux( demux_t * );static int DemuxBlock( demux_t *, const uint8_t *, int );static void DemuxTitles( demux_t * );static void ESSubtitleUpdate( demux_t * );static void ButtonUpdate( demux_t *, bool );static void ESNew( demux_t *, int );static int ProbeDVD( demux_t *, char * );static char *DemuxGetLanguageCode( demux_t *p_demux, const char *psz_var );static int ControlInternal( demux_t *, int, ... );/***************************************************************************** * DemuxOpen: *****************************************************************************/static int Open( vlc_object_t *p_this ){ demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; dvdnav_t *p_dvdnav; int i_angle; char *psz_name; char *psz_code; vlc_value_t val; if( !p_demux->psz_path || !*p_demux->psz_path ) { /* Only when selected */ if( !p_this->b_force ) return VLC_EGENERIC; psz_name = var_CreateGetString( p_this, "dvd" ); if( !psz_name ) { psz_name = strdup(""); } } else psz_name = ToLocaleDup( p_demux->psz_path );#ifdef WIN32 if( psz_name[0] && psz_name[1] == ':' && psz_name[2] == '\\' && psz_name[3] == '\0' ) psz_name[2] = '\0';#endif /* Try some simple probing to avoid going through dvdnav_open too often */ if( ProbeDVD( p_demux, psz_name ) != VLC_SUCCESS ) { free( psz_name ); return VLC_EGENERIC; } /* Open dvdnav */ if( dvdnav_open( &p_dvdnav, psz_name ) != DVDNAV_STATUS_OK ) { msg_Warn( p_demux, "cannot open dvdnav" ); free( psz_name ); return VLC_EGENERIC; } free( psz_name ); /* Fill p_demux field */ DEMUX_INIT_COMMON(); p_sys = p_demux->p_sys; p_sys->dvdnav = p_dvdnav; ps_track_init( p_sys->tk ); p_sys->i_aspect = -1; p_sys->i_mux_rate = 0; p_sys->i_pgc_length = 0; p_sys->b_spu_change = false; if( 1 ) { // Hack for libdvdnav CVS. // Without it dvdnav_get_number_of_titles() fails. // Remove when fixed in libdvdnav CVS. uint8_t buffer[DVD_VIDEO_LB_LEN]; int i_event, i_len; if( dvdnav_get_next_block( p_sys->dvdnav, buffer, &i_event, &i_len ) == DVDNAV_STATUS_ERR ) { msg_Warn( p_demux, "dvdnav_get_next_block failed" ); } dvdnav_sector_search( p_sys->dvdnav, 0, SEEK_SET ); } /* Configure dvdnav */ if( dvdnav_set_readahead_flag( p_sys->dvdnav, DVD_READ_CACHE ) != DVDNAV_STATUS_OK ) { msg_Warn( p_demux, "cannot set read-a-head flag" ); } if( dvdnav_set_PGC_positioning_flag( p_sys->dvdnav, 1 ) != DVDNAV_STATUS_OK ) { msg_Warn( p_demux, "cannot set PGC positioning flag" ); } /* Set menu language * XXX A menu-language may be better than sub-language */ psz_code = DemuxGetLanguageCode( p_demux, "sub-language" ); if( dvdnav_menu_language_select( p_sys->dvdnav, psz_code ) != DVDNAV_STATUS_OK ) { msg_Warn( p_demux, "can't set menu language to '%s' (%s)", psz_code, dvdnav_err_to_string( p_sys->dvdnav ) ); /* We try to fall back to 'en' */ if( strcmp( psz_code, LANGUAGE_DEFAULT ) ) dvdnav_menu_language_select( p_sys->dvdnav, (char*)LANGUAGE_DEFAULT ); } free( psz_code ); /* Set audio language */ psz_code = DemuxGetLanguageCode( p_demux, "audio-language" ); if( dvdnav_audio_language_select( p_sys->dvdnav, psz_code ) != DVDNAV_STATUS_OK ) { msg_Warn( p_demux, "can't set audio language to '%s' (%s)", psz_code, dvdnav_err_to_string( p_sys->dvdnav ) ); /* We try to fall back to 'en' */ if( strcmp( psz_code, LANGUAGE_DEFAULT ) ) dvdnav_audio_language_select( p_sys->dvdnav, (char*)LANGUAGE_DEFAULT ); } free( psz_code ); /* Set spu language */ psz_code = DemuxGetLanguageCode( p_demux, "sub-language" ); if( dvdnav_spu_language_select( p_sys->dvdnav, psz_code ) != DVDNAV_STATUS_OK ) { msg_Warn( p_demux, "can't set spu language to '%s' (%s)", psz_code, dvdnav_err_to_string( p_sys->dvdnav ) ); /* We try to fall back to 'en' */ if( strcmp( psz_code, LANGUAGE_DEFAULT ) ) dvdnav_spu_language_select(p_sys->dvdnav, (char*)LANGUAGE_DEFAULT ); } free( psz_code ); DemuxTitles( p_demux ); var_Create( p_demux, "dvdnav-menu", VLC_VAR_BOOL|VLC_VAR_DOINHERIT ); var_Get( p_demux, "dvdnav-menu", &val ); if( val.b_bool ) { msg_Dbg( p_demux, "trying to go to dvd menu" ); if( dvdnav_title_play( p_sys->dvdnav, 1 ) != DVDNAV_STATUS_OK ) { msg_Err( p_demux, "cannot set title (can't decrypt DVD?)" ); intf_UserFatal( p_demux, false, _("Playback failure"), _("VLC cannot set the DVD's title. It possibly " "cannot decrypt the entire disk.") ); dvdnav_close( p_sys->dvdnav ); free( p_sys ); return VLC_EGENERIC; } if( dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Title ) != DVDNAV_STATUS_OK ) { /* Try going to menu root */ if( dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Root ) != DVDNAV_STATUS_OK ) msg_Warn( p_demux, "cannot go to dvd menu" ); } } var_Create( p_demux, "dvdnav-angle", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT ); var_Get( p_demux, "dvdnav-angle", &val ); i_angle = val.i_int > 0 ? val.i_int : 1; /* Update default_pts to a suitable value for dvdnav access */ var_Create( p_demux, "dvdnav-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT ); /* FIXME hack hack hack hack FIXME */ /* Get p_input and create variable */ p_sys->p_input = vlc_object_find( p_demux, VLC_OBJECT_INPUT, FIND_PARENT ); var_Create( p_sys->p_input, "x-start", VLC_VAR_INTEGER ); var_Create( p_sys->p_input, "y-start", VLC_VAR_INTEGER ); var_Create( p_sys->p_input, "x-end", VLC_VAR_INTEGER ); var_Create( p_sys->p_input, "y-end", VLC_VAR_INTEGER ); var_Create( p_sys->p_input, "color", VLC_VAR_ADDRESS ); var_Create( p_sys->p_input, "menu-palette", VLC_VAR_ADDRESS ); var_Create( p_sys->p_input, "highlight", VLC_VAR_BOOL ); var_Create( p_sys->p_input, "highlight-mutex", VLC_VAR_MUTEX ); /* Now create our event thread catcher */ p_sys->p_ev = vlc_object_create( p_demux, sizeof( event_thread_t ) ); p_sys->p_ev->p_demux = p_demux; vlc_thread_create( p_sys->p_ev, "dvdnav event thread handler", EventThread, VLC_THREAD_PRIORITY_LOW, false ); return VLC_SUCCESS;}/***************************************************************************** * Close: *****************************************************************************/static void Close( vlc_object_t *p_this ){ demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys = p_demux->p_sys; int i; /* stop the event handler */ vlc_object_kill( p_sys->p_ev ); vlc_thread_join( p_sys->p_ev ); vlc_object_release( p_sys->p_ev ); var_Destroy( p_sys->p_input, "highlight-mutex" ); var_Destroy( p_sys->p_input, "highlight" ); var_Destroy( p_sys->p_input, "x-start" ); var_Destroy( p_sys->p_input, "x-end" ); var_Destroy( p_sys->p_input, "y-start" ); var_Destroy( p_sys->p_input, "y-end" ); var_Destroy( p_sys->p_input, "color" ); var_Destroy( p_sys->p_input, "menu-palette" ); vlc_object_release( p_sys->p_input ); for( i = 0; i < PS_TK_COUNT; i++ ) { ps_track_t *tk = &p_sys->tk[i]; if( tk->b_seen ) { es_format_Clean( &tk->fmt ); if( tk->es ) es_out_Del( p_demux->out, tk->es ); } } dvdnav_close( p_sys->dvdnav ); free( p_sys );}/***************************************************************************** * Control: *****************************************************************************/static int Control( demux_t *p_demux, int i_query, va_list args ){ demux_sys_t *p_sys = p_demux->p_sys; double f, *pf; bool *pb; int64_t *pi64; input_title_t ***ppp_title; int *pi_int; int i; switch( i_query ) { case DEMUX_SET_POSITION: case DEMUX_GET_POSITION: case DEMUX_GET_TIME: case DEMUX_GET_LENGTH: { uint32_t pos, len; if( dvdnav_get_position( p_sys->dvdnav, &pos, &len ) != DVDNAV_STATUS_OK || len == 0 ) { return VLC_EGENERIC; } if( i_query == DEMUX_GET_POSITION ) { pf = (double*)va_arg( args, double* ); *pf = (double)pos / (double)len; return VLC_SUCCESS; } else if( i_query == DEMUX_SET_POSITION ) { f = (double)va_arg( args, double ); pos = f * len; if( dvdnav_sector_search( p_sys->dvdnav, pos, SEEK_SET ) == DVDNAV_STATUS_OK ) { return VLC_SUCCESS; } } else if( i_query == DEMUX_GET_TIME ) { pi64 = (int64_t*)va_arg( args, int64_t * ); if( p_sys->i_pgc_length > 0 ) { *pi64 = p_sys->i_pgc_length * pos / len; return VLC_SUCCESS; } } else if( i_query == DEMUX_GET_LENGTH ) { pi64 = (int64_t*)va_arg( args, int64_t * ); if( p_sys->i_pgc_length > 0 ) { *pi64 = (int64_t)p_sys->i_pgc_length; return VLC_SUCCESS; } } return VLC_EGENERIC; } /* Special for access_demux */ case DEMUX_CAN_PAUSE: case DEMUX_CAN_SEEK: case DEMUX_CAN_CONTROL_PACE: /* TODO */ pb = (bool*)va_arg( args, bool * ); *pb = true; return VLC_SUCCESS; case DEMUX_SET_PAUSE_STATE: return VLC_SUCCESS; case DEMUX_GET_TITLE_INFO: ppp_title = (input_title_t***)va_arg( args, input_title_t*** ); pi_int = (int*)va_arg( args, int* ); *((int*)va_arg( args, int* )) = 0; /* Title offset */ *((int*)va_arg( args, int* )) = 1; /* Chapter offset */ /* Duplicate title infos */ *pi_int = p_sys->i_title; *ppp_title = malloc( sizeof( input_title_t ** ) * p_sys->i_title ); for( i = 0; i < p_sys->i_title; i++ ) { (*ppp_title)[i] = vlc_input_title_Duplicate( p_sys->title[i] ); } return VLC_SUCCESS; case DEMUX_SET_TITLE: i = (int)va_arg( args, int ); if( ( i == 0 && dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Root ) != DVDNAV_STATUS_OK ) || ( i != 0 && dvdnav_title_play( p_sys->dvdnav, i ) != DVDNAV_STATUS_OK ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -