-/*****************************************************************************
- * input_dvd.c: DVD raw reading plugin.
- * ---
+/* input_dvd.c: DVD raw reading plugin.
+ *****************************************************************************
* This plugins should handle all the known specificities of the DVD format,
* 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.29 2001/03/05 00:40:06 stef Exp $
+ * $Id: input_dvd.c,v 1.126 2002/03/03 17:34:27 xav Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
/*****************************************************************************
* Preamble
*****************************************************************************/
-#include "defs.h"
-
-#ifdef HAVE_CSS
-#define MODULE_NAME dvd-css
-#else /* HAVE_CSS */
-#define MODULE_NAME dvd-nocss
-#endif /* HAVE_CSS */
-#include "modules_inner.h"
-
#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
-#include <netinet/in.h>
+#include <string.h>
+
+#include <videolan/vlc.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
#include <fcntl.h>
#include <sys/types.h>
-#include <sys/uio.h>
-
+#include <sys/stat.h>
#include <string.h>
#include <errno.h>
-#include <malloc.h>
-#include "config.h"
-#include "common.h"
-#include "threads.h"
-#include "mtime.h"
-#include "tests.h"
+#ifdef STRNCASECMP_IN_STRINGS_H
+# include <strings.h>
+#endif
+
+#if defined( WIN32 )
+# include <io.h> /* read() */
+#else
+# include <sys/uio.h> /* struct iovec */
+#endif
-#include "intf_msg.h"
+#ifdef GOD_DAMN_DMCA
+# include "dummy_dvdcss.h"
+#else
+# include <videolan/dvdcss.h>
+#endif
-#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 "iso_lang.h"
#include "debug.h"
-#include "modules.h"
-
-/*****************************************************************************
- * Local tables
- *****************************************************************************/
-static struct
-{
- char p_code[3];
- char p_lang_long[20];
-}
-
-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", "" }
-};
+/* how many packets DVDDemux will read in each loop */
+#define DVD_READ_ONCE 64
/*****************************************************************************
* Local prototypes
*****************************************************************************/
-static int DVDProbe ( probedata_t *p_data );
-static int DVDCheckCSS ( struct input_thread_s * );
-static int DVDRead ( struct input_thread_s *, data_packet_t ** );
-static void DVDInit ( struct input_thread_s * );
-static void DVDEnd ( struct input_thread_s * );
-static void DVDSeek ( struct input_thread_s *, off_t );
-static int DVDSetArea ( struct input_thread_s *, int, int, int, int );
-static int DVDRewind ( struct input_thread_s * );
+
+/* called from outside */
+static int 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 *, byte_t *, size_t );
+static void DVDSeek ( struct input_thread_s *, off_t );
+
+static int DVDRewind ( struct input_thread_s * );
+static int DVDDemux ( struct input_thread_s * );
+static int DVDInit ( struct input_thread_s * );
+static void DVDEnd ( struct input_thread_s * );
+
+/* called only inside */
+static void DVDLaunchDecoders( input_thread_t * p_input );
+static int DVDChooseAngle( thread_dvd_data_t * );
+static int DVDFindCell( thread_dvd_data_t * );
+static int DVDFindSector( thread_dvd_data_t * );
+static int DVDChapterSelect( thread_dvd_data_t *, int );
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
* we don't pollute the namespace too much.
*****************************************************************************/
-void _M( input_getfunctions )( function_list_t * p_function_list )
+void _M( access_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_end = DVDEnd;
+#define input p_function_list->functions.access
+ input.pf_open = DVDOpen;
+ input.pf_close = DVDClose;
input.pf_read = DVDRead;
input.pf_set_area = DVDSetArea;
- 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_rewind = DVDRewind;
+ input.pf_set_program = DVDSetProgram;
input.pf_seek = DVDSeek;
#undef input
}
+void _M( demux_getfunctions)( function_list_t * p_function_list )
+{
+#define demux p_function_list->functions.demux
+ demux.pf_init = DVDInit;
+ demux.pf_end = DVDEnd;
+ demux.pf_demux = DVDDemux;
+ demux.pf_rewind = DVDRewind;
+#undef demux
+}
+
/*
- * Local tools to decode some data in ifo
+ * Data demux functions
*/
/*****************************************************************************
- * Language: gives the long language name from the two-letters ISO-639 code
+ * DVDInit: initializes DVD structures
*****************************************************************************/
-static char * Language( u16 i_code )
+static int DVDInit( input_thread_t * p_input )
{
- int i = 0;
- while( memcmp( lang_tbl[i].p_code, &i_code, 2 ) &&
- lang_tbl[i].p_lang_long[0] )
+ if( strncmp( p_input->p_access_module->psz_name, "dvd", 3 ) )
{
- i++;
+ return -1;
}
- return lang_tbl[i].p_lang_long;
-}
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+
+ DVDLaunchDecoders( p_input );
+
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
-/*
- * Data reading functions
- */
+ return 0;
+}
/*****************************************************************************
- * DVDProbe: verifies that the stream is a PS stream
+ * DVDEnd: frees unused data
*****************************************************************************/
-static int DVDProbe( probedata_t *p_data )
+static void DVDEnd( input_thread_t * p_input )
{
- 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 */
+/*****************************************************************************
+ * DVDDemux
+ *****************************************************************************/
+#define PEEK( SIZE ) \
+ i_result = input_Peek( p_input, &p_peek, SIZE ); \
+ if( i_result == -1 ) \
+ { \
+ return( -1 ); \
+ } \
+ else if( i_result < SIZE ) \
+ { \
+ /* EOF */ \
+ return( 0 ); \
}
- 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;
- }
+static int DVDDemux( input_thread_t * p_input )
+{
+ int i;
+ byte_t * p_peek;
+ data_packet_t * p_data;
+ ssize_t i_result;
+ int i_packet_size;
+
- i_handle = open( psz_name, 0 );
- if( i_handle == -1 )
+ /* Read headers to compute payload length */
+ for( i = 0 ; i < DVD_READ_ONCE ; i++ )
{
- return( 0 );
- }
- close( i_handle );
- return( i_score );
+ /* Read what we believe to be a packet header. */
+ PEEK( 4 );
+
+ /* Default header */
+ if( U32_AT( p_peek ) != 0x1BA )
+ {
+ /* That's the case for all packets, except pack header. */
+ i_packet_size = U16_AT( p_peek + 4 );
+ }
+ else
+ {
+ /* MPEG-2 Pack header. */
+ i_packet_size = 8;
+ }
+
+ /* Fetch a packet of the appropriate size. */
+ i_result = input_SplitBuffer( p_input, &p_data, i_packet_size + 6 );
+ if( i_result <= 0 )
+ {
+ return( i_result );
+ }
+
+ /* In MPEG-2 pack headers we still have to read stuffing bytes. */
+ if( (p_data->p_demux_start[3] == 0xBA) && (i_packet_size == 8) )
+ {
+ size_t i_stuffing = (p_data->p_demux_start[13] & 0x7);
+ /* Force refill of the input buffer - though we don't care
+ * about p_peek. Please note that this is unoptimized. */
+ PEEK( i_stuffing );
+ p_input->p_current_data += i_stuffing;
+ }
+
+ input_DemuxPS( p_input, p_data );
+
+ }
+
+ return i;
}
/*****************************************************************************
- * DVDCheckCSS: check the stream
+ * DVDRewind : reads a stream backward
*****************************************************************************/
-static int DVDCheckCSS( input_thread_t * p_input )
+static int DVDRewind( input_thread_t * p_input )
{
- return CSSTest( p_input->i_handle );
+ return( -1 );
}
+
+/*
+ * Data access functions
+ */
+
/*****************************************************************************
- * DVDFindSector: find cell index in adress map from index in
- * information table program map and give corresponding sectors.
+ * DVDOpen: open dvd
*****************************************************************************/
-static int DVDFindSector( thread_dvd_data_t * p_dvd )
+static int DVDOpen( struct input_thread_s *p_input )
{
- pgc_t * p_pgc;
- int i_cell;
- int i_index;
+ struct stat stat_info;
+ char * psz_parser = p_input->psz_name;
+ char * psz_device = p_input->psz_name;
+ dvdcss_handle dvdhandle;
+ thread_dvd_data_t * p_dvd;
+ input_area_t * p_area;
+ int i_title;
+ int i_chapter;
+ int i;
- p_pgc = &p_dvd->ifo.vts.pgci_ti.p_srp[p_dvd->i_vts_title-1].pgc;
+ /* Parse input string : device[@rawdevice] */
+ while( *psz_parser && *psz_parser != '@' )
+ {
+ psz_parser++;
+ }
- i_index = p_dvd->i_prg_cell - 1;
+ if( *psz_parser == '@' )
+ {
+ /* Found raw device */
+ *psz_parser = '\0';
+ psz_parser++;
- do {
- if( i_index++ > p_dvd->i_prg_cell )
- {
- return -1;
- }
-
- i_cell = p_dvd->i_cell + 1;
+ config_PutPszVariable( "DVDCSS_RAW_DEVICE", psz_parser );
+ }
- while( ( ( p_pgc->p_cell_pos_inf[i_index].i_vob_id !=
- p_dvd->ifo.vts.c_adt.p_cell_inf[i_cell].i_vob_id ) ||
- ( p_pgc->p_cell_pos_inf[i_index].i_cell_id !=
- p_dvd->ifo.vts.c_adt.p_cell_inf[i_cell].i_cell_id ) ) &&
- ( i_cell < ( p_dvd->ifo.vts.c_adt.i_cell_nb ) ) )
- {
- i_cell++;
- }
+ if( stat( psz_device, &stat_info ) == -1 )
+ {
+ intf_ErrMsg( "input error: cannot stat() device `%s' (%s)",
+ psz_device, strerror(errno));
+ return( -1 );
+ }
+
+#ifndef WIN32
+ if( !S_ISBLK(stat_info.st_mode) && !S_ISCHR(stat_info.st_mode) )
+ {
+ intf_WarnMsg( 3, "input : DVD plugin discarded"
+ " (not a valid block device)" );
+ return -1;
+ }
+#endif
+
+ intf_WarnMsg( 2, "input: dvd=%s raw=%s", psz_device, psz_parser );
+
+ /*
+ * set up input
+ */
+ p_input->i_mtu = 0;
- } while( i_cell == ( p_dvd->ifo.vts.c_adt.i_cell_nb ) );
+ vlc_mutex_lock( &p_input->stream.stream_lock );
- p_dvd->i_cell = i_cell;
- p_dvd->i_prg_cell = i_index;
+ p_input->stream.i_method = INPUT_METHOD_DVD;
- /* Find start and end sectors of new cell */
- p_dvd->i_sector = MAX(
- p_dvd->ifo.vts.c_adt.p_cell_inf[i_cell].i_ssector,
- p_pgc->p_cell_play_inf[i_index].i_entry_sector );
- p_dvd->i_end_sector = MIN(
- p_dvd->ifo.vts.c_adt.p_cell_inf[i_cell].i_esector,
- p_pgc->p_cell_play_inf[i_index].i_lsector );
+ /* 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 );
+
+ /*
+ * get plugin ready
+ */
+ dvdhandle = dvdcss_open( psz_device );
+
+ if( dvdhandle == NULL )
+ {
+ intf_ErrMsg( "dvd error: dvdcss can't open device" );
+ return -1;
+ }
+
+ p_dvd = malloc( sizeof(thread_dvd_data_t) );
+ if( p_dvd == NULL )
+ {
+ intf_ErrMsg( "dvd error: out of memory" );
+ return -1;
+ }
+
+ p_dvd->dvdhandle = (dvdcss_handle) dvdhandle;
+ p_input->p_access_data = (void *)p_dvd;
+
+ if( dvdcss_seek( p_dvd->dvdhandle, 0, DVDCSS_NOFLAGS ) < 0 )
+ {
+ intf_ErrMsg( "dvd error: %s", dvdcss_error( p_dvd->dvdhandle ) );
+ return -1;
+ }
+
+ /* Ifo allocation & initialisation */
+ if( IfoCreate( p_dvd ) < 0 )
+ {
+ intf_ErrMsg( "dvd error: allcation error in ifo" );
+ free( p_dvd );
+ return -1;
+ }
+
+ if( IfoInit( p_dvd->p_ifo ) < 0 )
+ {
+ intf_ErrMsg( "dvd error: fatal failure in ifo" );
+ IfoDestroy( p_dvd->p_ifo );
+ free( p_dvd );
+ return -1;
+ }
+
+ /* 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 ) );
+
+#define title_inf p_dvd->p_ifo->vmg.title_inf
+ intf_WarnMsg( 2, "dvd info: number of titles: %d", title_inf.i_title_nb );
+
+#define area p_input->stream.pp_areas
+ /* We start from 1 here since the default area 0
+ * is reserved for video_ts.vob */
+ for( i = 1 ; i <= title_inf.i_title_nb ; i++ )
+ {
+ input_AddArea( p_input );
+
+ /* Titles are Program Chains */
+ area[i]->i_id = i;
+
+ /* Absolute start offset and size
+ * We can only set that with vts ifo, so we do it during the
+ * first call to DVDSetArea */
+ area[i]->i_start = 0;
+ area[i]->i_size = 0;
+
+ /* Number of chapters */
+ area[i]->i_part_nb = title_inf.p_attr[i-1].i_chapter_nb;
+ area[i]->i_part = 1;
+
+ /* Number of angles */
+ area[i]->i_angle_nb = 0;
+ area[i]->i_angle = 1;
+
+ /* Offset to vts_i_0.ifo */
+ area[i]->i_plugin_data = p_dvd->p_ifo->i_start +
+ title_inf.p_attr[i-1].i_start_sector;
+ }
+#undef area
+
+ /* Get requested title - if none try the first title */
+ i_title = config_GetIntVariable( INPUT_TITLE_VAR );
+ if( i_title <= 0 || i_title > title_inf.i_title_nb )
+ {
+ i_title = 1;
+ }
+
+#undef title_inf
+
+ /* Get requested chapter - if none defaults to first one */
+ i_chapter = config_GetIntVariable( INPUT_CHAPTER_VAR );
+ if( i_chapter <= 0 )
+ {
+ i_chapter = 1;
+ }
-//intf_WarnMsg( 3, "cell: %d index: %d sector1: %x sector2: %x end1: %x end2: %x", i_cell, i_index, p_dvd->ifo.vts.c_adt.p_cell_inf[i_cell].i_ssector, p_pgc->p_cell_play_inf[i_index].i_entry_sector, p_dvd->ifo.vts.c_adt.p_cell_inf[i_cell].i_esector,p_pgc->p_cell_play_inf[i_index].i_lsector );
+ p_area = p_input->stream.pp_areas[i_title];
+ p_area->i_part = i_chapter;
+
+ /* set title, chapter, audio and subpic */
+ if( DVDSetArea( p_input, p_area ) )
+ {
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ return -1;
+ }
+
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
return 0;
+
}
/*****************************************************************************
- * DVDChapterSelect: find the cell corresponding to requested chapter
- * When called to find chapter 1, also sets title size and end.
+ * DVDClose: close dvd
*****************************************************************************/
-static int DVDChapterSelect( thread_dvd_data_t * p_dvd, int i_chapter )
+static void DVDClose( struct input_thread_s *p_input )
{
- pgc_t * p_pgc;
-
- p_pgc = &p_dvd->ifo.vts.pgci_ti.p_srp[p_dvd->i_vts_title-1].pgc;
-
- /* Find cell index in Program chain for current chapter */
- p_dvd->i_prg_cell = p_pgc->prg_map.pi_entry_cell[i_chapter-1] - 1;
- p_dvd->i_cell = -1;
-
- /* Search for cell_index in cell adress_table */
- DVDFindSector( p_dvd );
+ thread_dvd_data_t * p_dvd;
- /* initialize navigation parameters */
- p_dvd->i_sector = p_dvd->ifo.vts.c_adt.p_cell_inf[p_dvd->i_cell].i_ssector;
- p_dvd->i_end_sector =
- p_dvd->ifo.vts.c_adt.p_cell_inf[p_dvd->i_cell].i_esector;
+ p_dvd = (thread_dvd_data_t*)p_input->p_access_data;
- /* 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 );
+ IfoDestroy( p_dvd->p_ifo );
- /* Position the fd pointer on the right address */
- p_dvd->i_start = lseek( p_dvd->i_fd, p_dvd->i_start, SEEK_SET );
+ p_input->p_access_data = (void *)(p_dvd->dvdhandle);
+ free( p_dvd );
- p_dvd->i_chapter = i_chapter;
+ /* Clean up libdvdcss */
+ dvdcss_close( (dvdcss_handle) p_input->p_access_data );
+}
+/*****************************************************************************
+ * 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,
- int i_title, int i_chapter,
- int i_audio, int i_spu )
+static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area )
{
thread_dvd_data_t * p_dvd;
es_descriptor_t * p_es;
- int i_index;
- int i_nb;
u16 i_id;
- u8 i_ac3;
- u8 i_mpeg;
- u8 i_sub_pic;
- u8 i;
- boolean_t b_last;
-
- p_dvd = (thread_dvd_data_t*)p_input->p_plugin_data;
+ int i_vts_title;
+ int i_audio_nb = 0;
+ int i_spu_nb = 0;
+ int i;
- vlc_mutex_lock( &p_input->stream.stream_lock );
+ p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
+
+ /* we can't use the interface slider until initilization is complete */
+ p_input->stream.b_seekable = 0;
- if( i_title >= 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
*/
-
/* Change the default area */
- p_input->stream.p_selected_area = p_input->stream.pp_areas[i_title];
+ p_input->stream.p_selected_area =
+ p_input->stream.pp_areas[p_area->i_id];
+
+ /* 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;
- /* title number: it is not vts nb! */
- p_dvd->i_title = i_title;
+ /* 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 )
+ {
+ intf_ErrMsg( "dvd error: fatal error in vts ifo" );
+ free( p_dvd );
+ p_input->b_error = 1;
+ return -1;
+ }
+#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 =
- p_dvd->ifo.vmg.ptt_srpt.p_tts[i_title-1].i_vts_ttn;
+ 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[i_vts_title-1].i_title_id;
- /* vts number */
- p_dvd->ifo.i_title = i_title;
+ intf_WarnMsg( 3, "dvd: title %d vts_title %d pgc %d",
+ p_dvd->i_title, i_vts_title, p_dvd->i_title_id );
- /* ifo vts */
- IfoReadVTS( &(p_dvd->ifo) );
- intf_WarnMsg( 2, "ifo info: vts initialized" );
-
- /* css title key for current vts */
- if( p_dvd->b_encrypted )
+ /*
+ * Angle management
+ */
+ p_dvd->i_angle_nb = vmg.title_inf.p_attr[p_dvd->i_title-1].i_angle_nb;
+ p_dvd->i_angle = config_GetIntVariable( INPUT_ANGLE_VAR );
+ if( ( p_dvd->i_angle <= 0 ) || p_dvd->i_angle > p_dvd->i_angle_nb )
{
- p_dvd->p_css->i_title =
- p_dvd->ifo.vmg.ptt_srpt.p_tts[i_title-1].i_tts_nb;
- p_dvd->p_css->i_title_pos =
- p_dvd->ifo.vts.i_pos +
- p_dvd->ifo.vts.mat.i_tt_vobs_ssector * DVD_LB_SIZE;
- CSSGetKey( p_dvd->p_css );
- intf_WarnMsg( 2, "css info: vts key initialized" );
+ p_dvd->i_angle = 1;
}
/*
* Set selected title start and size
*/
- /* title set offset */
- p_dvd->i_title_start = p_dvd->ifo.vts.i_pos + DVD_LB_SIZE *
- (off_t)( p_dvd->ifo.vts.mat.i_tt_vobs_ssector );
+ /* 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 = -1;
+ p_dvd->i_cell = 0;
p_dvd->i_prg_cell = -1 +
- p_dvd->ifo.vts.pgci_ti.p_srp[p_dvd->i_vts_title-1].pgc.i_cell_nb;
- DVDFindSector( p_dvd );
+ vts.title_unit.p_title[p_dvd->i_title_id-1].title.i_cell_nb;
+ if( DVDFindCell( p_dvd ) < 0 )
+ {
+ intf_ErrMsg( "dvd error: can't find title end" );
+ p_input->b_error = 1;
+ return -1;
+ }
+
/* temporary hack to fix size in some dvds */
- if( p_dvd->i_cell >= p_dvd->ifo.vts.c_adt.i_cell_nb )
+ if( p_dvd->i_cell >= vts.cell_inf.i_cell_nb )
{
- p_dvd->i_cell = p_dvd->ifo.vts.c_adt.i_cell_nb - 1;
+ p_dvd->i_cell = vts.cell_inf.i_cell_nb - 1;
}
- p_dvd->i_size = DVD_LB_SIZE *
- (off_t)( p_dvd->ifo.vts.c_adt.p_cell_inf[p_dvd->i_cell].i_esector );
-
- DVDChapterSelect( p_dvd, 1 );
-
- p_dvd->i_size -= (off_t)( p_dvd->i_sector + 1 ) *DVD_LB_SIZE;
-
- lseek( p_input->i_handle, p_dvd->i_start, SEEK_SET );
+ p_dvd->i_sector = 0;
+ 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 */
- intf_WarnMsg( 2, "dvd info: title: %d", 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",
- p_dvd->ifo.vmg.ptt_srpt.p_tts[i_title-1].i_ptt_nb );
-
-/* intf_WarnMsg( 3, "last: %d index: %d", i_last_chapter, i_index );*/
+ 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;
+ }
+ p_dvd->i_size -= p_dvd->i_sector + 1;
-/* intf_WarnMsg( 3, "DVD: Cell: %d vob id: %d cell id: %d", i_end_cell, p_dvd->ifo.vts.c_adt.p_cell_inf[i_end_cell].i_vob_id, p_dvd->ifo.vts.c_adt.p_cell_inf[i_end_cell].i_cell_id );*/
+ 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
*/
if( p_input->stream.pp_programs != NULL )
{
- input_DelProgram( p_input, p_input->stream.pp_programs[0] );
+ /* We don't use input_EndStream here since
+ * we keep area structures */
+
+ for( i = 0 ; i < p_input->stream.i_selected_es_number ; i++ )
+ {
+ input_UnselectES( p_input, p_input->stream.pp_selected_es[i] );
+ }
+
+ 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];
+// p_input->stream.p_new_program = p_input->stream.pp_programs[0];
+
+ /* No PSM to read in DVD mode, we already have all information */
+ 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;
- input_SelectES( p_input, p_es );
- intf_WarnMsg( 1, "dvd info: video MPEG2 stream" );
-
+ p_es->i_cat = VIDEO_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_nb = p_dvd->ifo.vts.mat.i_audio_nb;
-
- i_ac3 = 0x7f;
- i_mpeg = 0xc0;
-
- for( i = 1 ; i <= i_nb ; i++ )
+ for( i = 1 ; i <= vts.manager_inf.i_audio_nb ; i++ )
{
+ IfoPrintAudio( p_dvd, i );
-#if 0
- fprintf( stderr, "Audio %d: %x %x %x %x %x %x %x %x %x %x %x %x\n", i,
- p_dvd->ifo.vts.mat.p_audio_atrt[i-1].i_num_channels,
- p_dvd->ifo.vts.mat.p_audio_atrt[i-1].i_coding_mode,
- p_dvd->ifo.vts.mat.p_audio_atrt[i-1].i_multichannel_extension,
- p_dvd->ifo.vts.mat.p_audio_atrt[i-1].i_type,
- p_dvd->ifo.vts.mat.p_audio_atrt[i-1].i_appl_mode,
- p_dvd->ifo.vts.mat.p_audio_atrt[i-1].i_foo,
- p_dvd->ifo.vts.mat.p_audio_atrt[i-1].i_bar,
- p_dvd->ifo.vts.mat.p_audio_atrt[i-1].i_appl_mode,
- p_dvd->ifo.vts.mat.p_audio_atrt[i-1].i_quantization,
- p_dvd->ifo.vts.mat.p_audio_atrt[i-1].i_sample_freq,
- p_dvd->ifo.vts.mat.p_audio_atrt[i-1].i_lang_code,
- p_dvd->ifo.vts.mat.p_audio_atrt[i-1].i_caption );
-#endif
-
- switch( p_dvd->ifo.vts.mat.p_audio_atrt[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;
- strcpy( p_es->psz_desc, Language( hton16(
- p_dvd->ifo.vts.mat.p_audio_atrt[i-1].i_lang_code ) ) );
-
- intf_WarnMsg( 1, "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;
- strcpy( p_es->psz_desc, Language( hton16(
- p_dvd->ifo.vts.mat.p_audio_atrt[i-1].i_lang_code ) ) );
-
- intf_WarnMsg( 1, "dvd info: audio stream %d %s\t(0x%x)",
- i, p_es->psz_desc, i_id );
-
- break;
- case 0x04: /* LPCM */
- i_id = 0;
- intf_ErrMsg( "dvd warning: LPCM audio not handled yet" );
- 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",
- p_dvd->ifo.vts.mat.p_audio_atrt[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 */
- i_nb = p_dvd->ifo.vts.mat.i_subpic_nb;
-
- b_last = 0;
- i_sub_pic = 0x20;
- for( i = 1 ; i <= i_nb ; i++ )
+
+ 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;
- strcpy( p_es->psz_desc, Language( hton16(
- p_dvd->ifo.vts.mat.p_subpic_atrt[i-1].i_lang_code ) ) );
- intf_WarnMsg( 1, "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 =
- ( p_dvd->ifo.vts.mat.p_subpic_atrt[i].i_prefix == 0 );
+ p_es->i_cat = SPU_ES;
+ strcpy( p_es->psz_desc, DecodeLanguage( hton16(
+ vts.manager_inf.p_spu_attr[i-1].i_lang_code ) ) );
}
}
-
- } // i_title >= 0
-
- /*
- * Select requested ES
- */
- if( ( i_audio >= 0 ) || ( i_title >= 0 ) )
- {
-
- /* Audio: we check it is in the range and
- * default it to the first if not */
- if( i_audio > p_dvd->ifo.vts.mat.i_audio_nb )
+#undef spu_status
+
+ /* FIXME: hack to check that the demuxer is ready, and set
+ * the decoders */
+ if( p_input->p_demux_module )
{
- i_audio = 1;
+ DVDLaunchDecoders( p_input );
}
- p_es = p_input->stream.pp_programs[0]->pp_es[i_audio];
+ } /* i_title >= 0 */
+ else
+ {
+ p_area = p_input->stream.p_selected_area;
+ }
+#undef vts
+#undef vmg
- /* We can only have one audio channel */
- /* Look for a preselected one */
- i_index = -1;
- for( i = 0 ; i < p_input->stream.i_selected_es_number ; i++ )
- {
- if( p_input->stream.pp_selected_es[i]->b_audio )
- {
- i_index = i;
- break;
- }
- }
+ /*
+ * Chapter selection
+ */
- if( i_index != -1 )
+ if( p_area->i_part != p_dvd->i_chapter )
+ {
+ if( ( p_area->i_part > 0 ) &&
+ ( p_area->i_part <= p_area->i_part_nb ))
{
-
- if( p_input->stream.pp_selected_es[i_index] != p_es )
+ if( DVDChapterSelect( p_dvd, p_area->i_part ) < 0 )
{
- input_UnselectES( p_input,
- p_input->stream.pp_selected_es[i_index] );
- input_SelectES( p_input, p_es );
- intf_WarnMsg( 1, "dvd info: audio %d selected -> %s (0x%x)",
- i_audio, p_es->psz_desc, p_es->i_id );
+ intf_ErrMsg( "dvd error: can't set chapter in area" );
+ p_input->b_error = 1;
+ return -1;
}
+
+ 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( 4, "dvd info: chapter %d start at: %lld",
+ p_area->i_part, p_area->i_tell );
}
else
{
- input_SelectES( p_input, p_es );
- intf_WarnMsg( 1, "dvd info: audio %d selected -> %s (0x%x)",
- i_audio, p_es->psz_desc, p_es->i_id );
+ p_area->i_part = 1;
+ p_dvd->i_chapter = 1;
}
}
- if( ( i_spu >= 0 ) || ( i_title >= 0 ) )
+#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 )
{
- /* For spu: no one if none or a not existing one requested */
- if( ( i_spu <= p_dvd->ifo.vts.mat.i_subpic_nb ) && ( i_spu > 0 ) )
+ if( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 )
{
- input_SelectES( p_input, ( p_es = p_input->stream.pp_programs[0]->
- pp_es[ i_spu + p_dvd->ifo.vts.mat.i_audio_nb ] ) );
+ if( ( p_area->i_angle - p_dvd->i_angle ) < 0 )
+ {
+ p_dvd->i_cell = 0;
+ }
+ p_dvd->i_prg_cell += ( p_area->i_angle - p_dvd->i_angle );
+ p_dvd->i_angle = p_area->i_angle;
- intf_WarnMsg( 1, "dvd info: spu %d selected -> %s (0x%x)",
- i_spu, p_es->psz_desc, p_es->i_id );
+ DVDFindSector( p_dvd );
+ p_dvd->i_cell += p_dvd->i_angle_cell;
+ }
+ else
+ {
+ p_dvd->i_angle = p_area->i_angle;
}
- }
-
- /*
- * Chapter selection
- */
-
- if( ( i_chapter > 0 ) &&
- ( i_chapter <= p_input->stream.p_selected_area->i_part_nb ) )
- {
- DVDChapterSelect( p_dvd, i_chapter );
-
- p_input->stream.p_selected_area->i_tell = p_dvd->i_start -
- p_input->stream.p_selected_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", i_chapter,
- p_input->stream.p_selected_area->i_tell );
+ intf_WarnMsg( 3, "dvd info: angle %d selected", p_area->i_angle );
}
- /* No PSM to read in DVD mode, we already have all information */
- p_input->stream.pp_programs[0]->b_is_ok = 1;
-
- vlc_mutex_unlock( &p_input->stream.stream_lock );
+ /* warn interface that something has changed */
+ p_input->stream.b_seekable = 1;
+ p_input->stream.b_changed = 1;
return 0;
}
+
/*****************************************************************************
- * DVDInit: initializes DVD structures
+ * DVDRead: reads data packets.
+ *****************************************************************************
+ * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
+ * bytes.
*****************************************************************************/
-static void DVDInit( input_thread_t * p_input )
+static int DVDRead( input_thread_t * p_input,
+ byte_t * p_buffer, size_t i_count )
{
- thread_dvd_data_t * p_dvd;
- int i_title;
- int i_chapter;
- int i_audio;
- int i_spu;
- int i;
-
- if( (p_dvd = malloc( sizeof(thread_dvd_data_t) )) == NULL )
- {
- intf_ErrMsg( "Out of memory" );
- p_input->b_error = 1;
- return;
- }
-
- p_input->p_plugin_data = (void *)p_dvd;
- p_input->p_method_data = NULL;
-
- p_dvd->i_fd = p_input->i_handle;
-
- p_dvd->i_block_once = 1;
- p_input->i_read_once = 8;
-
- p_dvd->b_encrypted = DVDCheckCSS( p_input );
+ thread_dvd_data_t * p_dvd;
+ int i_block_once;
+ int i_read_blocks;
+ int i_read_total;
+ int i_sector;
+ int i_blocks;
+ boolean_t b_eoc;
- lseek( p_input->i_handle, 0, SEEK_SET );
+ p_dvd = (thread_dvd_data_t *)(p_input->p_access_data);
- /* Reading structures initialisation */
- p_input->p_method_data =
- DVDNetlistInit( 4096, 8192, 4096, DVD_LB_SIZE, p_dvd->i_block_once );
- intf_WarnMsg( 2, "dvd info: netlist initialized" );
+ i_sector = 0;
+ i_read_total = 0;
+ i_read_blocks = 0;
+ b_eoc = 0;
- /* Ifo initialisation */
- p_dvd->ifo = IfoInit( p_input->i_handle );
- intf_WarnMsg( 2, "ifo info: vmg initialized" );
+ i_blocks = OFF2LB(i_count);
- /* CSS initialisation */
- if( p_dvd->b_encrypted )
+ while( i_blocks )
{
- p_dvd->p_css = CSSInit( p_input->i_handle );
+ i_sector = p_dvd->i_title_start + p_dvd->i_sector;
+ i_block_once = p_dvd->i_end_sector - p_dvd->i_sector + 1;
- if( p_dvd->p_css == NULL )
+ /* Get the position of the next cell if we're at cell end */
+ if( i_block_once <= 0 )
{
- intf_ErrMsg( "css error: fatal failure" );
- p_input->b_error = 1;
- return;
- }
+ int i_angle;
- intf_WarnMsg( 2, "css info: initialized" );
- }
+ p_dvd->i_cell++;
+ p_dvd->i_angle_cell++;
- /* Initialize ES structures */
- input_InitStream( p_input, sizeof( stream_ps_data_t ) );
+ /* Find cell index in adress map */
+ if( DVDFindSector( p_dvd ) < 0 )
+ {
+ intf_ErrMsg( "dvd error: can't find next cell" );
+ return 1;
+ }
- /* Set stream and area data */
- vlc_mutex_lock( &p_input->stream.stream_lock );
+ /* Position the fd pointer on the right address */
+ 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;
+ }
-#define srpt p_dvd->ifo.vmg.ptt_srpt
- intf_WarnMsg( 2, "dvd info: number of titles: %d", srpt.i_ttu_nb );
+ /* update chapter : it will be easier when we have navigation
+ * ES support */
+ if( p_dvd->i_chapter < ( p_dvd->i_chapter_nb - 1 ) )
+ {
+ if( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 )
+ {
+ i_angle = p_dvd->i_angle - 1;
+ }
+ else
+ {
+ i_angle = 0;
+ }
+ if( title.chapter_map.pi_start_cell[p_dvd->i_chapter] <=
+ ( p_dvd->i_prg_cell - i_angle + 1 ) )
+ {
+ p_dvd->i_chapter++;
+ b_eoc = 1;
+ }
+ }
-#define area p_input->stream.pp_areas
- /* We start from 1 here since area 0 is reserved for video_ts.vob */
- for( i = 1 ; i <= srpt.i_ttu_nb ; i++ )
- {
- input_AddArea( p_input );
+ i_block_once = p_dvd->i_end_sector - p_dvd->i_sector + 1;
+ }
- /* Should not be so simple eventually :
- * are title Program Chains, or still something else ? */
- area[i]->i_id = i;
+ /* The number of blocks read is the max between the requested
+ * value and the leaving block in the cell */
+ if( i_block_once > i_blocks )
+ {
+ i_block_once = i_blocks;
+ }
+ /*
+ intf_WarnMsg( 2, "Sector: 0x%x Read: %d Chapter: %d", p_dvd->i_sector, i_block_once, p_dvd->i_chapter );
+ */
- /* Absolute start offset and size
- * We can only set that with vts ifo, so we do it during the
- * first call to DVDSetArea */
- area[i]->i_start = 0;
- area[i]->i_size = 0;
+ /* Reads from DVD */
+ i_read_blocks = dvdcss_read( p_dvd->dvdhandle, p_buffer,
+ i_block_once, DVDCSS_READ_DECRYPT );
- /* Number of chapter */
- area[i]->i_part_nb = srpt.p_tts[i-1].i_ptt_nb;
- area[i]->i_part = 1;
+ i_blocks -= i_read_blocks;
+ p_buffer += LB2OFF( i_read_blocks );
+ i_read_total += i_read_blocks;
- /* Offset to vts_i_0.ifo */
- area[i]->i_plugin_data = p_dvd->ifo.i_off +
- ( srpt.p_tts[i-1].i_ssector * DVD_LB_SIZE );
- }
-#undef area
+ /* Update global position */
+ p_dvd->i_sector += i_read_blocks;
+ }
- vlc_mutex_unlock( &p_input->stream.stream_lock );
+ vlc_mutex_lock( &p_input->stream.stream_lock );
- /* Get requested title - if none try to find one where is the movie */
- i_title = main_GetIntVariable( INPUT_TITLE_VAR, 1 );
- if( i_title <= 0 || i_title > srpt.i_ttu_nb )
+ p_input->stream.p_selected_area->i_tell =
+ LB2OFF( i_sector + i_read_total ) -
+ p_input->stream.p_selected_area->i_start;
+ if( b_eoc )
{
- i_title = 1;
+ /* 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;
}
-#undef srpt
- /* Get requested chapter - if none defaults to first one */
- i_chapter = main_GetIntVariable( INPUT_CHAPTER_VAR, 1 );
- if( i_chapter <= 0 )
+ if( p_input->stream.p_selected_area->i_tell
+ >= p_input->stream.p_selected_area->i_size )
{
- i_chapter = 1;
+ if( ( p_dvd->i_title + 1 ) >= p_input->stream.i_area_nb )
+ {
+ /* EOF */
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ return 0;
+ }
+
+ /* EOT */
+ intf_WarnMsg( 4, "dvd info: new title" );
+ p_dvd->i_title++;
+ DVDSetArea( p_input, p_input->stream.pp_areas[p_dvd->i_title] );
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ return LB2OFF( i_read_total );
}
- /* For audio: first one if none or a not existing one specified */
- i_audio = main_GetIntVariable( INPUT_CHANNEL_VAR, 1 );
- if( i_audio <= 0 )
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+/*
+ if( i_read_blocks != i_block_once )
{
- main_PutIntVariable( INPUT_CHANNEL_VAR, 1 );
- i_audio = 1;
+ return -1;
}
-
- i_spu = main_GetIntVariable( INPUT_SUBTITLE_VAR, 0 );
-
- DVDSetArea( p_input, i_title, i_chapter, i_audio, i_spu );
-
- return;
-}
-
-/*****************************************************************************
- * 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;
-
- CSSEnd( p_dvd->p_css );
-// IfoEnd( p_dvd->p_ifo ) );
- free( p_dvd );
- DVDNetlistEnd( p_netlist );
+*/
+ return LB2OFF( i_read_total );
}
/*****************************************************************************
- * DVDRead: reads data packets into the netlist.
+ * DVDSeek : Goes to a given position on the stream.
*****************************************************************************
- * Returns -1 in case of error, 0 if everything went well, and 1 in case of
- * EOF.
+ * 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 int DVDRead( input_thread_t * p_input,
- data_packet_t ** pp_packets )
+static void DVDSeek( input_thread_t * p_input, off_t i_off )
{
thread_dvd_data_t * p_dvd;
- dvd_netlist_t * p_netlist;
- pgc_t * p_pgc;
- struct iovec * p_vec;
- struct data_packet_s * pp_data[p_input->i_read_once];
- u8 * pi_cur;
- int i_packet_size;
- int i_iovec;
- int i_packet;
- int i_pos;
- int i_read_bytes;
- int i_read_blocks;
+ int i_block;
+ int i_prg_cell;
+ int i_cell;
int i_chapter;
- off_t i_off;
- boolean_t b_eof;
+ int i_angle;
+
+ p_dvd = ( thread_dvd_data_t * )(p_input->p_access_data);
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ /* we have to take care of offset of beginning of title */
+ p_dvd->i_sector = OFF2LB(i_off + p_input->stream.p_selected_area->i_start)
+ - p_dvd->i_title_start;
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
- p_dvd = (thread_dvd_data_t *)p_input->p_plugin_data;
- p_netlist = (dvd_netlist_t *)p_input->p_method_data;
- p_pgc = &p_dvd->ifo.vts.pgci_ti.p_srp[p_dvd->i_vts_title-1].pgc;
+ i_prg_cell = 0;
+ i_chapter = 0;
- /* Get an iovec pointer */
- if( ( p_vec = DVDGetiovec( p_netlist ) ) == NULL )
+ /* parse vobu address map to find program cell */
+ while( title.p_cell_play[i_prg_cell].i_end_sector < p_dvd->i_sector )
{
- intf_ErrMsg( "DVD: read error" );
- return -1;
+ i_prg_cell++;
}
- /* Get the position of the next cell if we're at cell end */
+ p_dvd->i_prg_cell = i_prg_cell;
- if( p_dvd->i_sector > p_dvd->i_end_sector )
+ if( DVDChooseAngle( p_dvd ) < 0 )
{
- /* Find cell index in adress map */
- if( DVDFindSector( p_dvd ) < 0 )
- {
- pp_packets[0] = NULL;
- return 1;
- }
-
- /* 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 );
-
- i_chapter = 0;
-
- /* update chapter */
- while( p_pgc->prg_map.pi_entry_cell[i_chapter-1] - 1 <
- p_dvd->i_prg_cell )
- {
- i_chapter++;
- }
-
- p_dvd->i_chapter = i_chapter;
-
- 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;
+ p_input->b_error = 1;
+ return;
+ }
- vlc_mutex_unlock( &p_input->stream.stream_lock );
+ p_dvd->i_cell = 0;
+ /* Find first title cell which is inside program cell */
+ if( DVDFindCell( p_dvd ) < 0 )
+ {
+ /* no following cell : we're at eof */
+ intf_ErrMsg( "dvd error: cell seeking failed" );
+ p_input->b_error = 1;
+ return;
}
- /* Reads from DVD */
- i_read_bytes = readv( p_dvd->i_fd, p_vec, p_dvd->i_block_once );
- i_read_blocks = ( i_read_bytes + 0x7ff ) >> 11;
+ i_cell = p_dvd->i_cell;
- /* Update netlist indexes */
- DVDMviovec( p_netlist, i_read_blocks, pp_data );
+#define cell p_dvd->p_ifo->vts.cell_inf.p_cell_map[i_cell]
+ /* parse cell address map to find title cell containing sector */
+ while( cell.i_end_sector < p_dvd->i_sector )
+ {
+ i_cell++;
+ }
- /* Update global position */
- p_dvd->i_sector += i_read_blocks;
+ p_dvd->i_cell = i_cell;
- i_packet = 0;
+ /* if we're inside a multi-angle zone, we have to choose i_sector
+ * in the current angle ; we can't do it all the time since cells
+ * can be very wide out of such zones */
+ if( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 )
+ {
+ p_dvd->i_sector = __MAX(
+ cell.i_start_sector,
+ title.p_cell_play[p_dvd->i_prg_cell].i_start_sector );
+ }
- /* Read headers to compute payload length */
- for( i_iovec = 0 ; i_iovec < i_read_blocks ; i_iovec++ )
+ p_dvd->i_end_sector = __MIN(
+ cell.i_end_sector,
+ title.p_cell_play[p_dvd->i_prg_cell].i_end_sector );
+#undef cell
+ /* update chapter */
+ if( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 )
+ {
+ i_angle = p_dvd->i_angle - 1;
+ }
+ else
+ {
+ i_angle = 0;
+ }
+ if( p_dvd->i_chapter_nb > 1 )
{
- if( p_dvd->b_encrypted )
+ 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 ) ) )
{
- CSSDescrambleSector( p_dvd->p_css->pi_title_key,
- p_vec[i_iovec].iov_base );
- ((u8*)(p_vec[i_iovec].iov_base))[0x14] &= 0x8F;
+ i_chapter++;
}
+ }
+ else
+ {
+ i_chapter = 1;
+ }
- i_pos = 0;
-
- while( i_pos < p_netlist->i_buffer_size )
- {
- pi_cur = (u8*)(p_vec[i_iovec].iov_base + i_pos);
+ p_dvd->i_chapter = i_chapter;
- /*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 );
- }
- 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 );
- }
+ 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;
+ }
- pp_packets[i_packet] = pp_data[i_iovec];
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
+ p_input->stream.p_selected_area->i_tell =
+ LB2OFF ( i_block ) - p_input->stream.p_selected_area->i_start;
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
- }
+ intf_WarnMsg( 7, "Program Cell: %d Cell: %d Chapter: %d",
+ p_dvd->i_prg_cell, p_dvd->i_cell, p_dvd->i_chapter );
- (*pp_data[i_iovec]->pi_refcount)++;
+ return;
+}
- pp_packets[i_packet]->pi_refcount = pp_data[i_iovec]->pi_refcount;
+#define cell p_dvd->p_ifo->vts.cell_inf
- pp_packets[i_packet]->p_buffer = pp_data[i_iovec]->p_buffer;
+/*****************************************************************************
+ * DVDFindCell: adjust the title cell index with the program cell
+ *****************************************************************************/
+static int DVDFindCell( thread_dvd_data_t * p_dvd )
+{
+ int i_cell;
+ int i_index;
- pp_packets[i_packet]->p_payload_start =
- pp_packets[i_packet]->p_buffer + i_pos;
+ i_cell = p_dvd->i_cell;
+ i_index = p_dvd->i_prg_cell;
- pp_packets[i_packet]->p_payload_end =
- pp_packets[i_packet]->p_payload_start + i_packet_size + 6;
+ if( i_cell >= cell.i_cell_nb )
+ {
+ return -1;
+ }
- i_packet++;
- i_pos += i_packet_size + 6;
- }
+ while( ( ( title.p_cell_pos[i_index].i_vob_id !=
+ cell.p_cell_map[i_cell].i_vob_id ) ||
+ ( title.p_cell_pos[i_index].i_cell_id !=
+ cell.p_cell_map[i_cell].i_cell_id ) ) &&
+ ( i_cell < cell.i_cell_nb - 1 ) )
+ {
+ i_cell++;
}
- pp_packets[i_packet] = NULL;
+/*
+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,
+ cell.i_cell_nb );
+*/
- vlc_mutex_lock( &p_input->stream.stream_lock );
+ p_dvd->i_cell = i_cell;
- p_input->stream.p_selected_area->i_tell +=
- p_dvd->i_block_once *DVD_LB_SIZE;
- b_eof = p_input->stream.p_selected_area->i_tell < p_dvd->i_size ? 0 : 1;
+ return 0;
+}
- vlc_mutex_unlock( &p_input->stream.stream_lock );
+#undef cell
- if( ( i_read_blocks == p_dvd->i_block_once ) && ( !b_eof ) )
+/*****************************************************************************
+ * DVDFindSector: find cell index in adress map from index in
+ * information table program map and give corresponding sectors.
+ *****************************************************************************/
+static int DVDFindSector( thread_dvd_data_t * p_dvd )
+{
+
+ if( p_dvd->i_sector > title.p_cell_play[p_dvd->i_prg_cell].i_end_sector )
{
- return 0;
+ p_dvd->i_prg_cell++;
+
+ if( DVDChooseAngle( p_dvd ) < 0 )
+ {
+ return -1;
+ }
}
- else
+
+ if( DVDFindCell( p_dvd ) < 0 )
{
- return 1;
+ 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(
+ p_dvd->p_ifo->vts.cell_inf.p_cell_map[p_dvd->i_cell].i_start_sector,
+ title.p_cell_play[p_dvd->i_prg_cell].i_start_sector );
+ p_dvd->i_end_sector = __MIN(
+ p_dvd->p_ifo->vts.cell_inf.p_cell_map[p_dvd->i_cell].i_end_sector,
+ title.p_cell_play[p_dvd->i_prg_cell].i_end_sector );
+#else
+ p_dvd->i_sector = title.p_cell_play[p_dvd->i_prg_cell].i_start_sector;
+ p_dvd->i_end_sector = title.p_cell_play[p_dvd->i_prg_cell].i_end_sector;
+#endif
+/*
+ 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,
+ p_dvd->p_ifo->vts.cell_inf.p_cell_map[p_dvd->i_cell].i_start_sector,
+ p_dvd->p_ifo->vts.cell_inf.p_cell_map[p_dvd->i_cell].i_end_sector,
+ p_dvd->i_prg_cell,
+ title.p_cell_play[p_dvd->i_prg_cell].i_start_sector,
+ title.p_cell_play[p_dvd->i_prg_cell].i_end_sector,
+ title.p_cell_play[p_dvd->i_prg_cell].i_category,
+ title.p_cell_play[p_dvd->i_prg_cell].i_first_ilvu_vobu_esector,
+ title.p_cell_play[p_dvd->i_prg_cell].i_last_vobu_start_sector );
+*/
-/*****************************************************************************
- * DVDRewind : reads a stream backward
- *****************************************************************************/
-static int DVDRewind( input_thread_t * p_input )
-{
- return( -1 );
+ return 0;
}
/*****************************************************************************
- * 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
- * ---
- * The lock should be taken before calling this function.
+ * DVDChapterSelect: find the cell corresponding to requested chapter
*****************************************************************************/
-static void DVDSeek( input_thread_t * p_input, off_t i_off )
+static int DVDChapterSelect( thread_dvd_data_t * p_dvd, int i_chapter )
{
- thread_dvd_data_t * p_dvd;
- pgc_t * p_pgc;
- off_t i_pos;
- int i_prg_cell;
- int i_cell;
- int i_chapter;
-
- p_dvd = ( thread_dvd_data_t * )p_input->p_plugin_data;
- p_pgc = &p_dvd->ifo.vts.pgci_ti.p_srp[p_dvd->i_vts_title-1].pgc;
- /* update navigation data */
- p_dvd->i_sector = i_off >> 11;
+ /* Find cell index in Program chain for current chapter */
+ p_dvd->i_prg_cell = title.chapter_map.pi_start_cell[i_chapter-1] - 1;
+ p_dvd->i_cell = 0;
+ p_dvd->i_sector = 0;
- i_prg_cell = 0;
- i_cell = 0;
- i_chapter = 1;
+ DVDChooseAngle( p_dvd );
- /* parse vobu address map to find program cell */
- while( p_pgc->p_cell_play_inf[i_prg_cell].i_lsector < p_dvd->i_sector )
+ /* Search for cell_index in cell adress_table and initialize
+ * start sector */
+ if( DVDFindSector( p_dvd ) < 0 )
{
- i_prg_cell++;
+ intf_ErrMsg( "dvd error: can't select chapter" );
+ return -1;
}
- /* parse cell address map to find cell */
- while( p_dvd->ifo.vts.c_adt.p_cell_inf[i_cell].i_esector <=
- p_dvd->i_sector + 1 )
+
+ /* start is : beginning of vts vobs + offset to vob x */
+ p_dvd->i_start = p_dvd->i_title_start + p_dvd->i_sector;
+
+ /* Position the fd pointer on the right address */
+ if( ( p_dvd->i_start = dvdcss_seek( p_dvd->dvdhandle,
+ p_dvd->i_start,
+ DVDCSS_SEEK_MPEG ) ) < 0 )
{
- i_cell++;
+ intf_ErrMsg( "dvd error: %s", dvdcss_error( p_dvd->dvdhandle ) );
+ return -1;
}
- p_dvd->i_prg_cell = i_prg_cell;
- p_dvd->i_cell = i_cell - 1; /* DVDFindSector will add one */
-
- /* check coherence of data */
- DVDFindSector( p_dvd );
+ p_dvd->i_chapter = i_chapter;
+ return 0;
+}
- /* update chapter */
- while( p_pgc->prg_map.pi_entry_cell[i_chapter-1] - 1 < p_dvd->i_prg_cell )
+/*****************************************************************************
+ * DVDChooseAngle: select the cell corresponding to the selected angle
+ *****************************************************************************/
+static int DVDChooseAngle( thread_dvd_data_t * p_dvd )
+{
+ /* basic handling of angles */
+ switch( ( ( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 )
+ >> 12 ) )
{
- i_chapter++;
+ /* we enter a muli-angle section */
+ case 0x5:
+ p_dvd->i_prg_cell += p_dvd->i_angle - 1;
+ p_dvd->i_angle_cell = 0;
+ break;
+ /* we exit a multi-angle section */
+ case 0x9:
+ case 0xd:
+ p_dvd->i_prg_cell += p_dvd->i_angle_nb - p_dvd->i_angle;
+ break;
}
- p_dvd->i_chapter = i_chapter;
+ return 0;
+}
- /* we have to take care of offset of beginning of title */
- i_pos = i_off + p_input->stream.p_selected_area->i_start;
+#undef title
+/*****************************************************************************
+ * DVDLaunchDecoders
+ *****************************************************************************/
+static void DVDLaunchDecoders( input_thread_t * p_input )
+{
+ thread_dvd_data_t * p_dvd;
+ int i_audio;
+ int i_spu;
- /* with DVD, we have to be on a sector boundary */
- i_pos = i_pos & (~0x7ff);
+ p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
- i_pos = lseek( p_dvd->i_fd, i_pos, SEEK_SET );
+ /* Select Video stream (always 0) */
+ if( p_main->b_video )
+ {
+ input_SelectES( p_input, p_input->stream.pp_es[0] );
+ }
- p_input->stream.p_selected_area->i_tell = i_pos -
- p_input->stream.p_selected_area->i_start;
- p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
+ /* Select audio stream */
+ if( p_main->b_audio )
+ {
+ /* For audio: first one if none or a not existing one specified */
+ i_audio = config_GetIntVariable( INPUT_CHANNEL_VAR );
+ if( i_audio < 0 /*|| i_audio > i_audio_nb*/ )
+ {
+ config_PutIntVariable( INPUT_CHANNEL_VAR, 1 );
+ i_audio = 1;
+ }
+ if( i_audio > 0 /*&& i_audio_nb > 0*/ )
+ {
+ if( config_GetIntVariable( AOUT_SPDIF_VAR ) ||
+ ( config_GetIntVariable( INPUT_AUDIO_VAR ) ==
+ REQUESTED_AC3 ) )
+ {
+ int i_ac3 = i_audio;
+ while( ( p_input->stream.pp_es[i_ac3]->i_type !=
+ AC3_AUDIO_ES ) && ( i_ac3 <=
+ p_dvd->p_ifo->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] );
+ }
+ }
+ }
- return;
+ /* Select subtitle */
+ if( p_main->b_video )
+ {
+ /* for spu, default is none */
+ i_spu = config_GetIntVariable( INPUT_SUBTITLE_VAR );
+ if( i_spu < 0 /*|| i_spu > i_spu_nb*/ )
+ {
+ config_PutIntVariable( INPUT_SUBTITLE_VAR, 0 );
+ i_spu = 0;
+ }
+ if( i_spu > 0 /* && i_spu_nb > 0*/ )
+ {
+ i_spu += p_dvd->p_ifo->vts.manager_inf.i_audio_nb;
+ input_SelectES( p_input, p_input->stream.pp_es[i_spu] );
+ }
+ }
}