/*****************************************************************************
* 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:
* -dvd_udf to find files
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
- * $Id: input_dvd.c,v 1.40 2001/04/08 16:57:47 sam Exp $
+ * $Id: input_dvd.c,v 1.61 2001/05/30 17:03:12 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
#include "defs.h"
#ifdef HAVE_CSS
-#define MODULE_NAME dvd-css
+#define MODULE_NAME dvd
#else /* HAVE_CSS */
-#define MODULE_NAME dvd-nocss
+#define MODULE_NAME dvdnocss
#endif /* HAVE_CSS */
#include "modules_inner.h"
#include <sys/uio.h>
#include <string.h>
+#ifdef STRNCASECMP_IN_STRINGS_H
+# include <strings.h>
+#endif
#include <errno.h>
#include "config.h"
#include "dvd_netlist.h"
#include "dvd_ifo.h"
#include "dvd_css.h"
+#include "dvd_summary.h"
#include "input_dvd.h"
#include "mpeg_system.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", "" }
-};
-
/*****************************************************************************
* Local prototypes
*****************************************************************************/
+/* called from outside */
static int DVDProbe ( probedata_t *p_data );
-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 *, 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 * );
+/* called only inside */
+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.
#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 = NULL; /* Set in DVDInit */
+ input.pf_close = NULL;
input.pf_end = DVDEnd;
input.pf_read = DVDRead;
input.pf_set_area = DVDSetArea;
#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
*/
}
/*****************************************************************************
- * DVDFindCell: adjust the title cell index with the program cell
+ * DVDInit: initializes DVD structures
*****************************************************************************/
-static int DVDFindCell( thread_dvd_data_t * p_dvd )
+static void DVDInit( input_thread_t * p_input )
{
- int i_cell;
- int i_index;
+ thread_dvd_data_t * p_dvd;
+ input_area_t * p_area;
+ int i_title;
+ int i_chapter;
+ int i;
-#define title \
- p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_program_chain-1].title
-#define cell p_dvd->p_ifo->vts.cell_inf
+ p_dvd = malloc( sizeof(thread_dvd_data_t) );
+ if( p_dvd == NULL )
+ {
+ intf_ErrMsg( "dvd error: out of memory" );
+ p_input->b_error = 1;
+ return;
+ }
- i_cell = p_dvd->i_cell;
- i_index = p_dvd->i_prg_cell;
+ p_input->p_plugin_data = (void *)p_dvd;
+ p_input->p_method_data = NULL;
- 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 ) )
+ /* Set callback */
+ p_input->pf_open = p_input->pf_file_open;
+ p_input->pf_close = p_input->pf_file_close;
+
+ 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 = 32;
+ p_input->i_read_once = 128;
+
+ i = CSSTest( p_input->i_handle );
+
+ if( i < 0 )
{
- i_cell++;
+ intf_ErrMsg( "dvd error: error in css" );
+ free( p_dvd );
+ p_input->b_error = 1;
+ return;
}
- if( i_cell == cell.i_cell_nb )
+ p_dvd->b_encrypted = i;
+
+ lseek( p_input->i_handle, 0, SEEK_SET );
+
+ /* Reading structures initialisation */
+ p_input->p_method_data =
+ DVDNetlistInit( 2048, 4096, 2048, 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: can't find cell" );
- return -1;
+ intf_ErrMsg( "dvd error: allcation error in ifo" );
+ p_input->b_error = 1;
+ return;
}
- else
+
+ if( IfoInit( p_dvd->p_ifo ) < 0 )
{
- p_dvd->i_cell = i_cell;
- return 0;
+ intf_ErrMsg( "dvd error: fatal failure in ifo" );
+ free( p_dvd );
+ p_input->b_error = 1;
+ return;
}
-#undef title
-#undef cell
-}
-/*****************************************************************************
- * 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 )
-{
-#define title \
- p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_program_chain-1].title
+ /* 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;
+ }
- if( p_dvd->i_sector > title.p_cell_play[p_dvd->i_prg_cell].i_end_sector )
+ 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 );
+
+#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++ )
{
- p_dvd->i_prg_cell++;
+ 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_off +
+ ( title_inf.p_attr[i-1].i_start_sector * DVD_LB_SIZE );
+ }
+#undef area
+
+ /* Get requested title - if none try the first title */
+ i_title = main_GetIntVariable( INPUT_TITLE_VAR, 1 );
+ if( i_title <= 0 || i_title > title_inf.i_title_nb )
+ {
+ i_title = 1;
}
- if( DVDFindCell( p_dvd ) < 0 )
+#undef title_inf
+
+ /* Get requested chapter - if none defaults to first one */
+ i_chapter = main_GetIntVariable( INPUT_CHAPTER_VAR, 1 );
+ if( i_chapter <= 0 )
{
- intf_ErrMsg( "dvd error: can't find sector" );
- return -1;
+ i_chapter = 1;
}
- /* Find start and end sectors of new cell */
- 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 );
+ p_input->stream.pp_areas[i_title]->i_part = i_chapter;
-//intf_WarnMsg( 3, "cell: %d sector1: 0x%x end1: 0x%x\nindex: %d sector2: 0x%x end2: 0x%x", p_dvd->i_cell, p_dvd->p_ifo->p_vts->c_adt.p_cell_inf[p_dvd->i_cell].i_ssector, p_dvd->p_ifo->p_vts->c_adt.p_cell_inf[p_dvd->i_cell].i_esector, p_dvd->i_prg_cell, p_pgc->p_cell_play_inf[p_dvd->i_prg_cell].i_entry_sector, p_pgc->p_cell_play_inf[p_dvd->i_prg_cell].i_lsector );
-#undef title
+ p_area = p_input->stream.pp_areas[i_title];
- return 0;
+ /* set title, chapter, audio and subpic */
+ DVDSetArea( p_input, p_area );
+
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+ return;
}
/*****************************************************************************
- * DVDChapterSelect: find the cell corresponding to requested chapter
- * When called to find chapter 1, also sets title size and end.
+ * DVDEnd: frees unused data
*****************************************************************************/
-static int DVDChapterSelect( thread_dvd_data_t * p_dvd, int i_chapter )
+static void DVDEnd( input_thread_t * p_input )
{
-#define title \
- p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_program_chain-1].title
-
- /* 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;
-
- /* Search for cell_index in cell adress_table and initialize start sector */
- DVDFindSector( p_dvd );
+ thread_dvd_data_t * p_dvd;
+ dvd_netlist_t * p_netlist;
- /* 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 = (thread_dvd_data_t*)p_input->p_plugin_data;
+ p_netlist = (dvd_netlist_t *)p_input->p_method_data;
- /* 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->b_encrypted )
+ {
+ free( p_dvd->p_css );
+ }
- p_dvd->i_chapter = i_chapter;
-#undef title
- return 0;
+ IfoDestroy( p_dvd->p_ifo );
+ free( p_dvd );
+ DVDNetlistEnd( p_netlist );
}
/*****************************************************************************
* 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;
int i_spu;
- u16 i_id;
- u8 i_ac3;
- u8 i_mpeg;
- u8 i_sub_pic;
- u8 i;
- boolean_t b_last;
+ int i;
+ int j;
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 )
{
p_input->stream.p_selected_area =
p_input->stream.pp_areas[p_area->i_id];
- /* title number: it is not vts nb! */
+ /* release the lock to to let the interface go */
+// 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;
+ /* set number of chapters of current title */
+ p_dvd->i_chapter_nb = p_area->i_part_nb;
+
/* ifo vts */
- IfoTitleSet( p_dvd->p_ifo );
- intf_WarnMsg( 2, "ifo info: vts initialized" );
+ 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 =
- vmg.title_inf.p_attr[p_dvd->i_title-1].i_title_num;
- p_dvd->i_program_chain =
- vts.title_inf.p_title_start[p_dvd->i_vts_title-1].i_program_chain_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[i_vts_title-1].i_title_id;
+
+ intf_WarnMsg( 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;
- CSSGetKey( p_dvd->p_css );
- intf_WarnMsg( 2, "css info: vts key initialized" );
+
+ 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
+ */
+ p_dvd->i_angle_nb = vmg.title_inf.p_attr[p_dvd->i_title-1].i_angle_nb;
+ p_dvd->i_angle = main_GetIntVariable( INPUT_ANGLE_VAR, 1 );
+ if( ( p_dvd->i_angle <= 0 ) || p_dvd->i_angle > p_dvd->i_angle_nb )
+ {
+ p_dvd->i_angle = 1;
}
/*
/* last video cell */
p_dvd->i_cell = 0;
p_dvd->i_prg_cell = -1 +
- vts.title_unit.p_title[p_dvd->i_program_chain-1].title.i_cell_nb;
- DVDFindCell( 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 >= vts.cell_inf.i_cell_nb )
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 );
- DVDChapterSelect( p_dvd, 1 );
+ if( DVDChapterSelect( p_dvd, 1 ) < 0 )
+ {
+ intf_ErrMsg( "dvd error: can't find first chapter" );
+ p_input->b_error = 1;
+ return -1;
+ }
p_dvd->i_size -= (off_t)( p_dvd->i_sector + 1 ) *DVD_LB_SIZE;
- 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 );
+ IfoPrintTitle( p_dvd );
+
+// vlc_mutex_lock( &p_input->stream.stream_lock );
/* 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_angle_nb = p_dvd->i_angle_nb;
+ p_input->stream.p_selected_area->i_angle = p_dvd->i_angle;
/*
* Destroy obsolete ES by reinitializing program 0
p_es = NULL;
/* ES 0 -> video MPEG2 */
+ IfoPrintVideo( p_dvd );
+
p_es = input_AddES( p_input, p_input->stream.pp_programs[0], 0xe0, 0 );
p_es->i_stream_id = 0xe0;
p_es->i_type = MPEG2_VIDEO_ES;
p_es->i_cat = VIDEO_ES;
- input_SelectES( p_input, p_es );
- intf_WarnMsg( 1, "dvd info: video MPEG2 stream" );
+ intf_WarnMsg( 1, "dvd info: video mpeg2 stream" );
+ if( p_main->b_video )
+ {
+ input_SelectES( p_input, p_es );
+ }
+ intf_WarnMsg( 4, "dvd info: video selected" );
+#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;
-
for( i = 1 ; i <= vts.manager_inf.i_audio_nb ; i++ )
{
+ IfoPrintAudio( p_dvd, i );
-#ifdef DEBUG
- intf_WarnMsg( 1, "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 );
-#endif
-
- 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,
+ 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.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, IfoLanguage( 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 = 0xc0 + audio_status.i_position;
+ 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( 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_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, IfoLanguage( 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 */
+
+ i_id = ( ( 0xa0 + audio_status.i_position ) << 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 = 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( 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",
- vts.manager_inf.p_audio_attr[i-1].i_coding_mode );
+ 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, IfoLanguage( 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 );
+ 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;
+ /* 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_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, IfoLanguage( hton16(
vts.manager_inf.p_spu_attr[i-1].i_lang_code ) ) );
- intf_WarnMsg( 1, "dvd info: spu stream %d %s\t(0x%x)",
+ 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 );
}
}
-
- /* 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 )
- {
- main_PutIntVariable( INPUT_CHANNEL_VAR, 1 );
- i_audio = 1;
- }
- if( i_audio > 0 && vts.manager_inf.i_audio_nb > 0 )
+#undef spu_status
+ if( p_main->b_audio )
{
- input_SelectES( p_input, p_input->stream.pp_es[i_audio] );
- }
-
- /* 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 )
- {
- main_PutIntVariable( INPUT_CHANNEL_VAR, 1 );
- i_spu = 0;
+ /* 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 )
+ {
+ main_PutIntVariable( INPUT_CHANNEL_VAR, 1 );
+ i_audio = 1;
+ }
+ if( i_audio > 0 && vts.manager_inf.i_audio_nb > 0 )
+ {
+ input_SelectES( p_input, p_input->stream.pp_es[i_audio] );
+ }
}
- if( i_spu > 0 && vts.manager_inf.i_spu_nb > 0 )
+
+ if( p_main->b_video )
{
- i_spu += vts.manager_inf.i_audio_nb;
- input_SelectES( p_input, p_input->stream.pp_es[i_spu] );
+ /* 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 )
+ {
+ main_PutIntVariable( INPUT_SUBTITLE_VAR, 0 );
+ i_spu = 0;
+ }
+ if( i_spu > 0 && vts.manager_inf.i_spu_nb > 0 )
+ {
+ i_spu += vts.manager_inf.i_audio_nb;
+ input_SelectES( p_input, p_input->stream.pp_es[i_spu] );
+ }
}
} /* i_title >= 0 */
else
{
p_area = p_input->stream.p_selected_area;
}
+#undef vts
+#undef vmg
/*
* Chapter selection
*/
- if( ( p_area->i_part > 0 ) &&
- ( p_area->i_part <= p_area->i_part_nb ) )
- {
- DVDChapterSelect( p_dvd, p_area->i_part );
-
- p_input->stream.p_selected_area->i_tell = 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",
- p_area->i_part, p_area->i_tell );
- }
-
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-#undef vts
-#undef vmg
- return 0;
-}
-
-/*****************************************************************************
- * DVDInit: initializes DVD structures
- *****************************************************************************/
-static void DVDInit( input_thread_t * p_input )
-{
- thread_dvd_data_t * p_dvd;
- int i_title;
- 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 )
- {
- intf_ErrMsg( "dvd error: 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;
-
- /* 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 = 4;//128;
-
- i = CSSTest( p_input->i_handle );
-
- if( i < 0 )
- {
- intf_ErrMsg( "css error: could not get copyright bit" );
- free( p_dvd );
- p_input->b_error = 1;
- return;
- }
-
- p_dvd->b_encrypted = i;
-
- lseek( p_input->i_handle, 0, SEEK_SET );
-
- /* Reading structures initialisation */
- p_input->p_method_data =
- DVDNetlistInit( 2048, 8192, 2048, DVD_LB_SIZE, p_dvd->i_block_once );
- intf_WarnMsg( 2, "dvd info: netlist initialized" );
-
- /* Ifo initialisation */
- if( IfoInit( &p_dvd->p_ifo, p_input->i_handle ) < 0 )
- {
- intf_ErrMsg( "dvd error: fatal failure in IFO" );
- free( p_dvd );
- p_input->b_error = 1;
- return;
- }
-
- /* CSS initialisation */
- if( p_dvd->b_encrypted )
+
+ if( p_area->i_part != p_dvd->i_chapter )
{
- p_dvd->p_css = malloc( sizeof(css_t) );
- if( p_dvd->p_css == NULL )
+ if( ( p_area->i_part > 0 ) &&
+ ( p_area->i_part <= p_area->i_part_nb ))
{
- intf_ErrMsg( "dvd error: couldn't create CSS structure" );
- free( p_dvd );
- p_input->b_error = 1;
- return;
+ if( DVDChapterSelect( p_dvd, p_area->i_part ) < 0 )
+ {
+ 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 = 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",
+ p_area->i_part, p_area->i_tell );
}
-
- p_dvd->p_css->i_fd = p_input->i_handle;
- p_dvd->p_css->i_agid = 0;
-
- if( CSSInit( p_dvd->p_css ) )
+ else
{
- intf_ErrMsg( "dvd error: fatal failure in CSS" );
- free( p_dvd->p_css );
- free( p_dvd );
- p_input->b_error = 1;
- return;
+ p_area->i_part = 1;
+ p_dvd->i_chapter = 1;
}
-
- intf_WarnMsg( 2, "dvd info: CSS initialized" );
}
- /* Initialize ES structures */
- input_InitStream( p_input, sizeof( stream_ps_data_t ) );
-
- /* Set stream and area data */
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
-#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 area 0 is reserved for video_ts.vob */
- for( i = 1 ; i <= title_inf.i_title_nb ; i++ )
+#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 )
{
- 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;
-
- /* 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 );
- }
-#undef area
-
- vlc_mutex_unlock( &p_input->stream.stream_lock );
+ if( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 )
+ {
+ 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;
+
+ DVDFindSector( p_dvd );
+ p_dvd->i_cell += p_dvd->i_angle_cell;
+ }
+ else
+ {
+ p_dvd->i_angle = p_area->i_angle;
+ }
- /* Get requested title - if none try the first title */
- i_title = main_GetIntVariable( INPUT_TITLE_VAR, 1 );
- 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 = main_GetIntVariable( INPUT_CHAPTER_VAR, 1 );
- if( i_chapter <= 0 )
- {
- i_chapter = 1;
+ intf_WarnMsg( 2, "dvd info: angle %d selected", p_area->i_angle );
}
- p_input->stream.pp_areas[i_title]->i_part = i_chapter;
+ /* warn interface that something has changed */
+ p_input->stream.b_seekable = 1;
+ p_input->stream.b_changed = 1;
- /* set title, chapter, audio and subpic */
- DVDSetArea( p_input, p_input->stream.pp_areas[i_title] );
+ p_input->stream.pp_programs[0]->i_synchro_state = SYNCHRO_REINIT;
- return;
+ return 0;
}
-/*****************************************************************************
- * 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 );
- }
-
- IfoEnd( p_dvd->p_ifo );
- free( p_dvd );
- DVDNetlistEnd( p_netlist );
-}
/*****************************************************************************
* DVDRead: reads data packets into the netlist.
int i_read_blocks;
off_t i_off;
boolean_t b_eof;
+ boolean_t b_eot;
p_dvd = (thread_dvd_data_t *)p_input->p_plugin_data;
p_netlist = (dvd_netlist_t *)p_input->p_method_data;
-#define title \
- p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_program_chain-1].title
/* Get an iovec pointer */
if( ( p_vec = DVDGetiovec( p_netlist ) ) == NULL )
{
- intf_ErrMsg( "DVD: read error" );
+ intf_ErrMsg( "dvd error: can't get iovec" );
return -1;
}
/* Get the position of the next cell if we're at cell end */
if( i_block_once <= 0 )
{
+ int i_angle;
+
p_dvd->i_cell++;
+ p_dvd->i_angle_cell++;
/* Find cell index in adress map */
if( DVDFindSector( p_dvd ) < 0 )
/* update chapter : it will be easier when we have navigation
* ES support */
- if( title.chapter_map.pi_start_cell[p_dvd->i_chapter-1] <=
- p_dvd->i_prg_cell )
+ if( p_dvd->i_chapter < ( p_dvd->i_chapter_nb - 1 ) )
{
- p_dvd->i_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( title.chapter_map.pi_start_cell[p_dvd->i_chapter] <=
+ ( p_dvd->i_prg_cell - i_angle + 1 ) )
+ {
+ p_dvd->i_chapter++;
+ }
}
vlc_mutex_lock( &p_input->stream.stream_lock );
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_START;
+ p_input->stream.pp_programs[0]->i_synchro_state = SYNCHRO_REINIT;
vlc_mutex_unlock( &p_input->stream.stream_lock );
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.p_selected_area->i_tell += i_read_bytes;
- b_eof = p_input->stream.p_selected_area->i_tell < p_dvd->i_size ? 0 : 1;
+ 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 );
vlc_mutex_unlock( &p_input->stream.stream_lock );
- if( ( i_read_blocks == i_block_once ) && ( !b_eof ) )
+ if( b_eof )
{
+ return 1;
+ }
+
+ if( b_eot )
+ {
+ intf_WarnMsg( 4, "dvd info: new title" );
+ p_dvd->i_title++;
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ DVDSetArea( p_input, p_input->stream.pp_areas[p_dvd->i_title] );
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
return 0;
}
- else
+
+ if( i_read_blocks == i_block_once )
{
- return 1;
+ return 0;
}
-#undef title
-}
+ return -1;
+}
/*****************************************************************************
* DVDRewind : reads a stream backward
}
/*****************************************************************************
- * 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 )
int i_prg_cell;
int i_cell;
int i_chapter;
+ int i_angle;
p_dvd = ( thread_dvd_data_t * )p_input->p_plugin_data;
-#define title \
- p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_program_chain-1].title
/* 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_sector = i_pos >> 11;
i_prg_cell = 0;
- i_chapter = 1;
+ i_chapter = 0;
/* parse vobu address map to find program cell */
while( title.p_cell_play[i_prg_cell].i_end_sector < p_dvd->i_sector )
}
p_dvd->i_prg_cell = i_prg_cell;
+
+ if( DVDChooseAngle( p_dvd ) < 0 )
+ {
+ p_input->b_error = 1;
+ return;
+ }
+
p_dvd->i_cell = 0;
/* Find first title cell which is inside program cell */
- DVDFindCell( p_dvd );
+ 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;
+ }
i_cell = p_dvd->i_cell;
+
#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 )
p_dvd->i_cell = i_cell;
+ /* 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 );
+ }
+
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 */
- while( title.chapter_map.pi_start_cell[i_chapter-1] <= p_dvd->i_prg_cell )
+ if( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 )
+ {
+ i_angle = p_dvd->i_angle - 1;
+ }
+ else
+ {
+ 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 ) ) )
{
i_chapter++;
}
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( 1, "Program Cell: %d Cell: %d Chapter: %d",
- i_prg_cell, i_cell, p_dvd->i_chapter );
+/*
+ intf_WarnMsg( 3, "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
+ *****************************************************************************/
+static int DVDFindCell( thread_dvd_data_t * p_dvd )
+{
+ int i_cell;
+ int i_index;
+
+ i_cell = p_dvd->i_cell;
+ i_index = p_dvd->i_prg_cell;
+
+ if( i_cell >= cell.i_cell_nb )
+ {
+ return -1;
+ }
+
+ 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++;
+ }
+
+/*
+intf_WarnMsg( 3, "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 );
+*/
+
+ p_dvd->i_cell = i_cell;
+
+ return 0;
+}
+
+#undef cell
+
+/*****************************************************************************
+ * 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 )
+ {
+ p_dvd->i_prg_cell++;
+
+ if( DVDChooseAngle( p_dvd ) < 0 )
+ {
+ return -1;
+ }
+ }
+
+ if( DVDFindCell( p_dvd ) < 0 )
+ {
+ 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( 3, "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 );
+*/
+
+ return 0;
+}
+
+/*****************************************************************************
+ * DVDChapterSelect: find the cell corresponding to requested chapter
+ *****************************************************************************/
+static int DVDChapterSelect( thread_dvd_data_t * p_dvd, int i_chapter )
+{
+
+ /* 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;
+
+ DVDChooseAngle( p_dvd );
+
+ /* Search for cell_index in cell adress_table and initialize
+ * start sector */
+ if( DVDFindSector( p_dvd ) < 0 )
+ {
+ intf_ErrMsg( "dvd error: can't select chapter" );
+ return -1;
+ }
+
+ /* 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 );
+
+ /* Position the fd pointer on the right address */
+ p_dvd->i_start = lseek( p_dvd->i_fd, p_dvd->i_start, SEEK_SET );
+
+ p_dvd->i_chapter = i_chapter;
+ return 0;
+}
+
+/*****************************************************************************
+ * 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 ) )
+ {
+ /* 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;
+ }
+
+ return 0;
+}
+
+#undef title