X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=plugins%2Fdvd%2Finput_dvd.c;h=773852b60c8366b8975c2804f70832dddd6701c4;hb=003c2ab30097c1406da51290eccab8863dfe5101;hp=e9e034cf28c47ac6dfdba35dfa4521fc6f22b3c2;hpb=ca90f850b7db02523d44b133fdd0ac43d4996ff9;p=vlc diff --git a/plugins/dvd/input_dvd.c b/plugins/dvd/input_dvd.c index e9e034cf28..773852b60c 100644 --- a/plugins/dvd/input_dvd.c +++ b/plugins/dvd/input_dvd.c @@ -5,12 +5,12 @@ * especially the 2048 bytes logical block size. * It depends on: * -input_netlist used to read packets + * -libdvdcss for access and unscrambling * -dvd_ifo for ifo parsing and analyse - * -dvd_css for unscrambling * -dvd_udf to find files ***************************************************************************** * Copyright (C) 1998-2001 VideoLAN - * $Id: input_dvd.c,v 1.56 2001/05/07 03:14:09 stef Exp $ + * $Id: input_dvd.c,v 1.106 2001/12/10 04:53:10 sam Exp $ * * Author: Stéphane Borel * @@ -29,233 +29,91 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************/ +#define MODULE_NAME dvd +#include "modules_inner.h" + /***************************************************************************** * Preamble *****************************************************************************/ #include "defs.h" -#ifdef HAVE_CSS -#define MODULE_NAME dvd -#else /* HAVE_CSS */ -#define MODULE_NAME dvdnocss -#endif /* HAVE_CSS */ -#include "modules_inner.h" - #include #include -#include -#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif #include #include -#include - #include +#include + #ifdef STRNCASECMP_IN_STRINGS_H # include #endif -#include -#include "config.h" +#if defined( WIN32 ) +# include /* read() */ +#else +# include /* struct iovec */ +#endif + +#ifdef GOD_DAMN_DMCA +# include "dummy_dvdcss.h" +#else +# include +#endif + #include "common.h" +#include "intf_msg.h" #include "threads.h" #include "mtime.h" +#include "iso_lang.h" #include "tests.h" -#include "intf_msg.h" - -#include "main.h" +#if defined( WIN32 ) +# include "input_iovec.h" +#endif #include "stream_control.h" #include "input_ext-intf.h" #include "input_ext-dec.h" +#include "input_ext-plugins.h" -#include "input.h" - -#include "dvd_netlist.h" -#include "dvd_ifo.h" -#include "dvd_css.h" #include "input_dvd.h" -#include "mpeg_system.h" +#include "dvd_ifo.h" +#include "dvd_summary.h" #include "debug.h" #include "modules.h" +#include "modules_export.h" -/***************************************************************************** - * Local tables - *****************************************************************************/ -static struct -{ - char p_code[3]; - char p_lang_long[20]; -} +/* how many blocks DVDRead will read in each loop */ +#define DVD_BLOCK_READ_ONCE 64 +#define DVD_DATA_READ_ONCE (4 * DVD_BLOCK_READ_ONCE) -lang_tbl[] = -{ - /* The ISO 639 language codes. - * Language names with * prefix are not spelled in their own language - */ - { " ", "Not Specified" }, - { "aa", "*Afar" }, - { "ab", "*Abkhazian" }, - { "af", "*Afrikaans" }, - { "am", "*Amharic" }, - { "ar", "*Arabic" }, - { "as", "*Assamese" }, - { "ay", "*Aymara" }, - { "az", "*Azerbaijani" }, - { "ba", "*Bashkir" }, - { "be", "*Byelorussian" }, - { "bg", "*Bulgarian" }, - { "bh", "*Bihari" }, - { "bi", "*Bislama" }, - { "bn", "*Bengali; Bangla" }, - { "bo", "*Tibetan" }, - { "br", "*Breton" }, - { "ca", "*Catalan" }, - { "co", "*Corsican" }, - { "cs", "*Czech(Ceske)" }, - { "cy", "*Welsh" }, - { "da", "Dansk" }, - { "de", "Deutsch" }, - { "dz", "*Bhutani" }, - { "el", "*Greek" }, - { "en", "English" }, - { "eo", "*Esperanto" }, - { "es", "Espanol" }, - { "et", "*Estonian" }, - { "eu", "*Basque" }, - { "fa", "*Persian" }, - { "fi", "Suomi" }, - { "fj", "*Fiji" }, - { "fo", "*Faroese" }, - { "fr", "Francais" }, - { "fy", "*Frisian" }, - { "ga", "*Irish" }, - { "gd", "*Scots Gaelic" }, - { "gl", "*Galician" }, - { "gn", "*Guarani" }, - { "gu", "*Gujarati" }, - { "ha", "*Hausa" }, - { "he", "*Hebrew" }, /* formerly iw */ - { "hi", "*Hindi" }, - { "hr", "Hrvatski" }, /* Croatian */ - { "hu", "Magyar" }, - { "hy", "*Armenian" }, - { "ia", "*Interlingua" }, - { "id", "*Indonesian" }, /* formerly in */ - { "ie", "*Interlingue" }, - { "ik", "*Inupiak" }, - { "in", "*Indonesian" }, /* replaced by id */ - { "is", "Islenska" }, - { "it", "Italiano" }, - { "iu", "*Inuktitut" }, - { "iw", "*Hebrew" }, /* replaced by he */ - { "ja", "*Japanese" }, - { "ji", "*Yiddish" }, /* replaced by yi */ - { "jw", "*Javanese" }, - { "ka", "*Georgian" }, - { "kk", "*Kazakh" }, - { "kl", "*Greenlandic" }, - { "km", "*Cambodian" }, - { "kn", "*Kannada" }, - { "ko", "*Korean" }, - { "ks", "*Kashmiri" }, - { "ku", "*Kurdish" }, - { "ky", "*Kirghiz" }, - { "la", "*Latin" }, - { "ln", "*Lingala" }, - { "lo", "*Laothian" }, - { "lt", "*Lithuanian" }, - { "lv", "*Latvian, Lettish" }, - { "mg", "*Malagasy" }, - { "mi", "*Maori" }, - { "mk", "*Macedonian" }, - { "ml", "*Malayalam" }, - { "mn", "*Mongolian" }, - { "mo", "*Moldavian" }, - { "mr", "*Marathi" }, - { "ms", "*Malay" }, - { "mt", "*Maltese" }, - { "my", "*Burmese" }, - { "na", "*Nauru" }, - { "ne", "*Nepali" }, - { "nl", "Nederlands" }, - { "no", "Norsk" }, - { "oc", "*Occitan" }, - { "om", "*(Afan) Oromo" }, - { "or", "*Oriya" }, - { "pa", "*Punjabi" }, - { "pl", "*Polish" }, - { "ps", "*Pashto, Pushto" }, - { "pt", "Portugues" }, - { "qu", "*Quechua" }, - { "rm", "*Rhaeto-Romance" }, - { "rn", "*Kirundi" }, - { "ro", "*Romanian" }, - { "ru", "*Russian" }, - { "rw", "*Kinyarwanda" }, - { "sa", "*Sanskrit" }, - { "sd", "*Sindhi" }, - { "sg", "*Sangho" }, - { "sh", "*Serbo-Croatian" }, - { "si", "*Sinhalese" }, - { "sk", "*Slovak" }, - { "sl", "*Slovenian" }, - { "sm", "*Samoan" }, - { "sn", "*Shona" }, - { "so", "*Somali" }, - { "sq", "*Albanian" }, - { "sr", "*Serbian" }, - { "ss", "*Siswati" }, - { "st", "*Sesotho" }, - { "su", "*Sundanese" }, - { "sv", "Svenska" }, - { "sw", "*Swahili" }, - { "ta", "*Tamil" }, - { "te", "*Telugu" }, - { "tg", "*Tajik" }, - { "th", "*Thai" }, - { "ti", "*Tigrinya" }, - { "tk", "*Turkmen" }, - { "tl", "*Tagalog" }, - { "tn", "*Setswana" }, - { "to", "*Tonga" }, - { "tr", "*Turkish" }, - { "ts", "*Tsonga" }, - { "tt", "*Tatar" }, - { "tw", "*Twi" }, - { "ug", "*Uighur" }, - { "uk", "*Ukrainian" }, - { "ur", "*Urdu" }, - { "uz", "*Uzbek" }, - { "vi", "*Vietnamese" }, - { "vo", "*Volapuk" }, - { "wo", "*Wolof" }, - { "xh", "*Xhosa" }, - { "yi", "*Yiddish" }, /* formerly ji */ - { "yo", "*Yoruba" }, - { "za", "*Zhuang" }, - { "zh", "*Chinese" }, - { "zu", "*Zulu" }, - { "\0", "" } -}; +/* Size of netlist */ +#define DVD_NETLIST_SIZE 256 /***************************************************************************** * Local prototypes *****************************************************************************/ /* called from outside */ -static int DVDProbe ( probedata_t *p_data ); -static void DVDInit ( struct input_thread_s * ); -static void DVDEnd ( struct input_thread_s * ); -static int DVDSetArea ( struct input_thread_s *, struct input_area_s * ); -static int DVDRead ( struct input_thread_s *, data_packet_t ** ); -static void DVDSeek ( struct input_thread_s *, off_t ); -static int DVDRewind ( struct input_thread_s * ); +static int DVDProbe ( probedata_t *p_data ); +static void DVDInit ( struct input_thread_s * ); +static void DVDEnd ( struct input_thread_s * ); +static void DVDOpen ( struct input_thread_s * ); +static void DVDClose ( struct input_thread_s * ); +static int DVDSetArea ( struct input_thread_s *, struct input_area_s * ); +static int DVDSetProgram ( struct input_thread_s *, pgrm_descriptor_t * ); +static int DVDRead ( struct input_thread_s *, data_packet_t ** ); +static void DVDSeek ( struct input_thread_s *, off_t ); +static int DVDRewind ( struct input_thread_s * ); /* called only inside */ -static char * Language( u16 ); static int DVDChooseAngle( thread_dvd_data_t * ); static int DVDFindCell( thread_dvd_data_t * ); static int DVDFindSector( thread_dvd_data_t * ); @@ -270,41 +128,23 @@ void _M( input_getfunctions )( function_list_t * p_function_list ) #define input p_function_list->functions.input p_function_list->pf_probe = DVDProbe; input.pf_init = DVDInit; - input.pf_open = input_FileOpen; - input.pf_close = input_FileClose; + input.pf_open = DVDOpen; + input.pf_close = DVDClose; input.pf_end = DVDEnd; + input.pf_init_bit_stream = InitBitstream; input.pf_read = DVDRead; input.pf_set_area = DVDSetArea; + input.pf_set_program = DVDSetProgram; input.pf_demux = input_DemuxPS; - input.pf_new_packet = DVDNewPacket; - input.pf_new_pes = DVDNewPES; - input.pf_delete_packet = DVDDeletePacket; - input.pf_delete_pes = DVDDeletePES; + input.pf_new_packet = input_NetlistNewPacket; + input.pf_new_pes = input_NetlistNewPES; + input.pf_delete_packet = input_NetlistDeletePacket; + input.pf_delete_pes = input_NetlistDeletePES; input.pf_rewind = DVDRewind; input.pf_seek = DVDSeek; #undef input } -/* - * Local tools to decode some data in ifo - */ - -/***************************************************************************** - * Language: gives the long language name from the two-letters ISO-639 code - *****************************************************************************/ -static char * Language( u16 i_code ) -{ - int i = 0; - - while( memcmp( lang_tbl[i].p_code, &i_code, 2 ) && - lang_tbl[i].p_lang_long[0] ) - { - i++; - } - - return lang_tbl[i].p_lang_long; -} - /* * Data reading functions */ @@ -317,36 +157,20 @@ static int DVDProbe( probedata_t *p_data ) input_thread_t * p_input = (input_thread_t *)p_data; char * psz_name = p_input->p_source; - int i_handle; int i_score = 5; if( TestMethod( INPUT_METHOD_VAR, "dvd" ) ) { -#ifdef HAVE_CSS return( 999 ); -#else /* HAVE_CSS */ - return( 998 ); -#endif /* HAVE_CSS */ } if( ( strlen(psz_name) > 4 ) && !strncasecmp( psz_name, "dvd:", 4 ) ) { /* If the user specified "dvd:" then it's probably a DVD */ -#ifdef HAVE_CSS i_score = 100; -#else /* HAVE_CSS */ - i_score = 90; -#endif /* HAVE_CSS */ psz_name += 4; } - i_handle = open( psz_name, 0 ); - if( i_handle == -1 ) - { - return( 0 ); - } - close( i_handle ); - return( i_score ); } @@ -361,9 +185,6 @@ static void DVDInit( input_thread_t * p_input ) int i_chapter; int i; - /* I don't want DVDs to start playing immediately */ -// p_input->stream.i_new_status = PAUSE_S; - p_dvd = malloc( sizeof(thread_dvd_data_t) ); if( p_dvd == NULL ) { @@ -375,36 +196,32 @@ static void DVDInit( input_thread_t * p_input ) p_input->p_plugin_data = (void *)p_dvd; p_input->p_method_data = NULL; - p_dvd->i_fd = p_input->i_handle; - - /* reading several block once seems to cause lock-up - * when using input_ToggleES - * who wrote thez damn buggy piece of shit ??? --stef */ - p_dvd->i_block_once = 1;//32; - p_input->i_read_once = 8;//128; - - i = CSSTest( p_input->i_handle ); + p_dvd->dvdhandle = (dvdcss_handle) p_input->p_handle; - if( i < 0 ) + if( dvdcss_seek( p_dvd->dvdhandle, 0, DVDCSS_NOFLAGS ) < 0 ) { - free( p_dvd ); + intf_ErrMsg( "dvd error: %s", dvdcss_error( p_dvd->dvdhandle ) ); p_input->b_error = 1; return; } - p_dvd->b_encrypted = i; - - lseek( p_input->i_handle, 0, SEEK_SET ); + /* We read DVD_BLOCK_READ_ONCE in each loop, so the input will receive + * DVD_DATA_READ_ONCE at most */ + p_dvd->i_block_once = DVD_BLOCK_READ_ONCE; + /* this value mustn't be modifed */ + p_input->i_read_once = DVD_DATA_READ_ONCE; /* Reading structures initialisation */ - p_input->p_method_data = - DVDNetlistInit( 2048, 4096, 2048, DVD_LB_SIZE, p_dvd->i_block_once ); + input_NetlistInit( p_input, DVD_NETLIST_SIZE, 2 * DVD_NETLIST_SIZE, + DVD_NETLIST_SIZE, DVD_LB_SIZE, p_dvd->i_block_once ); intf_WarnMsg( 2, "dvd info: netlist initialized" ); /* Ifo allocation & initialisation */ if( IfoCreate( p_dvd ) < 0 ) { intf_ErrMsg( "dvd error: allcation error in ifo" ); + dvdcss_close( p_dvd->dvdhandle ); + free( p_dvd ); p_input->b_error = 1; return; } @@ -412,46 +229,19 @@ static void DVDInit( input_thread_t * p_input ) if( IfoInit( p_dvd->p_ifo ) < 0 ) { intf_ErrMsg( "dvd error: fatal failure in ifo" ); + IfoDestroy( p_dvd->p_ifo ); + dvdcss_close( p_dvd->dvdhandle ); free( p_dvd ); p_input->b_error = 1; return; } - /* CSS initialisation */ - if( p_dvd->b_encrypted ) - { - p_dvd->p_css = malloc( sizeof(css_t) ); - if( p_dvd->p_css == NULL ) - { - intf_ErrMsg( "dvd error: couldn't create css structure" ); - free( p_dvd ); - p_input->b_error = 1; - return; - } - - p_dvd->p_css->i_agid = 0; - - if( CSSInit( p_input->i_handle, p_dvd->p_css ) < 0 ) - { - intf_ErrMsg( "dvd error: fatal failure in css" ); - free( p_dvd->p_css ); - free( p_dvd ); - p_input->b_error = 1; - return; - } - - intf_WarnMsg( 2, "dvd info: css initialized" ); - } - /* Set stream and area data */ vlc_mutex_lock( &p_input->stream.stream_lock ); /* Initialize ES structures */ input_InitStream( p_input, sizeof( stream_ps_data_t ) ); - /* disc input method */ - p_input->stream.i_method = INPUT_METHOD_DVD; - #define title_inf p_dvd->p_ifo->vmg.title_inf intf_WarnMsg( 2, "dvd info: number of titles: %d", title_inf.i_title_nb ); @@ -480,8 +270,8 @@ static void DVDInit( input_thread_t * p_input ) area[i]->i_angle = 1; /* Offset to vts_i_0.ifo */ - area[i]->i_plugin_data = p_dvd->p_ifo->i_off + - ( title_inf.p_attr[i-1].i_start_sector * DVD_LB_SIZE ); + area[i]->i_plugin_data = p_dvd->p_ifo->i_start + + title_inf.p_attr[i-1].i_start_sector; } #undef area @@ -505,65 +295,136 @@ static void DVDInit( input_thread_t * p_input ) p_area = p_input->stream.pp_areas[i_title]; - vlc_mutex_unlock( &p_input->stream.stream_lock ); - /* set title, chapter, audio and subpic */ DVDSetArea( p_input, p_area ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); + return; } +/***************************************************************************** + * DVDOpen: open dvd + *****************************************************************************/ +static void DVDOpen( struct input_thread_s *p_input ) +{ + dvdcss_handle dvdhandle; + char * psz_parser; + char * psz_device; + + vlc_mutex_lock( &p_input->stream.stream_lock ); + + /* If we are here we can control the pace... */ + p_input->stream.b_pace_control = 1; + + p_input->stream.b_seekable = 1; + p_input->stream.p_selected_area->i_size = 0; + + p_input->stream.p_selected_area->i_tell = 0; + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + /* Parse input string : dvd:device[:rawdevice] */ + if( strlen( p_input->p_source ) > 4 + && !strncasecmp( p_input->p_source, "dvd:", 4 ) ) + { + psz_parser = psz_device = p_input->p_source + 4; + } + else + { + psz_parser = psz_device = p_input->p_source; + } + + while( *psz_parser && *psz_parser != '@' ) + { + psz_parser++; + } + + if( *psz_parser == '@' ) + { + /* Found raw device */ + *psz_parser = '\0'; + psz_parser++; + + main_PutPszVariable( "DVDCSS_RAW_DEVICE", psz_parser ); + } + + intf_WarnMsg( 2, "input: dvd=%s raw=%s", psz_device, psz_parser ); + + dvdhandle = dvdcss_open( psz_device ); + + if( dvdhandle == NULL ) + { + intf_ErrMsg( "dvd error: dvdcss can't open device" ); + p_input->b_error = 1; + return; + } + + p_input->p_handle = (void *) dvdhandle; +} + +/***************************************************************************** + * DVDClose: close dvd + *****************************************************************************/ +static void DVDClose( struct input_thread_s *p_input ) +{ + /* Clean up libdvdcss */ + dvdcss_close( (dvdcss_handle) p_input->p_handle ); +} + /***************************************************************************** * DVDEnd: frees unused data *****************************************************************************/ static void DVDEnd( input_thread_t * p_input ) { thread_dvd_data_t * p_dvd; - dvd_netlist_t * p_netlist; p_dvd = (thread_dvd_data_t*)p_input->p_plugin_data; - p_netlist = (dvd_netlist_t *)p_input->p_method_data; - - if( p_dvd->b_encrypted ) - { - free( p_dvd->p_css ); - } IfoDestroy( p_dvd->p_ifo ); + free( p_dvd ); - DVDNetlistEnd( p_netlist ); + + input_NetlistEnd( p_input ); +} + +/***************************************************************************** + * DVDSetProgram: Does nothing, a DVD is mono-program + *****************************************************************************/ +static int DVDSetProgram( input_thread_t * p_input, + pgrm_descriptor_t * p_program ) +{ + return 0; } /***************************************************************************** * DVDSetArea: initialize input data for title x, chapter y. - * It should be called for each user navigation request, and to change - * audio or sub-picture streams. - * --- + * It should be called for each user navigation request. + ***************************************************************************** * Take care that i_title starts from 0 (vmg) and i_chapter start from 1. - * i_audio, i_spu start from 1 ; 0 means off. - * A negative value for an argument means it does not change + * Note that you have to take the lock before entering here. *****************************************************************************/ static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area ) { thread_dvd_data_t * p_dvd; es_descriptor_t * p_es; + u16 i_id; + int i_vts_title; + int i_audio_nb = 0; + int i_spu_nb = 0; int i_audio; int i_spu; - u16 i_id; - u8 i_ac3; - u8 i_mpeg; - u8 i_lpcm; - u8 i_sub_pic; - u8 i; - int j; - boolean_t b_last; + int i; p_dvd = (thread_dvd_data_t*)p_input->p_plugin_data; - vlc_mutex_lock( &p_input->stream.stream_lock ); + /* we can't use the interface slider until initilization is complete */ + p_input->stream.b_seekable = 0; if( p_area != p_input->stream.p_selected_area ) { + /* Reset the Chapter position of the old title */ + p_input->stream.p_selected_area->i_part = 0; /* * We have to load all title information @@ -572,16 +433,13 @@ static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area ) p_input->stream.p_selected_area = p_input->stream.pp_areas[p_area->i_id]; -// vlc_mutex_unlock( &p_input->stream.stream_lock ); - /* title number: it is not vts nb!, * it is what appears in the interface list */ p_dvd->i_title = p_area->i_id; p_dvd->p_ifo->i_title = p_dvd->i_title; - /* uodate title environnement variable so that we don't - * loop on the same title forever */ - main_PutIntVariable( INPUT_TITLE_VAR, p_dvd->i_title + 1 ); + /* set number of chapters of current title */ + p_dvd->i_chapter_nb = p_area->i_part_nb; /* ifo vts */ if( IfoTitleSet( p_dvd->p_ifo ) < 0 ) @@ -595,42 +453,13 @@ static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area ) #define vmg p_dvd->p_ifo->vmg #define vts p_dvd->p_ifo->vts /* title position inside the selected vts */ - p_dvd->i_vts_title = - vmg.title_inf.p_attr[p_dvd->i_title-1].i_title_num; + i_vts_title = vmg.title_inf.p_attr[p_dvd->i_title-1].i_title_num; p_dvd->i_title_id = - vts.title_inf.p_title_start[p_dvd->i_vts_title-1].i_title_id; + vts.title_inf.p_title_start[i_vts_title-1].i_title_id; - intf_WarnMsg( 3, "dvd: title %d vts_title %d pgc %d", - p_dvd->i_title, - p_dvd->i_vts_title, - p_dvd->i_title_id ); + intf_WarnMsgImm( 3, "dvd: title %d vts_title %d pgc %d", + p_dvd->i_title, i_vts_title, p_dvd->i_title_id ); - /* css title key for current vts */ - if( p_dvd->b_encrypted ) - { - /* this one is vts number */ - p_dvd->p_css->i_title = - vmg.title_inf.p_attr[p_dvd->i_title-1].i_title_set_num; - p_dvd->p_css->i_title_pos = - vts.i_pos + - vts.manager_inf.i_title_vob_start_sector * DVD_LB_SIZE; - - j = CSSGetKey( p_input->i_handle, p_dvd->p_css ); - if( j < 0 ) - { - intf_ErrMsg( "dvd error: fatal error in vts css key" ); - free( p_dvd ); - p_input->b_error = 1; - return -1; - } - else if( j > 0 ) - { - intf_ErrMsg( "dvd error: css decryption unavailable" ); - free( p_dvd ); - p_input->b_error = 1; - return -1; - } - } /* * Angle management @@ -646,9 +475,9 @@ static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area ) * Set selected title start and size */ - /* title set offset */ - p_dvd->i_title_start = vts.i_pos + DVD_LB_SIZE * - (off_t)( vts.manager_inf.i_title_vob_start_sector ); + /* title set offset XXX: convert to block values */ + p_dvd->i_title_start = + vts.i_pos + vts.manager_inf.i_title_vob_start_sector; /* last video cell */ p_dvd->i_cell = 0; @@ -661,44 +490,52 @@ static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area ) p_input->b_error = 1; return -1; } - + /* temporary hack to fix size in some dvds */ if( p_dvd->i_cell >= vts.cell_inf.i_cell_nb ) { p_dvd->i_cell = vts.cell_inf.i_cell_nb - 1; } - - + p_dvd->i_sector = 0; - p_dvd->i_size = DVD_LB_SIZE * - (off_t)( vts.cell_inf.p_cell_map[p_dvd->i_cell].i_end_sector ); - intf_WarnMsg( 2, "dvd info: stream size 1: %lld @ %d", p_dvd->i_size, - vts.cell_inf.p_cell_map[p_dvd->i_cell].i_end_sector ); - + p_dvd->i_size = vts.cell_inf.p_cell_map[p_dvd->i_cell].i_end_sector; + if( DVDChapterSelect( p_dvd, 1 ) < 0 ) { intf_ErrMsg( "dvd error: can't find first chapter" ); p_input->b_error = 1; return -1; } + + /* Force libdvdcss to check its title key. + * It is only useful for title cracking method. Methods using the + * decrypted disc key are fast enough to check the key at each seek */ - p_dvd->i_size -= (off_t)( p_dvd->i_sector + 1 ) *DVD_LB_SIZE; + if( dvdcss_seek( p_dvd->dvdhandle, p_dvd->i_start, + DVDCSS_SEEK_KEY ) < 0 ) + { + intf_ErrMsg( "dvd error: %s", dvdcss_error( p_dvd->dvdhandle ) ); + return -1; + } - intf_WarnMsg( 2, "dvd info: title: %d", p_dvd->i_title ); - intf_WarnMsg( 2, "dvd info: vobstart at: %lld", p_dvd->i_start ); - intf_WarnMsg( 2, "dvd info: stream size: %lld", p_dvd->i_size ); - intf_WarnMsg( 2, "dvd info: number of chapters: %d", - vmg.title_inf.p_attr[p_dvd->i_title-1].i_chapter_nb ); - intf_WarnMsg( 2, "dvd info: number of angles: %d", p_dvd->i_angle_nb ); + p_dvd->i_size -= p_dvd->i_sector + 1; -// vlc_mutex_lock( &p_input->stream.stream_lock ); + IfoPrintTitle( p_dvd ); /* Area definition */ - p_input->stream.p_selected_area->i_start = p_dvd->i_start; - p_input->stream.p_selected_area->i_size = p_dvd->i_size; + p_input->stream.p_selected_area->i_start = LB2OFF( p_dvd->i_start ); + p_input->stream.p_selected_area->i_size = LB2OFF( p_dvd->i_size ); p_input->stream.p_selected_area->i_angle_nb = p_dvd->i_angle_nb; p_input->stream.p_selected_area->i_angle = p_dvd->i_angle; +#if 0 + /* start at the beginning of the title */ + /* FIXME: create a conf option to select whether to restart + * title or not */ + p_input->stream.p_selected_area->i_tell = 0; + p_input->stream.p_selected_area->i_part = 1; +#endif + /* * Destroy obsolete ES by reinitializing program 0 * and find all ES in title with ifo data @@ -713,159 +550,187 @@ static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area ) input_UnselectES( p_input, p_input->stream.pp_selected_es[i] ); } - input_DelProgram( p_input, p_input->stream.pp_programs[0] ); + free( p_input->stream.pp_selected_es ); + input_DelProgram( p_input, p_input->stream.p_selected_program ); p_input->stream.pp_selected_es = NULL; p_input->stream.i_selected_es_number = 0; } input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) ); + p_input->stream.p_selected_program = p_input->stream.pp_programs[0]; /* No PSM to read in DVD mode, we already have all information */ - p_input->stream.pp_programs[0]->b_is_ok = 1; - p_input->stream.pp_programs[0]->i_synchro_state = SYNCHRO_START; + p_input->stream.p_selected_program->b_is_ok = 1; p_es = NULL; /* ES 0 -> video MPEG2 */ - p_es = input_AddES( p_input, p_input->stream.pp_programs[0], 0xe0, 0 ); + IfoPrintVideo( p_dvd ); + + p_es = input_AddES( p_input, p_input->stream.p_selected_program, + 0xe0, 0 ); p_es->i_stream_id = 0xe0; p_es->i_type = MPEG2_VIDEO_ES; p_es->i_cat = VIDEO_ES; - intf_WarnMsg( 1, "dvd info: video mpeg2 stream" ); if( p_main->b_video ) { input_SelectES( p_input, p_es ); } +#define audio_status \ + vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_audio_status[i-1] /* Audio ES, in the order they appear in .ifo */ - - i_ac3 = 0x7f; - i_mpeg = 0xc0; - i_lpcm = 0x9f; - for( i = 1 ; i <= vts.manager_inf.i_audio_nb ; i++ ) { + IfoPrintAudio( p_dvd, i ); - intf_WarnMsg( 5, "dvd info: audio %d: %x %x %x %x %x %x %x %x %x %x %x %x", i, - vts.manager_inf.p_audio_attr[i-1].i_num_channels, - vts.manager_inf.p_audio_attr[i-1].i_coding_mode, - vts.manager_inf.p_audio_attr[i-1].i_multichannel_extension, - vts.manager_inf.p_audio_attr[i-1].i_type, - vts.manager_inf.p_audio_attr[i-1].i_appl_mode, - vts.manager_inf.p_audio_attr[i-1].i_foo, - vts.manager_inf.p_audio_attr[i-1].i_test, - vts.manager_inf.p_audio_attr[i-1].i_bar, - vts.manager_inf.p_audio_attr[i-1].i_quantization, - vts.manager_inf.p_audio_attr[i-1].i_sample_freq, - vts.manager_inf.p_audio_attr[i-1].i_lang_code, - vts.manager_inf.p_audio_attr[i-1].i_caption ); - - switch( vts.manager_inf.p_audio_attr[i-1].i_coding_mode ) + /* audio channel is active if first byte is 0x80 */ + if( audio_status.i_available ) { - case 0x00: /* AC3 */ - i_id = ( ( i_ac3 + i ) << 8 ) | 0xbd; - p_es = input_AddES( p_input, - p_input->stream.pp_programs[0], i_id, 0 ); - p_es->i_stream_id = 0xbd; - p_es->i_type = AC3_AUDIO_ES; - p_es->b_audio = 1; - p_es->i_cat = AUDIO_ES; - strcpy( p_es->psz_desc, Language( hton16( - vts.manager_inf.p_audio_attr[i-1].i_lang_code ) ) ); - strcat( p_es->psz_desc, " (ac3)" ); - - intf_WarnMsg( 3, "dvd info: audio stream %d %s\t(0x%x)", - i, p_es->psz_desc, i_id ); - - break; - case 0x02: - case 0x03: /* MPEG audio */ - i_id = 0xbf + i; - p_es = input_AddES( p_input, - p_input->stream.pp_programs[0], i_id, 0 ); - p_es->i_stream_id = i_id; - p_es->i_type = MPEG2_AUDIO_ES; - p_es->b_audio = 1; - p_es->i_cat = AUDIO_ES; - strcpy( p_es->psz_desc, Language( hton16( - vts.manager_inf.p_audio_attr[i-1].i_lang_code ) ) ); - strcat( p_es->psz_desc, " (mpeg)" ); - - intf_WarnMsg( 3, "dvd info: audio stream %d %s\t(0x%x)", - i, p_es->psz_desc, i_id ); - - break; - case 0x04: /* LPCM */ -#if 0 - i_id = ( ( i_lpcm + i ) << 8 ) | 0xbd; - p_es = input_AddES( p_input, - p_input->stream.pp_programs[0], i_id, 0 ); - p_es->i_stream_id = i_id; - p_es->i_type = LPCM_AUDIO_ES; - p_es->b_audio = 1; - p_es->i_cat = AUDIO_ES; - strcpy( p_es->psz_desc, Language( hton16( - vts.manager_inf.p_audio_attr[i-1].i_lang_code ) ) ); - strcat( p_es->psz_desc, " (lpcm)" ); - - intf_WarnMsg( 3, "dvd info: audio stream %d %s\t(0x%x)", - i, p_es->psz_desc, i_id ); -#else - i_id = 0; - intf_ErrMsg( "dvd warning: LPCM audio not handled yet" ); -#endif - break; - case 0x06: /* DTS */ - i_id = 0; - i_ac3--; - intf_ErrMsg( "dvd warning: DTS audio not handled yet" ); - break; - default: - i_id = 0; - intf_ErrMsg( "dvd warning: unknown audio type %.2x", - vts.manager_inf.p_audio_attr[i-1].i_coding_mode ); + i_audio_nb++; + + switch( vts.manager_inf.p_audio_attr[i-1].i_coding_mode ) + { + case 0x00: /* AC3 */ + i_id = ( ( 0x80 + audio_status.i_position ) << 8 ) | 0xbd; + p_es = input_AddES( p_input, + p_input->stream.p_selected_program, i_id, 0 ); + p_es->i_stream_id = 0xbd; + p_es->i_type = AC3_AUDIO_ES; + p_es->b_audio = 1; + p_es->i_cat = AUDIO_ES; + strcpy( p_es->psz_desc, DecodeLanguage( hton16( + vts.manager_inf.p_audio_attr[i-1].i_lang_code ) ) ); + strcat( p_es->psz_desc, " (ac3)" ); + + break; + case 0x02: + case 0x03: /* MPEG audio */ + i_id = 0xc0 + audio_status.i_position; + p_es = input_AddES( p_input, + p_input->stream.p_selected_program, i_id + , 0 ); + p_es->i_stream_id = i_id; + p_es->i_type = MPEG2_AUDIO_ES; + p_es->b_audio = 1; + p_es->i_cat = AUDIO_ES; + strcpy( p_es->psz_desc, DecodeLanguage( hton16( + vts.manager_inf.p_audio_attr[i-1].i_lang_code ) ) ); + strcat( p_es->psz_desc, " (mpeg)" ); + + break; + case 0x04: /* LPCM */ + + i_id = ( ( 0xa0 + audio_status.i_position ) << 8 ) | 0xbd; + p_es = input_AddES( p_input, + p_input->stream.p_selected_program, + i_id, 0 ); + p_es->i_stream_id = 0xbd; + p_es->i_type = LPCM_AUDIO_ES; + p_es->b_audio = 1; + p_es->i_cat = AUDIO_ES; + strcpy( p_es->psz_desc, DecodeLanguage( hton16( + vts.manager_inf.p_audio_attr[i-1].i_lang_code ) ) ); + strcat( p_es->psz_desc, " (lpcm)" ); + + break; + case 0x06: /* DTS */ + i_id = ( ( 0x88 + audio_status.i_position ) << 8 ) | 0xbd; + intf_ErrMsg( "dvd warning: DTS audio not handled yet" + "(0x%x)", i_id ); + break; + default: + i_id = 0; + intf_ErrMsg( "dvd warning: unknown audio type %.2x", + vts.manager_inf.p_audio_attr[i-1].i_coding_mode ); + } } - } - +#undef audio_status +#define spu_status \ + vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_spu_status[i-1] + /* Sub Picture ES */ - b_last = 0; - i_sub_pic = 0x20; for( i = 1 ; i <= vts.manager_inf.i_spu_nb; i++ ) { - if( !b_last ) + IfoPrintSpu( p_dvd, i ); + + if( spu_status.i_available ) { - i_id = ( i_sub_pic++ << 8 ) | 0xbd; + i_spu_nb++; + + /* there are several streams for one spu */ + if( vts.manager_inf.video_attr.i_ratio ) + { + /* 16:9 */ + switch( vts.manager_inf.video_attr.i_perm_displ ) + { + case 1: + i_id = ( ( 0x20 + spu_status.i_position_pan ) << 8 ) + | 0xbd; + break; + case 2: + i_id = ( ( 0x20 + spu_status.i_position_letter ) << 8 ) + | 0xbd; + break; + default: + i_id = ( ( 0x20 + spu_status.i_position_wide ) << 8 ) + | 0xbd; + break; + } + } + else + { + /* 4:3 */ + i_id = ( ( 0x20 + spu_status.i_position_43 ) << 8 ) + | 0xbd; + } p_es = input_AddES( p_input, - p_input->stream.pp_programs[0], i_id, 0 ); + p_input->stream.p_selected_program, + i_id, 0 ); p_es->i_stream_id = 0xbd; p_es->i_type = DVD_SPU_ES; p_es->i_cat = SPU_ES; - strcpy( p_es->psz_desc, Language( hton16( + strcpy( p_es->psz_desc, DecodeLanguage( hton16( vts.manager_inf.p_spu_attr[i-1].i_lang_code ) ) ); - intf_WarnMsg( 3, "dvd info: spu stream %d %s\t(0x%x)", - i, p_es->psz_desc, i_id ); - - /* The before the last spu has a 0x0 prefix */ - b_last = - ( vts.manager_inf.p_spu_attr[i].i_prefix == 0 ); } } - +#undef spu_status if( p_main->b_audio ) { /* For audio: first one if none or a not existing one specified */ i_audio = main_GetIntVariable( INPUT_CHANNEL_VAR, 1 ); - if( i_audio < 0 || i_audio > vts.manager_inf.i_audio_nb ) + if( i_audio < 0 || i_audio > i_audio_nb ) { main_PutIntVariable( INPUT_CHANNEL_VAR, 1 ); i_audio = 1; } - if( i_audio > 0 && vts.manager_inf.i_audio_nb > 0 ) + if( i_audio > 0 && i_audio_nb > 0 ) { - input_SelectES( p_input, p_input->stream.pp_es[i_audio] ); + if( main_GetIntVariable( AOUT_SPDIF_VAR, 0 ) || + ( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) == + REQUESTED_AC3 ) ) + { + int i_ac3 = i_audio; + while( ( p_input->stream.pp_es[i_ac3]->i_type != + AC3_AUDIO_ES ) && ( i_ac3 <= + vts.manager_inf.i_audio_nb ) ) + { + i_ac3++; + } + if( p_input->stream.pp_es[i_ac3]->i_type == AC3_AUDIO_ES ) + { + input_SelectES( p_input, + p_input->stream.pp_es[i_ac3] ); + } + } + else + { + input_SelectES( p_input, + p_input->stream.pp_es[i_audio] ); + } } } @@ -873,12 +738,12 @@ static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area ) { /* for spu, default is none */ i_spu = main_GetIntVariable( INPUT_SUBTITLE_VAR, 0 ); - if( i_spu < 0 || i_spu > vts.manager_inf.i_spu_nb ) + if( i_spu < 0 || i_spu > i_spu_nb ) { main_PutIntVariable( INPUT_SUBTITLE_VAR, 0 ); i_spu = 0; } - if( i_spu > 0 && vts.manager_inf.i_spu_nb > 0 ) + if( i_spu > 0 && i_spu_nb > 0 ) { i_spu += vts.manager_inf.i_audio_nb; input_SelectES( p_input, p_input->stream.pp_es[i_spu] ); @@ -896,7 +761,6 @@ static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area ) * Chapter selection */ - if( p_area->i_part != p_dvd->i_chapter ) { if( ( p_area->i_part > 0 ) && @@ -909,11 +773,11 @@ static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area ) return -1; } - p_input->stream.p_selected_area->i_tell = p_dvd->i_start - - p_area->i_start; + p_input->stream.p_selected_area->i_tell = + LB2OFF( p_dvd->i_start ) - p_area->i_start; p_input->stream.p_selected_area->i_part = p_dvd->i_chapter; - intf_WarnMsg( 2, "dvd info: chapter %d start at: %lld", + intf_WarnMsg( 4, "dvd info: chapter %d start at: %lld", p_area->i_part, p_area->i_tell ); } else @@ -922,9 +786,9 @@ static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area ) p_dvd->i_chapter = 1; } } + #define title \ p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title - if( p_area->i_angle != p_dvd->i_angle ) { if( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 ) @@ -944,14 +808,13 @@ static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area ) p_dvd->i_angle = p_area->i_angle; } - intf_WarnMsg( 2, "dvd info: angle %d selected", p_area->i_angle ); + intf_WarnMsg( 3, "dvd info: angle %d selected", p_area->i_angle ); } /* warn interface that something has changed */ + p_input->stream.b_seekable = 1; p_input->stream.b_changed = 1; - vlc_mutex_unlock( &p_input->stream.stream_lock ); - return 0; } @@ -966,34 +829,29 @@ static int DVDRead( input_thread_t * p_input, data_packet_t ** pp_packets ) { thread_dvd_data_t * p_dvd; - dvd_netlist_t * p_netlist; - input_area_t * p_area; + netlist_t * p_netlist; struct iovec * p_vec; - struct data_packet_s * pp_data[p_input->i_read_once]; + struct data_packet_s * pp_data[DVD_DATA_READ_ONCE]; u8 * pi_cur; int i_block_once; int i_packet_size; int i_iovec; int i_packet; int i_pos; - int i_read_bytes; int i_read_blocks; - off_t i_off; + int i_sector; boolean_t b_eof; boolean_t b_eot; + boolean_t b_eoc; p_dvd = (thread_dvd_data_t *)p_input->p_plugin_data; - p_netlist = (dvd_netlist_t *)p_input->p_method_data; - - /* Get an iovec pointer */ - if( ( p_vec = DVDGetiovec( p_netlist ) ) == NULL ) - { - intf_ErrMsg( "dvd error: can't get iovec" ); - return -1; - } + p_netlist = (netlist_t *)p_input->p_method_data; + b_eoc = 0; + i_sector = p_dvd->i_title_start + p_dvd->i_sector; i_block_once = p_dvd->i_end_sector - p_dvd->i_sector + 1; + /* Get the position of the next cell if we're at cell end */ if( i_block_once <= 0 ) { @@ -1011,9 +869,13 @@ static int DVDRead( input_thread_t * p_input, } /* Position the fd pointer on the right address */ - i_off = lseek( p_dvd->i_fd, - p_dvd->i_title_start + - (off_t)( p_dvd->i_sector ) *DVD_LB_SIZE, SEEK_SET ); + if( ( i_sector = dvdcss_seek( p_dvd->dvdhandle, + p_dvd->i_title_start + p_dvd->i_sector, + DVDCSS_SEEK_MPEG ) ) < 0 ) + { + intf_ErrMsg( "dvd error: %s", dvdcss_error( p_dvd->dvdhandle ) ); + return -1; + } /* update chapter : it will be easier when we have navigation * ES support */ @@ -1031,39 +893,38 @@ static int DVDRead( input_thread_t * p_input, ( p_dvd->i_prg_cell - i_angle + 1 ) ) { p_dvd->i_chapter++; + b_eoc = 1; } } - vlc_mutex_lock( &p_input->stream.stream_lock ); - - p_input->stream.p_selected_area->i_tell = i_off - - p_input->stream.p_selected_area->i_start; - p_input->stream.p_selected_area->i_part = p_dvd->i_chapter; - - /* the synchro has to be reinitialized when we change cell */ - p_input->stream.pp_programs[0]->i_synchro_state = SYNCHRO_REINIT; - - vlc_mutex_unlock( &p_input->stream.stream_lock ); - i_block_once = p_dvd->i_end_sector - p_dvd->i_sector + 1; } - /* the number of blocks read is the maw between the requested + /* The number of blocks read is the max between the requested * value and the leaving block in the cell */ if( i_block_once > p_dvd->i_block_once ) { i_block_once = p_dvd->i_block_once; } -//intf_WarnMsg( 2, "Sector: 0x%x Read: %d Chapter: %d", p_dvd->i_sector, i_block_once, p_dvd->i_chapter ); - +/* +intf_WarnMsg( 2, "Sector: 0x%x Read: %d Chapter: %d", p_dvd->i_sector, i_block_once, p_dvd->i_chapter ); +*/ p_netlist->i_read_once = i_block_once; + /* Get an iovec pointer */ + if( ( p_vec = input_NetlistGetiovec( p_netlist ) ) == NULL ) + { + intf_ErrMsg( "dvd error: can't get iovec" ); + return -1; + } + /* Reads from DVD */ - i_read_bytes = readv( p_dvd->i_fd, p_vec, i_block_once ); - i_read_blocks = ( i_read_bytes + 0x7ff ) >> 11; + i_read_blocks = dvdcss_readv( p_dvd->dvdhandle, p_vec, + i_block_once, DVDCSS_READ_DECRYPT ); - /* Update netlist indexes */ - DVDMviovec( p_netlist, i_read_blocks, pp_data ); + /* Update netlist indexes: we don't do it in DVDGetiovec since we + * need know the real number of blocks read */ + input_NetlistMviovec( p_netlist, i_read_blocks, pp_data ); /* Update global position */ p_dvd->i_sector += i_read_blocks; @@ -1073,64 +934,36 @@ static int DVDRead( input_thread_t * p_input, /* Read headers to compute payload length */ for( i_iovec = 0 ; i_iovec < i_read_blocks ; i_iovec++ ) { - if( p_dvd->b_encrypted ) - { - CSSDescrambleSector( p_dvd->p_css->pi_title_key, - p_vec[i_iovec].iov_base ); - ((u8*)(p_vec[i_iovec].iov_base))[0x14] &= 0x8F; - } - i_pos = 0; while( i_pos < p_netlist->i_buffer_size ) { - pi_cur = (u8*)(p_vec[i_iovec].iov_base + i_pos); + pi_cur = (u8*)p_vec[i_iovec].iov_base + i_pos; /*default header */ if( U32_AT( pi_cur ) != 0x1BA ) { /* That's the case for all packets, except pack header. */ i_packet_size = U16_AT( pi_cur + 4 ); - pp_packets[i_packet] = DVDNewPtr( p_netlist ); + pp_packets[i_packet] = input_NetlistNewPtr( p_netlist ); + (*pp_data[i_iovec]->pi_refcount)++; + pp_packets[i_packet]->pi_refcount = + pp_data[i_iovec]->pi_refcount; + pp_packets[i_packet]->p_buffer = pp_data[i_iovec]->p_buffer; } else { - /* Pack header. */ - if( ( pi_cur[4] & 0xC0 ) == 0x40 ) - { - /* MPEG-2 */ - i_packet_size = 8; - } - else if( ( pi_cur[4] & 0xF0 ) == 0x20 ) - { - /* MPEG-1 */ - i_packet_size = 6; - } - else - { - intf_ErrMsg( "Unable to determine stream type" ); - return( -1 ); - } - + /* MPEG-2 Pack header. */ + i_packet_size = 8; pp_packets[i_packet] = pp_data[i_iovec]; - } - (*pp_data[i_iovec]->pi_refcount)++; - - pp_packets[i_packet]->pi_refcount = pp_data[i_iovec]->pi_refcount; - - pp_packets[i_packet]->p_buffer = pp_data[i_iovec]->p_buffer; - pp_packets[i_packet]->p_payload_start = pp_packets[i_packet]->p_buffer + i_pos; pp_packets[i_packet]->p_payload_end = pp_packets[i_packet]->p_payload_start + i_packet_size + 6; - pp_packets[i_packet]->p_next = NULL; - pp_packets[i_packet]->b_discard_payload = 0; - i_packet++; i_pos += i_packet_size + 6; } @@ -1140,25 +973,37 @@ static int DVDRead( input_thread_t * p_input, vlc_mutex_lock( &p_input->stream.stream_lock ); - p_input->stream.p_selected_area->i_tell += i_read_bytes; - b_eot = !( p_input->stream.p_selected_area->i_tell < p_dvd->i_size ); - b_eof = b_eot && ( ( p_dvd->i_title + 1 ) >= p_input->stream.i_area_nb ); - p_area = p_input->stream.pp_areas[p_dvd->i_title + 1]; + p_input->stream.p_selected_area->i_tell = + LB2OFF( i_sector + i_read_blocks ) - + p_input->stream.p_selected_area->i_start; + if( b_eoc ) + { + /* We modify i_part only at end of chapter not to erase + * some modification from the interface */ + p_input->stream.p_selected_area->i_part = p_dvd->i_chapter; + } - vlc_mutex_unlock( &p_input->stream.stream_lock ); + b_eot = !( p_input->stream.p_selected_area->i_tell + < p_input->stream.p_selected_area->i_size ); + b_eof = b_eot && ( ( p_dvd->i_title + 1 ) >= p_input->stream.i_area_nb ); if( b_eof ) { + vlc_mutex_unlock( &p_input->stream.stream_lock ); return 1; } if( b_eot ) { + intf_WarnMsg( 4, "dvd info: new title" ); p_dvd->i_title++; - DVDSetArea( p_input, p_area ); + DVDSetArea( p_input, p_input->stream.pp_areas[p_dvd->i_title] ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); return 0; } + vlc_mutex_unlock( &p_input->stream.stream_lock ); + if( i_read_blocks == i_block_once ) { return 0; @@ -1176,16 +1021,16 @@ static int DVDRewind( input_thread_t * p_input ) } /***************************************************************************** - * DVDSeek : Goes to a given position on the stream ; this one is used by the - * input and translate chronological position from input to logical postion - * on the device - * --- + * DVDSeek : Goes to a given position on the stream. + ***************************************************************************** + * This one is used by the input and translate chronological position from + * input to logical position on the device. * The lock should be taken before calling this function. *****************************************************************************/ static void DVDSeek( input_thread_t * p_input, off_t i_off ) { thread_dvd_data_t * p_dvd; - off_t i_pos; + int i_block; int i_prg_cell; int i_cell; int i_chapter; @@ -1194,11 +1039,8 @@ static void DVDSeek( input_thread_t * p_input, off_t i_off ) p_dvd = ( thread_dvd_data_t * )p_input->p_plugin_data; /* we have to take care of offset of beginning of title */ - i_pos = i_off + p_input->stream.p_selected_area->i_start - - p_dvd->i_title_start; - - /* update navigation data */ - p_dvd->i_sector = i_pos >> 11; + p_dvd->i_sector = OFF2LB(i_off + p_input->stream.p_selected_area->i_start) + - p_dvd->i_title_start; i_prg_cell = 0; i_chapter = 0; @@ -1222,7 +1064,7 @@ static void DVDSeek( input_thread_t * p_input, off_t i_off ) /* Find first title cell which is inside program cell */ if( DVDFindCell( p_dvd ) < 0 ) { - /* no following cell : we're at eof */ + /* no following cell : we're at eof */ intf_ErrMsg( "dvd error: cell seeking failed" ); p_input->b_error = 1; return; @@ -1262,30 +1104,44 @@ static void DVDSeek( input_thread_t * p_input, off_t i_off ) { i_angle = 0; } - while( ( title.chapter_map.pi_start_cell[i_chapter] <= - ( p_dvd->i_prg_cell - i_angle + 1 ) ) && - ( i_chapter < ( p_dvd->i_chapter_nb - 1 ) ) ) + if( p_dvd->i_chapter_nb > 1 ) + { + while( ( title.chapter_map.pi_start_cell[i_chapter] <= + ( p_dvd->i_prg_cell - i_angle + 1 ) ) && + ( i_chapter < ( p_dvd->i_chapter_nb - 1 ) ) ) + { + i_chapter++; + } + } + else { - i_chapter++; + i_chapter = 1; } p_dvd->i_chapter = i_chapter; p_input->stream.p_selected_area->i_part = p_dvd->i_chapter; + if( ( i_block = dvdcss_seek( p_dvd->dvdhandle, + p_dvd->i_title_start + p_dvd->i_sector, + DVDCSS_SEEK_MPEG ) ) < 0 ) + { + intf_ErrMsg( "dvd error: %s", dvdcss_error( p_dvd->dvdhandle ) ); + p_input->b_error = 1; + return; + } + p_input->stream.p_selected_area->i_tell = - lseek( p_dvd->i_fd, p_dvd->i_title_start + - (off_t)( p_dvd->i_sector ) *DVD_LB_SIZE, SEEK_SET ) - - p_input->stream.p_selected_area->i_start; -/* - intf_WarnMsg( 3, "Program Cell: %d Cell: %d Chapter: %d", + LB2OFF ( i_block ) - p_input->stream.p_selected_area->i_start; + + intf_WarnMsg( 7, "Program Cell: %d Cell: %d Chapter: %d", p_dvd->i_prg_cell, p_dvd->i_cell, p_dvd->i_chapter ); -*/ + return; } #define cell p_dvd->p_ifo->vts.cell_inf - + /***************************************************************************** * DVDFindCell: adjust the title cell index with the program cell *****************************************************************************/ @@ -1312,7 +1168,7 @@ static int DVDFindCell( thread_dvd_data_t * p_dvd ) } /* -intf_WarnMsg( 3, "FindCell: i_cell %d i_index %d found %d nb %d", +intf_WarnMsg( 12, "FindCell: i_cell %d i_index %d found %d nb %d", p_dvd->i_cell, p_dvd->i_prg_cell, i_cell, @@ -1348,7 +1204,7 @@ static int DVDFindSector( thread_dvd_data_t * p_dvd ) intf_ErrMsg( "dvd error: can't find sector" ); return -1; } - + /* Find start and end sectors of new cell */ #if 1 p_dvd->i_sector = MAX( @@ -1363,7 +1219,7 @@ static int DVDFindSector( thread_dvd_data_t * p_dvd ) #endif /* - intf_WarnMsg( 3, "cell: %d sector1: 0x%x end1: 0x%x\n" + intf_WarnMsg( 12, "cell: %d sector1: 0x%x end1: 0x%x\n" "index: %d sector2: 0x%x end2: 0x%x\n" "category: 0x%x ilvu end: 0x%x vobu start 0x%x", p_dvd->i_cell, @@ -1402,11 +1258,16 @@ static int DVDChapterSelect( thread_dvd_data_t * p_dvd, int i_chapter ) } /* start is : beginning of vts vobs + offset to vob x */ - p_dvd->i_start = p_dvd->i_title_start + - DVD_LB_SIZE * (off_t)( p_dvd->i_sector ); + p_dvd->i_start = p_dvd->i_title_start + p_dvd->i_sector; /* Position the fd pointer on the right address */ - p_dvd->i_start = lseek( p_dvd->i_fd, p_dvd->i_start, SEEK_SET ); + if( ( p_dvd->i_start = dvdcss_seek( p_dvd->dvdhandle, + p_dvd->i_start, + DVDCSS_SEEK_MPEG ) ) < 0 ) + { + intf_ErrMsg( "dvd error: %s", dvdcss_error( p_dvd->dvdhandle ) ); + return -1; + } p_dvd->i_chapter = i_chapter; return 0; @@ -1425,7 +1286,6 @@ static int DVDChooseAngle( thread_dvd_data_t * p_dvd ) case 0x5: p_dvd->i_prg_cell += p_dvd->i_angle - 1; p_dvd->i_angle_cell = 0; -// intf_WarnMsg( 3, "dvd info: choosing angle %d", p_dvd->i_angle ); break; /* we exit a multi-angle section */ case 0x9: