📄 dvdread.c
字号:
/***************************************************************************** * dvdread.c : DvdRead input module for vlc ***************************************************************************** * Copyright (C) 2001-2006 the VideoLAN team * $Id: 3e51aadc00c43bf6fa9aa761dcba7b2b30e1a0cc $ * * Authors: Stéphane Borel <stef@via.ecp.fr> * Gildas Bazin <gbazin@videolan.org> * * 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_charset.h>#include <vlc_interface.h>#include <vlc_iso_lang.h>#include "../demux/ps.h"#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>#ifdef HAVE_DVDREAD_DVD_READER_H #include <dvdread/dvd_reader.h> #include <dvdread/ifo_types.h> #include <dvdread/ifo_read.h> #include <dvdread/nav_read.h> #include <dvdread/nav_print.h>#else #include <libdvdread/dvd_reader.h> #include <libdvdread/ifo_types.h> #include <libdvdread/ifo_read.h> #include <libdvdread/nav_read.h> #include <libdvdread/nav_print.h>#endif#include <assert.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 CSSMETHOD_TEXT N_("Method used by libdvdcss for decryption")#define CSSMETHOD_LONGTEXT N_( \ "Set the method used by libdvdcss for key decryption.\n" \ "title: decrypted title key is guessed from the encrypted sectors of " \ "the stream. Thus it should work with a file as well as the " \ "DVD device. But it sometimes takes much time to decrypt a title " \ "key and may even fail. With this method, the key is only checked "\ "at the beginning of each title, so it won't work if the key " \ "changes in the middle of a title.\n" \ "disc: the disc key is first cracked, then all title keys can be " \ "decrypted instantly, which allows us to check them often.\n" \ "key: the same as \"disc\" if you don't have a file with player keys " \ "at compilation time. If you do, the decryption of the disc key " \ "will be faster with this method. It is the one that was used by " \ "libcss.\n" \ "The default method is: key.")static const char *const psz_css_list[] = { "title", "disc", "key" };static const char *const psz_css_list_text[] = { N_("title"), N_("Disc"), N_("Key") };static int Open ( vlc_object_t * );static void Close( vlc_object_t * );vlc_module_begin(); set_shortname( N_("DVD without menus") ); set_description( N_("DVDRead Input (DVD without menu support)") ); set_category( CAT_INPUT ); set_subcategory( SUBCAT_INPUT_ACCESS ); add_integer( "dvdread-angle", 1, NULL, ANGLE_TEXT, ANGLE_LONGTEXT, false ); add_integer( "dvdread-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, true ); add_string( "dvdread-css-method", NULL, NULL, CSSMETHOD_TEXT, CSSMETHOD_LONGTEXT, true ); change_string_list( psz_css_list, psz_css_list_text, 0 ); set_capability( "access_demux", 0 ); add_shortcut( "dvd" ); add_shortcut( "dvdread" ); add_shortcut( "dvdsimple" ); set_callbacks( Open, Close );vlc_module_end();/* how many blocks DVDRead will read in each loop */#define DVD_BLOCK_READ_ONCE 4/***************************************************************************** * Local prototypes *****************************************************************************/struct demux_sys_t{ /* DVDRead state */ dvd_reader_t *p_dvdread; dvd_file_t *p_title; ifo_handle_t *p_vmg_file; ifo_handle_t *p_vts_file; int i_title; int i_chapter, i_chapters; int i_angle, i_angles; tt_srpt_t *p_tt_srpt; pgc_t *p_cur_pgc; dsi_t dsi_pack; int i_ttn; int i_pack_len; int i_cur_block; int i_next_vobu; int i_mux_rate; /* Current title start/end blocks */ int i_title_start_block; int i_title_end_block; int i_title_blocks; int i_title_offset; mtime_t i_title_cur_time; int i_title_start_cell; int i_title_end_cell; int i_cur_cell; int i_next_cell; mtime_t i_cell_cur_time; mtime_t i_cell_duration; /* Track */ ps_track_t tk[PS_TK_COUNT]; int i_titles; input_title_t **titles; /* Video */ int i_aspect; /* SPU */ uint32_t clut[16];};static int Control ( demux_t *, int, va_list );static int Demux ( demux_t * );static int DemuxBlock( demux_t *, uint8_t *, int );static void DemuxTitles( demux_t *, int * );static void ESNew( demux_t *, int, int );static int DvdReadSetArea ( demux_t *, int, int, int );static void DvdReadSeek ( demux_t *, int );static void DvdReadHandleDSI( demux_t *, uint8_t * );static void DvdReadFindCell ( demux_t * );/***************************************************************************** * Open: *****************************************************************************/static int Open( vlc_object_t *p_this ){ demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; char *psz_name; char *psz_dvdcss_env; dvd_reader_t *p_dvdread; ifo_handle_t *p_vmg_file; 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 /* Override environment variable DVDCSS_METHOD with config option */ psz_dvdcss_env = config_GetPsz( p_demux, "dvdread-css-method" ); if( psz_dvdcss_env && *psz_dvdcss_env )#ifdef HAVE_SETENV setenv( "DVDCSS_METHOD", psz_dvdcss_env, 1 );#else { /* FIXME: this create a small memory leak */ char *psz_env; psz_env = malloc( strlen("DVDCSS_METHOD=") + strlen( psz_dvdcss_env ) + 1 ); if( !psz_env ) { free( psz_dvdcss_env ); return VLC_ENOMEM; } sprintf( psz_env, "%s%s", "DVDCSS_METHOD=", psz_dvdcss_env ); putenv( psz_env ); }#endif free( psz_dvdcss_env ); /* Open dvdread */ if( !(p_dvdread = DVDOpen( psz_name )) ) { msg_Err( p_demux, "DVDRead cannot open source: %s", psz_name ); intf_UserFatal( p_demux, false, _("Playback failure"), _("DVDRead could not open the disk \"%s\"."), psz_name ); free( psz_name ); return VLC_EGENERIC; } free( psz_name ); /* Ifo allocation & initialisation */ if( !( p_vmg_file = ifoOpen( p_dvdread, 0 ) ) ) { msg_Warn( p_demux, "cannot open VMG info" ); return VLC_EGENERIC; } msg_Dbg( p_demux, "VMG opened" ); /* Fill p_demux field */ DEMUX_INIT_COMMON(); p_sys = p_demux->p_sys; ps_track_init( p_sys->tk ); p_sys->i_aspect = -1; p_sys->i_title_cur_time = (mtime_t) 0; p_sys->i_cell_cur_time = (mtime_t) 0; p_sys->i_cell_duration = (mtime_t) 0; p_sys->p_dvdread = p_dvdread; p_sys->p_vmg_file = p_vmg_file; p_sys->p_title = NULL; p_sys->p_vts_file = NULL; p_sys->i_title = p_sys->i_chapter = -1; p_sys->i_mux_rate = 0; var_Create( p_demux, "dvdread-angle", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT ); var_Get( p_demux, "dvdread-angle", &val ); p_sys->i_angle = val.i_int > 0 ? val.i_int : 1; DemuxTitles( p_demux, &p_sys->i_angle ); if( DvdReadSetArea( p_demux, 0, 0, p_sys->i_angle ) != VLC_SUCCESS ) { Close( p_this ); msg_Err( p_demux, "DvdReadSetArea(0,0,%i) failed (can't decrypt DVD?)", p_sys->i_angle ); return VLC_EGENERIC; } /* Update default_pts to a suitable value for dvdread access */ var_Create( p_demux, "dvdread-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT ); 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; 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 ); } } /* Close libdvdread */ if( p_sys->p_title ) DVDCloseFile( p_sys->p_title ); if( p_sys->p_vts_file ) ifoClose( p_sys->p_vts_file ); if( p_sys->p_vmg_file ) ifoClose( p_sys->p_vmg_file ); DVDClose( p_sys->p_dvdread ); free( p_sys );}static int64_t dvdtime_to_time( dvd_time_t *dtime, uint8_t still_time ){/* Macro to convert Binary Coded Decimal to Decimal */#define BCD2D(__x__) (((__x__ & 0xf0) >> 4) * 10 + (__x__ & 0x0f)) double f_fps, f_ms; int64_t i_micro_second = 0; if (still_time == 0 || still_time == 0xFF) { i_micro_second += (int64_t)(BCD2D(dtime->hour)) * 60 * 60 * 1000000; i_micro_second += (int64_t)(BCD2D(dtime->minute)) * 60 * 1000000; i_micro_second += (int64_t)(BCD2D(dtime->second)) * 1000000; switch((dtime->frame_u & 0xc0) >> 6) { case 1: f_fps = 25.0; break; case 3: f_fps = 29.97; break; default: f_fps = 2500.0; break; } f_ms = BCD2D(dtime->frame_u&0x3f) * 1000.0 / f_fps; i_micro_second += (int64_t)(f_ms * 1000.0); } else { i_micro_second = still_time; i_micro_second = (int64_t)((double)i_micro_second * 1000000.0); } return i_micro_second;}/***************************************************************************** * 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_GET_POSITION: { pf = (double*) va_arg( args, double* ); if( p_sys->i_title_blocks > 0 ) *pf = (double)p_sys->i_title_offset / p_sys->i_title_blocks; else *pf = 0.0; return VLC_SUCCESS; } case DEMUX_SET_POSITION: { f = (double)va_arg( args, double ); DvdReadSeek( p_demux, f * p_sys->i_title_blocks ); return VLC_SUCCESS; } case DEMUX_GET_TIME: pi64 = (int64_t*)va_arg( args, int64_t * ); if( p_demux->info.i_title >= 0 && p_demux->info.i_title < p_sys->i_titles ) { *pi64 = (int64_t) dvdtime_to_time( &p_sys->p_cur_pgc->playback_time, 0 ) / p_sys->i_title_blocks * p_sys->i_title_offset; return VLC_SUCCESS; } *pi64 = 0; return VLC_EGENERIC; case DEMUX_GET_LENGTH: pi64 = (int64_t*)va_arg( args, int64_t * ); if( p_demux->info.i_title >= 0 && p_demux->info.i_title < p_sys->i_titles ) { *pi64 = (int64_t)dvdtime_to_time( &p_sys->p_cur_pgc->playback_time, 0 ); return VLC_SUCCESS; } *pi64 = 0; 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* )) = 1; /* Title offset */ *((int*)va_arg( args, int* )) = 1; /* Chapter offset */ /* Duplicate title infos */ *pi_int = p_sys->i_titles; *ppp_title = malloc( sizeof(input_title_t **) * p_sys->i_titles ); for( i = 0; i < p_sys->i_titles; i++ ) { (*ppp_title)[i] = vlc_input_title_Duplicate(p_sys->titles[i]); } return VLC_SUCCESS; case DEMUX_SET_TITLE: i = (int)va_arg( args, int ); if( DvdReadSetArea( p_demux, i, 0, -1 ) != VLC_SUCCESS ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -