]> git.sesse.net Git - vlc/commitdiff
-New ES detection based on .ifo for DVD module. It might fail (I have
authorStéphane Borel <stef@videolan.org>
Thu, 22 Feb 2001 08:44:45 +0000 (08:44 +0000)
committerStéphane Borel <stef@videolan.org>
Thu, 22 Feb 2001 08:44:45 +0000 (08:44 +0000)
found one DVD for which ifo seems false).

-Title and chapter selection on the command line (see -t and -T options)
It will allow to watch some DVD that went through menus by default.

-beginning of menus in gnome interface.

13 files changed:
include/config.h.in
include/input.h
plugins/dvd/dvd_css.c
plugins/dvd/dvd_ifo.c
plugins/dvd/dvd_ifo.h
plugins/dvd/input_dvd.c
plugins/dvd/input_dvd.h
plugins/gnome/gnome_callbacks.c
plugins/gnome/gnome_callbacks.h
plugins/gnome/gnome_interface.c
plugins/gnome/intf_gnome.glade
src/input/input_programs.c
src/interface/main.c

index e38845f093163319223a04f7e114bbca9ef82906..7292c8479d070354492ea6134f0dd8cca74f27bc 100644 (file)
 #define INPUT_DVD_DEVICE_VAR            "vlc_dvd_device"
 #define INPUT_DVD_DEVICE_DEFAULT        "/dev/dvd"
 
+#define INPUT_TITLE_VAR                 "vlc_input_title"
+#define INPUT_CHAPTER_VAR               "vlc_input_chapter"
 #define INPUT_AUDIO_VAR                 "vlc_input_audio"
 #define INPUT_CHANNEL_VAR               "vlc_input_channel"
 #define INPUT_SUBTITLE_VAR              "vlc_input_subtitle"
index e95ec4c4990eaabfbc111e6ae8c78defacdee8b1..655a49782dc06c81f3616bae78bef09c052abf11 100644 (file)
@@ -2,7 +2,7 @@
  * input.h: structures of the input not exported to other modules
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
- * $Id: input.h,v 1.30 2001/02/20 02:53:13 stef Exp $
+ * $Id: input.h,v 1.31 2001/02/22 08:44:45 stef Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -66,6 +66,7 @@ struct es_descriptor_s * input_AddES ( struct input_thread_s *,
                                        size_t );
 void input_DelES     ( struct input_thread_s *, struct es_descriptor_s * );
 int  input_SelectES  ( struct input_thread_s *, struct es_descriptor_s * );
+int  input_UnSelectES( struct input_thread_s *, struct es_descriptor_s * );
 
 /*****************************************************************************
  * Prototypes from input_dec.c
index 9b5c3ec22075f4f1a2e6baf17383619fa67bcfe2..9da6cd87d6b30b7ad7c4d069a9e3baf180cabc9c 100644 (file)
@@ -2,7 +2,7 @@
  * dvd_css.c: Functions for DVD authentification and unscrambling
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: dvd_css.c,v 1.14 2001/02/20 23:30:15 sam Exp $
+ * $Id: dvd_css.c,v 1.15 2001/02/22 08:44:45 stef Exp $
  *
  * Author: Stéphane Borel <stef@via.ecp.fr>
  *
@@ -1199,7 +1199,7 @@ int CSSGetKey( css_t * p_css )
      * produces multiple keys (RT)
      */
     intf_WarnMsg( 3, "CSS: Title %d key: %02X %02X %02X %02X %02X",
-                i_title + 1,
+                i_title,
                 p_title_key[i_highest].pi_key[0],
                 p_title_key[i_highest].pi_key[1],
                 p_title_key[i_highest].pi_key[2],
index d3996f402eb544b306de7869ba31b0cc53000f1c..4f6ecd565fa862a4258fa5487809aca7db35610a 100644 (file)
@@ -2,7 +2,7 @@
  * dvd_ifo.c: Functions for ifo parsing
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: dvd_ifo.c,v 1.13 2001/02/20 07:49:12 sam Exp $
+ * $Id: dvd_ifo.c,v 1.14 2001/02/22 08:44:45 stef Exp $
  *
  * Author: Stéphane Borel <stef@via.ecp.fr>
  *
@@ -528,6 +528,7 @@ static vobu_admap_t ReadMap( ifo_t* p_ifo )
 static vmgi_mat_t ReadVMGInfMat( ifo_t* p_ifo )
 {
     vmgi_mat_t  mat;
+    u64         i_temp;
     int         i;
 //    off_t     i_start = p_ifo->i_pos;
 
@@ -561,20 +562,21 @@ static vmgi_mat_t ReadVMGInfMat( ifo_t* p_ifo )
     GETL( &mat.i_c_adt_ssector );
     GETL( &mat.i_vobu_admap_ssector );
     FLUSH( 32 );
-    GETS( &mat.i_video_atrt );
+//    GETS( &mat.video_atrt );
+FLUSH(2);
     FLUSH( 1 );
     GETC( &mat.i_audio_nb );
 //fprintf( stderr, "vmgi audio nb : %d\n", mat.i_audio_nb );
     for( i=0 ; i < 8 ; i++ )
     {
-        GETLL( &mat.pi_audio_atrt[i] );
+        GETLL( &i_temp );
     }
     FLUSH( 17 );
     GETC( &mat.i_subpic_nb );
 //fprintf( stderr, "vmgi subpic nb : %d\n", mat.i_subpic_nb );
     for( i=0 ; i < mat.i_subpic_nb ; i++ )
     {
-        GET( &mat.pi_subpic_atrt[i], 6 );
+        GET( &i_temp, 6 );
         /* FIXME : take care of endianness */
     }
 
@@ -685,6 +687,7 @@ static vmg_vts_atrt_t ReadVTSAttr( ifo_t* p_ifo )
 {
     vmg_vts_atrt_t  atrt;
     int             i, j;
+    u64             i_temp;
     off_t           i_start = p_ifo->i_pos;
 
 //fprintf( stderr, "VTS ATTR\n" );
@@ -718,37 +721,39 @@ static vmg_vts_atrt_t ReadVTSAttr( ifo_t* p_ifo )
                                 SEEK_SET );
         GETL( &atrt.p_vts_atrt[i].i_ebyte );
         GETL( &atrt.p_vts_atrt[i].i_cat_app_type );
-        GETS( &atrt.p_vts_atrt[i].i_vtsm_video_atrt );
+//        GETS( &atrt.p_vts_atrt[i].vtsm_video_atrt );
+FLUSH(2);
         FLUSH( 1 );
         GETC( &atrt.p_vts_atrt[i].i_vtsm_audio_nb );
 //fprintf( stderr, "m audio nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_audio_nb );
         for( j=0 ; j<8 ; j++ )
         {
-            GETLL( &atrt.p_vts_atrt[i].pi_vtsm_audio_atrt[j] );
+            GETLL( &i_temp );
         }
         FLUSH( 17 );
         GETC( &atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
 //fprintf( stderr, "m subp nb : %d\n", atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
         for( j=0 ; j<28 ; j++ )
         {
-            GET( &atrt.p_vts_atrt[i].pi_vtsm_subpic_atrt[j], 6 );
+            GET( &i_temp, 6 );
             /* FIXME : Fix endianness issue here */
         }
         FLUSH( 2 );
-        GETS( &atrt.p_vts_atrt[i].i_vtstt_video_atrt );
+//        GETS( &atrt.p_vts_atrt[i].vtstt_video_atrt );
+FLUSH(2);
         FLUSH( 1 );
         GETL( &atrt.p_vts_atrt[i].i_vtstt_audio_nb );
 //fprintf( stderr, "tt audio nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_audio_nb );
         for( j=0 ; j<8 ; j++ )
         {
-            GETLL( &atrt.p_vts_atrt[i].pi_vtstt_audio_atrt[j] );
+            GETLL( &i_temp );
         }
         FLUSH( 17 );
         GETC( &atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
 //fprintf( stderr, "tt subp nb : %d\n", atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
         for( j=0 ; j<28/*atrt.p_vts_atrt[i].i_vtstt_subpic_nb*/ ; j++ )
         {
-            GET( &atrt.p_vts_atrt[i].pi_vtstt_subpic_atrt[j], 6 );
+            GET( &i_temp, 6 );
             /* FIXME : Fix endianness issue here */
         }
     }
@@ -825,6 +830,7 @@ static vtsi_mat_t ReadVTSInfMat( ifo_t* p_ifo )
 {
     vtsi_mat_t  mat;
     int         i;
+    u64         i_temp;
 //    off_t       i_start = p_ifo->i_pos;
 
 //fprintf( stderr, "VTSI\n" );
@@ -851,36 +857,61 @@ static vtsi_mat_t ReadVTSInfMat( ifo_t* p_ifo )
     GETL( &mat.i_c_adt_ssector );
     GETL( &mat.i_vobu_admap_ssector );
     FLUSH( 24 );
-    GETS( &mat.i_m_video_atrt );
+//    GETS( &mat.m_video_atrt );
+FLUSH(2);
     FLUSH( 1 );
     GETC( &mat.i_m_audio_nb );
     for( i=0 ; i<8 ; i++ )
     {
-        GETLL( &mat.pi_m_audio_atrt[i] );
+        GETLL( &i_temp );
     }
     FLUSH( 17 );
     GETC( &mat.i_m_subpic_nb );
     for( i=0 ; i<28 ; i++ )
     {
-        GET( &mat.pi_m_subpic_atrt[i], 6 );
+        GET( &i_temp, 6 );
         /* FIXME : take care of endianness */
     }
     FLUSH( 2 );
-    GETS( &mat.i_video_atrt );
+//    GETS( &mat.video_atrt );
+FLUSH(2);
     FLUSH( 1 );
     GETC( &mat.i_audio_nb );
 //fprintf( stderr, "vtsi audio nb : %d\n", mat.i_audio_nb );
     for( i=0 ; i<8 ; i++ )
     {
-        GETLL( &mat.pi_audio_atrt[i] );
+        GETLL( &i_temp );
+//fprintf( stderr, "Audio %d: %llx\n", i, i_temp );
+        i_temp >>= 32;
+        mat.p_audio_atrt[i].i_lang_code = i_temp & 0xffff;
+        i_temp >>= 16;
+        mat.p_audio_atrt[i].i_num_channels = i_temp & 0x7;
+        i_temp >>= 4;
+        mat.p_audio_atrt[i].i_sample_freq = i_temp & 0x3;
+        i_temp >>= 2;
+        mat.p_audio_atrt[i].i_quantization = i_temp & 0x3;
+        i_temp >>= 2;
+        mat.p_audio_atrt[i].i_appl_mode = i_temp & 0x3;
+        i_temp >>= 2;
+        mat.p_audio_atrt[i].i_type = i_temp & 0x3;
+        i_temp >>= 2;
+        mat.p_audio_atrt[i].i_multichannel_extension = i_temp & 0x1;
+        i_temp >>= 1;
+        mat.p_audio_atrt[i].i_coding_mode = i_temp & 0x7;
     }
     FLUSH( 17 );
     GETC( &mat.i_subpic_nb );
 //fprintf( stderr, "vtsi subpic nb : %d\n", mat.i_subpic_nb );
     for( i=0 ; i<mat.i_subpic_nb ; i++ )
     {
-        GET( &mat.pi_subpic_atrt[i], 6 );
-        /* FIXME : take care of endianness */
+        GET( &i_temp, 6 );
+        i_temp = hton64( i_temp ) >> 16;
+//fprintf( stderr, "Subpic %d: %llx\n", i, i_temp );
+        mat.p_subpic_atrt[i].i_caption = i_temp & 0xff;
+        i_temp >>= 16;
+        mat.p_subpic_atrt[i].i_lang_code = i_temp & 0xffff;
+        i_temp >>= 16;
+        mat.p_subpic_atrt[i].i_prefix = i_temp & 0xffff;
     }
 
     return mat;
@@ -999,7 +1030,8 @@ int IfoReadVTS( ifo_t* p_ifo )
     intf_WarnMsg( 2, "ifo: initializing VTS %d", p_ifo->i_title );
 
     i_title = p_ifo->i_title;
-    i_off = (off_t)( p_ifo->vmg.ptt_srpt.p_tts[i_title].i_ssector ) *DVD_LB_SIZE
+    i_off = (off_t)( p_ifo->vmg.ptt_srpt.p_tts[i_title-1].i_ssector )
+                   * DVD_LB_SIZE
                    + p_ifo->i_off;
 
     p_ifo->i_pos = lseek( p_ifo->i_fd, i_off, SEEK_SET );
index 9d3da34053396b073533d75432a0c75d8e533677..58e1ed6e27e66788bf4592dd600ba441177eac1d 100644 (file)
@@ -2,7 +2,7 @@
  * dvd_ifo.h: Structures for ifo parsing
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: dvd_ifo.h,v 1.7 2001/02/20 02:53:13 stef Exp $
+ * $Id: dvd_ifo.h,v 1.8 2001/02/22 08:44:45 stef Exp $
  *
  * Author: Stéphane Borel <stef@via.ecp.fr>
  *
 /*
  * Program Chain structures
  */
+typedef struct ifo_video_s
+{
+    u8      i_compression         ;// 2;
+    u8      i_system              ;// 2;
+    u8      i_ratio               ;// 2;
+    u8      i_perm_displ          ;// 2;
+
+    u8      i_line21_1            ;// 1;
+    u8      i_line21_2            ;// 1;
+    u8      i_source_res          ;// 2;
+    u8      i_letterboxed         ;// 1;
+    u8      i_mode                ;// 1;
+} ifo_video_t;
+
+/* Audio type information */
+typedef struct ifo_audio_s
+{
+    u8      i_coding_mode         ;// 3;
+    u8      i_multichannel_extension  ;// 1;
+    u8      i_type                ;// 2;
+    u8      i_appl_mode           ;// 2;
+
+    u8      i_quantization        ;// 2;
+    u8      i_sample_freq         ;// 2;
+//    u8                            ;// 1;
+    u8      i_num_channels        ;// 3;
+    u16     i_lang_code           ;// 16;   // <char> description
+    u8      i_foo                 ;// 8;    // 0x00000000 ?
+    u8      i_caption             ;// 8;
+    u8      i_bar                 ;// 8;    // 0x00000000 ?
+} ifo_audio_t;
+
+typedef struct ifo_spu_t
+{
+    u16     i_prefix              ;// 16;   // 0x0100 ?
+    u16     i_lang_code           ;// 16;   // <char> description
+    u8      i_foo                 ;// 8;    // dont know
+    u8      i_caption             ;// 8;    // 0x00 ?
+} ifo_spu_t;
+
+
 
 /* Ifo vitual machine Commands */
 typedef struct ifo_command_s
@@ -241,13 +282,13 @@ typedef struct vmgi_mat_s
     u32             i_c_adt_ssector;            // 4 bytes
     u32             i_vobu_admap_ssector;       // 4 bytes
 //    char[2]         ???
-    u16             i_video_atrt;               // 2 bytes
+    ifo_video_t     video_atrt;                 // 2 bytes
 //    char            ???
     u8              i_audio_nb;                 // 1 byte
-    u64             pi_audio_atrt[8];           // i_vmgm_audio_nb * 8 bytes
+    ifo_audio_t     p_audio_atrt[8];            // i_vmgm_audio_nb * 8 bytes
 //    char[16]        ???
     u8              i_subpic_nb;                // 1 byte
-    u64             pi_subpic_atrt[32];         // i_subpic_nb * 6 bytes
+    ifo_spu_t       p_subpic_atrt[32];          // i_subpic_nb * 6 bytes
 } vmgi_mat_t;
 
 
@@ -315,21 +356,21 @@ typedef struct vts_atrt_s
 {
     u32             i_ebyte;                    // 4 bytes
     u32             i_cat_app_type;             // 4 bytes
-    u16             i_vtsm_video_atrt;          // 2 bytes
+    ifo_video_t     vtsm_video_atrt;          // 2 bytes
 //    char            ???
     u8              i_vtsm_audio_nb;            // 1 byte
-    u64             pi_vtsm_audio_atrt[8];      // 8 * 8 bytes
+    ifo_audio_t     p_vtsm_audio_atrt[8];       // 8 * 8 bytes
 //    char[17]        ???
     u8              i_vtsm_subpic_nb;           // 1 byte
-    u64             pi_vtsm_subpic_atrt[28];    // i_vtsm_subpic_nb * 6 bytes
+    ifo_spu_t       p_vtsm_subpic_atrt[28];     // i_vtsm_subpic_nb * 6 bytes
 //    char[2]         ???
-    u16             i_vtstt_video_atrt;         // 2 bytes
+    ifo_video_t     vtstt_video_atrt;         // 2 bytes
 //    char            ???
     u8              i_vtstt_audio_nb;           // 1 byte
-    u64             pi_vtstt_audio_atrt[8];     // 8 * 8 bytes
+    ifo_audio_t     p_vtstt_audio_atrt[8];      // 8 * 8 bytes
 //    char[17]        ???
     u8              i_vtstt_subpic_nb;          // 1 byte
-    u64             pi_vtstt_subpic_atrt[28];   // i_vtstt_subpic_nb * 6 bytes
+    ifo_spu_t       p_vtstt_subpic_atrt[28];    // i_vtstt_subpic_nb * 6 bytes
 } vts_atrt_t;
 
 /* Main struct for vts attributes
@@ -388,22 +429,22 @@ typedef struct vtsi_mat_s
     u32             i_c_adt_ssector;            // 4 bytes
     u32             i_vobu_admap_ssector;       // 4 bytes
 //    char[24]        ???
-    u16             i_m_video_atrt;             // 2 bytes
+    ifo_video_t     m_video_atrt;               // 2 bytes
 //    char            ???
     u8              i_m_audio_nb;               // 1 byte
-    u64             pi_m_audio_atrt[8];         // i_vmgm_audio_nb * 8 bytes
+    ifo_audio_t     p_m_audio_atrt[8];          // i_vmgm_audio_nb * 8 bytes
 //    char[16]        ???
     u8              i_m_subpic_nb;              // 1 byte
-    u64             pi_m_subpic_atrt[32];       // i_subpic_nb * 6 bytes
+    ifo_spu_t       p_m_subpic_atrt[32];        // i_subpic_nb * 6 bytes
                                                 // !!! only 28 subpics ???
 //    char[2]         ???
-    u16             i_video_atrt;               // 2 bytes
+    ifo_video_t     video_atrt;                 // 2 bytes
 //    char            ???
     u8              i_audio_nb;                 // 1 byte
-    u64             pi_audio_atrt[8];           // i_vmgm_audio_nb * 8 bytes
+    ifo_audio_t     p_audio_atrt[8];            // i_vmgm_audio_nb * 8 bytes
 //    char[16]        ???
     u8              i_subpic_nb;                // 1 byte
-    u64             pi_subpic_atrt[32];         // i_subpic_nb * 6 bytes
+    ifo_spu_t       p_subpic_atrt[32];          // i_subpic_nb * 6 bytes
 } vtsi_mat_t;
 
 /* 
index 64d7f8907a86071cc270e39ddf2c62dfb7de02ac..ff7ae20d887887f9477e2af64271f60e6df4207c 100644 (file)
@@ -10,7 +10,7 @@
  *  -dvd_udf to find files
  *****************************************************************************
  * Copyright (C) 1998-2001 VideoLAN
- * $Id: input_dvd.c,v 1.18 2001/02/20 23:30:15 sam Exp $
+ * $Id: input_dvd.c,v 1.19 2001/02/22 08:44:45 stef Exp $
  *
  * Author: Stéphane Borel <stef@via.ecp.fr>
  *
@@ -278,11 +278,12 @@ void _M( input_getfunctions )( function_list_t * p_function_list )
 /*****************************************************************************
  * Language: gives the long language name from the two-letters ISO-639 code
  *****************************************************************************/
-static char * Language( char * p_code )
+static char * Language( u16 i_code )
 {
     int     i = 0;
 
-    while( !memcmp( lang_tbl[i].p_code, p_code, 2 ) && lang_tbl[i].p_lang_long )
+    while( memcmp( lang_tbl[i].p_code, &i_code, 2 ) &&
+           lang_tbl[i].p_lang_long[0] )
     {
         i++;
     }
@@ -336,291 +337,316 @@ static int DVDCheckCSS( input_thread_t * p_input )
 }
 
 /*****************************************************************************
- * 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.
- * ---
- * Take care that i_title and i_chapter start from 0.
+ * DVDChapterSelect: find the cell corresponding to requested chapter
  *****************************************************************************/
-static int DVDSetArea( input_thread_t * p_input,
-                       int i_title, int i_chapter,
-                       int i_audio, int i_spu )
+static int DVDChapterSelect( thread_dvd_data_t * p_dvd, int i_chapter )
 {
-    thread_dvd_data_t *  p_method;
-//    es_descriptor_t *    p_es;
-    off_t                i_start;
-    off_t                i_size;
     pgc_t *              p_pgc;
     int                  i_start_cell;
     int                  i_end_cell;
     int                  i_index;
     int                  i_cell;
-//    int                  i_nb;
-//    int                  i_id;
-//    int                  i;
-    
-    p_method = (thread_dvd_data_t*)p_input->p_plugin_data;
 
-    /* Ifo structures reading */
-    p_method->ifo.i_title = i_title;
-    IfoReadVTS( &(p_method->ifo) );
-    intf_WarnMsg( 2, "Ifo: VTS initialized" );
+    p_pgc = &p_dvd->ifo.vts.pgci_ti.p_srp[0].pgc;
 
-    if( p_method->b_encrypted )
-    {
-        p_method->css.i_title = i_title;
-        p_method->css.i_title_pos =
-                p_method->ifo.vts.i_pos +
-                p_method->ifo.vts.mat.i_tt_vobs_ssector * DVD_LB_SIZE;
-        CSSGetKey( &(p_method->css) );
-        intf_WarnMsg( 2, "CSS: VTS key initialized" );
-    }
-
-    /* Set selected title start and size */
-    p_pgc = &p_method->ifo.vts.pgci_ti.p_srp[0].pgc;
-
-    /* Find cell index in Program chain */
-    i_index = p_pgc->prg_map.pi_entry_cell[i_chapter] - 1;
+    /* Find cell index in Program chain for current chapter */
+    i_index = p_pgc->prg_map.pi_entry_cell[i_chapter-1] - 1;
 
     /* Search for cell_index in cell adress_table */
     i_cell = 0;
     while( p_pgc->p_cell_pos_inf[i_index].i_vob_id >
-           p_method->ifo.vts.c_adt.p_cell_inf[i_cell].i_vob_id )
+           p_dvd->ifo.vts.c_adt.p_cell_inf[i_cell].i_vob_id )
     {
         i_cell++;
     }
     while( p_pgc->p_cell_pos_inf[i_index].i_cell_id >
-           p_method->ifo.vts.c_adt.p_cell_inf[i_cell].i_cell_id )
+           p_dvd->ifo.vts.c_adt.p_cell_inf[i_cell].i_cell_id )
     {
         i_cell++;
     }
-    i_start_cell = i_cell;
-    i_end_cell = i_start_cell + p_pgc->i_cell_nb - 1;
-
-    intf_WarnMsg( 3, "DVD: Start cell: %d End Cell: %d",
-                                            i_start_cell, i_end_cell );
 
-    p_method->i_start_cell = i_start_cell;
-    p_method->i_end_cell = i_end_cell;
+    i_start_cell = i_cell;
 
-    /* start is : beginning of vts + offset to vobs + offset to vob x */
-    i_start = p_method->ifo.vts.i_pos + DVD_LB_SIZE *
-            ( p_method->ifo.vts.mat.i_tt_vobs_ssector +
-              p_method->ifo.vts.c_adt.p_cell_inf[i_start_cell].i_ssector );
+    p_dvd->i_start = p_dvd->ifo.vts.i_pos + DVD_LB_SIZE *
+            (off_t)( p_dvd->ifo.vts.mat.i_tt_vobs_ssector +
+                     p_dvd->ifo.vts.c_adt.p_cell_inf[i_start_cell].i_ssector );
 
-    i_start = lseek( p_input->i_handle, i_start, SEEK_SET );
-    intf_WarnMsg( 2, "DVD: VOBstart at: %lld", i_start );
+    if( i_chapter == 1 )
+    {
+        i_end_cell = i_start_cell + p_pgc->i_cell_nb - 1;
+        p_dvd->i_size = (off_t)DVD_LB_SIZE *
+            ( p_dvd->ifo.vts.c_adt.p_cell_inf[i_end_cell].i_esector -
+              p_dvd->ifo.vts.c_adt.p_cell_inf[i_start_cell].i_ssector + 1 );
+        p_dvd->i_chapter_nb = p_pgc->i_cell_nb;
+        intf_WarnMsg( 3, "DVD: Start cell: %d End Cell: %d",
+                                            i_start_cell, i_end_cell );
+    }
 
-    i_size = (off_t)
-        ( p_method->ifo.vts.c_adt.p_cell_inf[i_end_cell].i_esector -
-          p_method->ifo.vts.c_adt.p_cell_inf[i_start_cell].i_ssector + 1 )
-        *DVD_LB_SIZE;
-    intf_WarnMsg( 2, "DVD: stream size: %lld", i_size );
+    return 0;
+}
 
-#if 0
-    p_es = NULL;
+/*****************************************************************************
+ * 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.
+ * ---
+ * 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
+ *****************************************************************************/
+static int DVDSetArea( input_thread_t * p_input,
+                       int i_title, int i_chapter,
+                       int i_audio, int i_spu )
+{
+    thread_dvd_data_t *  p_method;
+    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_method = (thread_dvd_data_t*)p_input->p_plugin_data;
 
     vlc_mutex_lock( &p_input->stream.stream_lock );
 
-    /* ES 0 -> video MPEG2 */
-    intf_WarnMsg( 1, "DVD: Video MPEG2 stream" );
-    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;
-    input_SelectES( p_input, p_es );
-
-    /* Audio ES, in the order they appear in .ifo */
-    i_nb = p_method->ifo.vts.mat.i_audio_nb;
-    intf_WarnMsg( 1, "DVD: Audio streams %d", i_nb );
-    for( i = 0 ; i < i_nb ; i++ )
+    if( i_title >= 0 )
     {
-        i_id = ( ( 0x80 + i ) << 8 ) | 0xbd;
-        p_es = input_AddES( p_input,
-                           p_input->stream.pp_programs[0], i_id, 0 );
-        p_es->i_stream_id = 0xbd;
-        p_es->i_type = AC3_AUDIO_ES;
-        p_es->b_audio = 1;
-//        p_es->psz_desc = p_method->ifo.vts.mat.pi_audio_attr[i];
-        if( i == 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];
+
+        /* Ifo VTS, and CSS reading */
+        p_method->ifo.i_title = i_title;
+        IfoReadVTS( &(p_method->ifo) );
+        intf_WarnMsg( 2, "Ifo: VTS initialized" );
+    
+        if( p_method->b_encrypted )
         {
-            input_SelectES( p_input, p_es );
+            p_method->css.i_title = i_title;
+            p_method->css.i_title_pos =
+                    p_method->ifo.vts.i_pos +
+                    p_method->ifo.vts.mat.i_tt_vobs_ssector * DVD_LB_SIZE;
+            CSSGetKey( &(p_method->css) );
+            intf_WarnMsg( 2, "CSS: VTS key initialized" );
         }
-    }
-
-    /* Sub Picture ES */
-    i_nb = p_method->ifo.vts.mat.i_subpic_nb;
-    intf_WarnMsg( 1, "DVD: Subpic streams %d", i_nb );
-    for( i = 0 ; i < i_nb ; i++ )
-    {
-        i_id = ( ( 0x20 + 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 = DVD_SPU_ES;
-//        p_es->psz_desc = p_method->ifo.vts.mat.pi_subpic_attr[i];
-        if( i == 12 )
+    
+        /*
+         * Set selected title start and size
+         */
+        DVDChapterSelect( p_method, 1 );
+    
+        /* start is : beginning of vts + offset to vobs + offset to vob x */
+            
+        p_method->i_start =
+                    lseek( p_input->i_handle, p_method->i_start, SEEK_SET );
+
+        intf_WarnMsg( 2, "DVD: vobstart at: %lld", p_method->i_start );
+        intf_WarnMsg( 2, "DVD: stream size: %lld", p_method->i_size );
+        intf_WarnMsg( 2, "DVD: number of chapters: %lld",
+                                                   p_method->i_chapter_nb );
+
+        /* Area definition */
+        p_input->stream.p_selected_area->i_start = p_method->i_start;
+        p_input->stream.p_selected_area->i_size = p_method->i_size;
+        p_input->stream.p_selected_area->i_part_nb = p_method->i_chapter_nb;
+
+        /*
+         * Destroy obsolete ES by reinitializing program 0
+         * and find all ES in title with ifo data
+         */
+        if( p_input->stream.pp_programs != NULL )
         {
-            input_SelectES( p_input, p_es );
+            input_DelProgram( p_input, p_input->stream.pp_programs[0] );
         }
 
-    }
-
-    /* area definition */
-    p_input->stream.pp_areas[i_title]->i_start = i_start;
-    p_input->stream.pp_areas[i_title]->i_size = i_size;
-
-    /* No PSM to read in DVD mode */
-    p_input->stream.pp_programs[0]->b_is_ok = 1;
+        input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
 
-    /* Init has been successfull ; change the default area */
-    p_input->stream.p_selected_area = p_input->stream.pp_areas[i_title];
+        p_es = NULL;
 
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
+        /* ES 0 -> video MPEG2 */
+        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;
+        input_SelectES( p_input, p_es );
+        intf_WarnMsg( 1, "DVD: Video MPEG2 stream" );
+    
+        /* Audio ES, in the order they appear in .ifo */
+        i_nb = p_method->ifo.vts.mat.i_audio_nb;
+    
+        i_ac3 = 0x80;
+        i_mpeg = 0xc0;
 
-#else
-    p_input->stream.p_selected_area = p_input->stream.pp_areas[0]; 
+        for( i = 1 ; i <= i_nb ; i++ )
+        {
 
-    if( p_input->stream.b_seekable )
-    {
-        stream_ps_data_t * p_demux_data =
-             (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
+#if 0
+    fprintf( stderr, "Audio %d: %x %x %x %x %x %x\n", i,
+            p_method->ifo.vts.mat.p_audio_atrt[i].i_coding_mode,
+            p_method->ifo.vts.mat.p_audio_atrt[i].i_multichannel_extension,
+            p_method->ifo.vts.mat.p_audio_atrt[i].i_type,
+            p_method->ifo.vts.mat.p_audio_atrt[i].i_appl_mode,
+            p_method->ifo.vts.mat.p_audio_atrt[i].i_foo,
+            p_method->ifo.vts.mat.p_audio_atrt[i].i_bar );
+#endif
 
-        /* Pre-parse the stream to gather stream_descriptor_t. */
-        p_input->stream.pp_programs[0]->b_is_ok = 0;
-        p_demux_data->i_PSM_version = EMPTY_PSM_VERSION;
+            switch( p_method->ifo.vts.mat.p_audio_atrt[i].i_coding_mode )
+            {
+            case 0x00:              /* AC3 */
+                i_id = ( ( 0x7f + 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_method->ifo.vts.mat.p_audio_atrt[i-1].i_lang_code ) ) ); 
 
-        while( !p_input->b_die && !p_input->b_error
-                && !p_demux_data->b_has_PSM )
-        {
-            int                 i_result, i;
-            data_packet_t *     pp_packets[INPUT_READ_ONCE];
+                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_method->ifo.vts.mat.p_audio_atrt[i-1].i_lang_code ) ) ); 
 
-            i_result = DVDRead( p_input, pp_packets );
-            if( i_result == 1 )
-            {
-                /* EOF */
-                vlc_mutex_lock( &p_input->stream.stream_lock );
-                p_input->stream.pp_programs[0]->b_is_ok = 1;
-                vlc_mutex_unlock( &p_input->stream.stream_lock );
                 break;
-            }
-            if( i_result == -1 )
-            {
-                p_input->b_error = 1;
+            case 0x04:              /* LPCM */
+                i_id = 0;
+                intf_ErrMsg( "DVD: LPCM audio not handled yet" );
+                break;
+            case 0x06:              /* DTS */
+                i_id = 0;
+                intf_ErrMsg( "DVD: DTS audio not handled yet" );
                 break;
+            default:
+                i_id = 0;
+                intf_ErrMsg( "DVD: unkown audio" );
             }
-
-            for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ )
+        
+            intf_WarnMsg( 1, "DVD: Audio stream %d %s\t(0x%x)",
+                          i, p_es->psz_desc, i_id );
+        }
+    
+        /* Sub Picture ES */
+        i_nb = p_method->ifo.vts.mat.i_subpic_nb;
+    
+        b_last = 0;
+        i_sub_pic = 0x20;
+        for( i = 1 ; i <= i_nb ; i++ )
+        {
+            if( !b_last )
             {
-                /* FIXME: use i_p_config_t */
-                input_ParsePS( p_input, pp_packets[i] );
-                input_NetlistDeletePacket( p_input->p_method_data,
-                                           pp_packets[i] );
+                i_id = ( i_sub_pic++ << 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;
+                strcpy( p_es->psz_desc, Language( hton16(
+                    p_method->ifo.vts.mat.p_subpic_atrt[i-1].i_lang_code ) ) ); 
+                intf_WarnMsg( 1, "DVD: 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_method->ifo.vts.mat.p_subpic_atrt[i].i_prefix == 0 ); 
             }
+        }
+
+    } // i_title >= 0
 
-            /* File too big. */
-            if( p_input->stream.p_selected_area->i_tell >
-                                                    INPUT_PREPARSE_LENGTH )
+    /*
+     * 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_method->ifo.vts.mat.i_audio_nb )
+        {
+            i_audio = 1;
+        }
+
+        p_es = p_input->stream.pp_programs[0]->pp_es[i_audio];
+
+        /* 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;
             }
         }
-        lseek( p_input->i_handle, i_start, SEEK_SET );
-        vlc_mutex_lock( &p_input->stream.stream_lock );
 
-        /* i_tell is an indicator from the beginning of the stream,
-         * not of the DVD */
-        p_input->stream.p_selected_area->i_tell = 0;
-
-        if( p_demux_data->b_has_PSM )
+        if( i_index != -1 )
         {
-            /* (The PSM decoder will care about spawning the decoders) */
-            p_input->stream.pp_programs[0]->b_is_ok = 1;
+            
+            if( p_input->stream.pp_selected_es[i_index] != p_es )
+            {
+                input_UnSelectES( p_input,
+                                  p_input->stream.pp_selected_es[i_index] );
+                input_SelectES( p_input, p_es );
+                intf_WarnMsg( 1, "DVD: Audio %d selected -> %s (0x%x)",
+                              i_audio, p_es->psz_desc, p_es->i_id );
+            }
         }
-#ifdef AUTO_SPAWN
         else
         {
-            /* (We have to do it ourselves) */
-            int                 i_es;
-
-            /* FIXME: we should do multiple passes in case an audio type
-             * is not present */
-            for( i_es = 0;
-                 i_es < p_input->stream.pp_programs[0]->i_es_number;
-                 i_es++ )
-            {
-#define p_es p_input->stream.pp_programs[0]->pp_es[i_es]
-                switch( p_es->i_type )
-                {
-                    case MPEG1_VIDEO_ES:
-                    case MPEG2_VIDEO_ES:
-                        input_SelectES( p_input, p_es );
-                        break;
-
-                    case MPEG1_AUDIO_ES:
-                    case MPEG2_AUDIO_ES:
-                        if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 )
-                                == (p_es->i_id & 0x1F) )
-                        switch( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) )
-                        {
-                        case 0:
-                            main_PutIntVariable( INPUT_AUDIO_VAR,
-                                                 REQUESTED_MPEG );
-                        case REQUESTED_MPEG:
-                            input_SelectES( p_input, p_es );
-                        }
-                        break;
-
-                    case AC3_AUDIO_ES:
-                        if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 )
-                                == ((p_es->i_id & 0xF00) >> 8) )
-                        switch( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) )
-                        {
-                        case 0:
-                            main_PutIntVariable( INPUT_AUDIO_VAR,
-                                                 REQUESTED_AC3 );
-                        case REQUESTED_AC3:
-                            input_SelectES( p_input, p_es );
-                        }
-                        break;
-
-                    case DVD_SPU_ES:
-                        if( main_GetIntVariable( INPUT_SUBTITLE_VAR, -1 )
-                                == ((p_es->i_id & 0x1F00) >> 8) )
-                        {
-                            input_SelectES( p_input, p_es );
-                        }
-                        break;
-
-                    case LPCM_AUDIO_ES:
-                        /* FIXME ! */
-                        break;
-                }
-            }
-                    
+            input_SelectES( p_input, p_es );
+            intf_WarnMsg( 1, "DVD: Audio %d selected -> %s (0x%x)",
+                          i_audio, p_es->psz_desc, p_es->i_id );
         }
-#endif
-#ifdef STATS
-        input_DumpStream( p_input );
-#endif
-
-        /* FIXME : ugly kludge */
-        p_input->stream.p_selected_area->i_size = i_size;
+    }
 
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
+    if( ( i_spu >= 0 ) || ( i_title >= 0 ) )
+    {
+        /* For spu: no one if none or a not existed one requested */
+        if( ( i_spu <= p_method->ifo.vts.mat.i_subpic_nb ) && ( i_spu > 0 ) )
+        {
+            input_SelectES( p_input, ( p_es = p_input->stream.pp_programs[0]->
+                pp_es[ i_spu + p_method->ifo.vts.mat.i_audio_nb ] ) );
+    
+            intf_WarnMsg( 1, "DVD: SPU   %d selected -> %s (0x%x)",
+                          i_spu, p_es->psz_desc, p_es->i_id );
+        }
     }
-    else
+
+    /*
+     * Chapter selection
+     */
+
+    if( ( i_chapter > 0 ) &&
+        ( i_chapter <= p_input->stream.p_selected_area->i_part_nb ) )
     {
-        /* The programs will be added when we read them. */
-        vlc_mutex_lock( &p_input->stream.stream_lock );
-        p_input->stream.pp_programs[0]->b_is_ok = 0;
+        DVDChapterSelect( p_method, i_chapter );
+
+        p_input->stream.p_selected_area->i_part = i_chapter; 
 
-        /* FIXME : ugly kludge */
-        p_input->stream.p_selected_area->i_size = i_size;
+        DVDSeek( p_input, p_method->i_start -
+                          p_input->stream.p_selected_area->i_start );
 
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        intf_WarnMsg( 2, "DVD: Chapter %d start at: %lld", i_chapter,
+                                    p_input->stream.p_selected_area->i_tell );
     }
-#endif  
+
+    /* 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 );
 
     return 0;
 }
@@ -631,6 +657,10 @@ static int DVDSetArea( input_thread_t * p_input,
 static void DVDInit( input_thread_t * p_input )
 {
     thread_dvd_data_t *  p_method;
+    int                  i_title;
+    int                  i_chapter;
+    int                  i_audio;
+    int                  i_spu;
     int                  i;
 
     if( (p_method = malloc( sizeof(thread_dvd_data_t) )) == NULL )
@@ -674,7 +704,6 @@ static void DVDInit( input_thread_t * p_input )
 
     /* Initialize ES structures */
     input_InitStream( p_input, sizeof( stream_ps_data_t ) );
-    input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
 
     /* Set stream and area data */
     vlc_mutex_lock( &p_input->stream.stream_lock );
@@ -682,9 +711,12 @@ static void DVDInit( input_thread_t * p_input )
     /* FIXME: We consider here that one title is one title set
      * it is not true !!! */
 
+    intf_WarnMsg( 2, "DVD: Number of titles: %d\n",
+                  p_method->ifo.vmg.mat.i_tts_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 < p_method->ifo.vmg.mat.i_tts_nb ; i++ )
+    for( i = 1 ; i <= p_method->ifo.vmg.mat.i_tts_nb ; i++ )
     {
         input_AddArea( p_input );
 
@@ -709,10 +741,32 @@ static void DVDInit( input_thread_t * p_input )
 
     vlc_mutex_unlock( &p_input->stream.stream_lock );
 
-    /* By default, set all parameters to 0 */
-    /* FIXME: wrong kludge to get first title number */
-    DVDSetArea( p_input, p_method->ifo.vmg.ptt_srpt.p_tts[0].i_tts_nb - 1,
-                0, 0, 0 );
+    /* Get requested title - if none try to find one where is the movie */
+    i_title = main_GetIntVariable( INPUT_TITLE_VAR,
+                              p_method->ifo.vmg.ptt_srpt.p_tts[0].i_tts_nb );
+    if( i_title <= 0 || i_title >= p_method->ifo.vmg.mat.i_tts_nb )
+    {
+        i_title = p_method->ifo.vmg.ptt_srpt.p_tts[0].i_tts_nb;
+    }
+
+    /* Get requested chapter - if none defaults to first one */
+    i_chapter = main_GetIntVariable( INPUT_CHAPTER_VAR, 1 );
+    if( i_chapter <= 0 )
+    {
+        i_chapter = 1;
+    }
+
+    /* For audio: first one if none or a not existing one specified */
+    i_audio = main_GetIntVariable( INPUT_CHANNEL_VAR, 1 );
+    if( i_audio <= 0 )
+    {
+        main_PutIntVariable( INPUT_CHANNEL_VAR, 1 );
+        i_audio = 1;
+    }
+
+    i_spu = main_GetIntVariable( INPUT_SUBTITLE_VAR, 0 );
+
+    DVDSetArea( p_input, i_title, i_chapter, i_audio, i_spu );
 
     return;
 }
@@ -739,102 +793,120 @@ static void DVDEnd( input_thread_t * p_input )
 static int DVDRead( input_thread_t * p_input,
                    data_packet_t ** pp_packets )
 {
-    thread_dvd_data_t *     p_method;
-    netlist_t *             p_netlist;
-    struct iovec *          p_vec;
-    struct data_packet_s *  p_data;
-    u8 *                    pi_cur;
-    int                     i_packet_size;
-    int                     i_packet;
-    int                     i_pos;
-    int                     i;
-    boolean_t               b_first_packet;
-
-    p_method = ( thread_dvd_data_t * ) p_input->p_plugin_data;
-    p_netlist = ( netlist_t * ) p_input->p_method_data;
-
-    /* Get an iovec pointer */
-    if( ( p_vec = input_NetlistGetiovec( p_netlist ) ) == NULL )
-    {
-        intf_ErrMsg( "DVD: read error" );
-        return -1;
-    }
+    byte_t              p_header[6];
+    data_packet_t *     p_data;
+    size_t              i_packet_size;
+    int                 i_packet, i_error;
+    thread_dvd_data_t * p_method;
 
-    /* Reads from DVD */
-    readv( p_input->i_handle, p_vec, p_method->i_read_once );
+    p_method = (thread_dvd_data_t *)p_input->p_plugin_data;
 
-    if( p_method->b_encrypted )
+    memset( pp_packets, 0, INPUT_READ_ONCE * sizeof(data_packet_t *) );
+    for( i_packet = 0; i_packet < INPUT_READ_ONCE; i_packet++ )
     {
-        for( i=0 ; i<p_method->i_read_once ; i++ )
+        /* Read what we believe to be a packet header. */
+        if( (i_error = SafeRead( p_input, p_header, 6 )) )
         {
-            CSSDescrambleSector( p_method->css.pi_title_key, 
-                                 p_vec[i].iov_base );
-            ((u8*)(p_vec[i].iov_base))[0x14] &= 0x8F;
+            return( i_error );
         }
-    }
 
-    /* Update netlist indexes */
-    input_NetlistMviovec( p_netlist, p_method->i_read_once, &p_data );
-
-    i_packet = 0;
-    /* Read headers to compute payload length */
-    for( i = 0 ; i < p_method->i_read_once ; i++ )
-    {
-        i_pos = 0;
-        b_first_packet = 1;
-        while( i_pos < p_netlist->i_buffer_size )
+        if( (U32_AT(p_header) & 0xFFFFFF00) != 0x100L )
         {
-            pi_cur = (u8*)(p_vec[i].iov_base + i_pos);
-            /*default header */
-            if( U32_AT( pi_cur ) != 0x1BA )
+            /* This is not the startcode of a packet. Read the stream
+             * until we find one. */
+            u32         i_startcode = U32_AT(p_header);
+            int         i_nb;
+            byte_t      i_dummy;
+
+            if( i_startcode )
             {
-                /* That's the case for all packets, except pack header. */
-                i_packet_size = U16_AT( pi_cur + 4 );
+                /* It is common for MPEG-1 streams to pad with zeros
+                 * (although it is forbidden by the recommendation), so
+                 * don't bother everybody in this case. */
+                intf_WarnMsg( 1, "Garbage at input (%x)", i_startcode );
             }
-            else
+
+            while( (i_startcode & 0xFFFFFF00) != 0x100L )
             {
-                /* Pack header. */
-                if( ( pi_cur[4] & 0xC0 ) == 0x40 )
-                {
-                    /* MPEG-2 */
-                    i_packet_size = 8;
-                }
-                else if( ( pi_cur[4] & 0xF0 ) == 0x20 )
+                i_startcode <<= 8;
+                if( (i_nb = SafeRead( p_input, &i_dummy, 1 )) != 0 )
                 {
-                    /* MPEG-1 */
-                    i_packet_size = 6;
+                    i_startcode |= i_dummy;
                 }
                 else
                 {
-                    intf_ErrMsg( "Unable to determine stream type" );
-                    return( -1 );
+                    return( 1 );
                 }
             }
-            if( b_first_packet )
+
+            /* Packet found. */
+            *(u32 *)p_header = U32_AT(&i_startcode);
+            if( (i_error = SafeRead( p_input, p_header + 4, 2 )) )
+            {
+                return( i_error );
+            }
+        }
+
+        if( U32_AT(p_header) != 0x1BA )
+        {
+            /* That's the case for all packets, except pack header. */
+            i_packet_size = U16_AT(&p_header[4]);
+        }
+        else
+        {
+            /* Pack header. */
+            if( (p_header[4] & 0xC0) == 0x40 )
             {
-                p_data->b_discard_payload = 0;
-                b_first_packet = 0;
+                /* MPEG-2 */
+                i_packet_size = 8;
+            }
+            else if( (p_header[4] & 0xF0) == 0x20 )
+            {
+                /* MPEG-1 */
+                i_packet_size = 6;
             }
             else
-            { 
-                p_data = input_NetlistNewPacket( p_netlist ,
-                                                 i_packet_size + 6 );
-                memcpy( p_data->p_buffer,
-                        p_vec[i].iov_base + i_pos , i_packet_size + 6 );
+            {
+                intf_ErrMsg( "Unable to determine stream type" );
+                return( -1 );
             }
+        }
 
-            p_data->p_payload_end = p_data->p_payload_start + i_packet_size + 6;
-            pp_packets[i_packet] = p_data;
-            i_packet++;
-            i_pos += i_packet_size + 6;
+        /* Fetch a packet of the appropriate size. */
+        if( (p_data = NewPacket( p_input, i_packet_size + 6 )) == NULL )
+        {
+            intf_ErrMsg( "Out of memory" );
+            return( -1 );
         }
-    }
-    pp_packets[i_packet] = NULL;
 
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-    p_input->stream.p_selected_area->i_tell +=
-                                        p_method->i_read_once *DVD_LB_SIZE;
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
+        /* Copy the header we already read. */
+        memcpy( p_data->p_buffer, p_header, 6 );
+
+        /* Read the remaining of the packet. */
+        if( i_packet_size && (i_error =
+                SafeRead( p_input, p_data->p_buffer + 6, i_packet_size )) )
+        {
+            return( i_error );
+        }
+
+        /* In MPEG-2 pack headers we still have to read stuffing bytes. */
+        if( U32_AT(p_header) == 0x1BA )
+        {
+            if( i_packet_size == 8 && (p_data->p_buffer[13] & 0x7) != 0 )
+            {
+                /* MPEG-2 stuffing bytes */
+                byte_t      p_garbage[8];
+                if( (i_error = SafeRead( p_input, p_garbage,
+                                         p_data->p_buffer[13] & 0x7)) )
+                {
+                    return( i_error );
+                }
+            }
+        }
+
+        /* Give the packet to the other input stages. */
+        pp_packets[i_packet] = p_data;
+    }
 
     return( 0 );
 }
index 9eb97b1157d9d1680e670a9344323da7944948df..8c2cee89eba900b6247f7d3692843c25a761c223 100644 (file)
@@ -35,9 +35,9 @@ typedef struct thread_dvd_data_s
     boolean_t               b_encrypted;        // CSS encryption
     int                     i_read_once;        // NB of bytes read by DVDRead
 
-    int                     i_start_byte;
-    int                     i_start_cell;
-    int                     i_end_cell;
+    int                     i_chapter_nb;
+    off_t                   i_start;
+    off_t                   i_size;
 
     /* Scrambling Information */
     struct css_s            css;
index 5bcad8632de721ae5d8bc265164f5fe095874d2f..7f410d6de9be81e28a7ad826f2aafde1f8798205 100644 (file)
@@ -584,3 +584,51 @@ on_intf_window_drag_data_received      (GtkWidget       *widget,
     }
 }
 
+
+void
+on_menubar_audio_activate              (GtkMenuItem     *menuitem,
+                                        gpointer         user_data)
+{
+
+}
+
+
+void
+on_menubar_subtitles_activate          (GtkMenuItem     *menuitem,
+                                        gpointer         user_data)
+{
+
+}
+
+
+void
+on_popup_title_activate                (GtkMenuItem     *menuitem,
+                                        gpointer         user_data)
+{
+
+}
+
+
+void
+on_popup_chapter_activate              (GtkMenuItem     *menuitem,
+                                        gpointer         user_data)
+{
+
+}
+
+
+void
+on_popup_audio_activate                (GtkMenuItem     *menuitem,
+                                        gpointer         user_data)
+{
+
+}
+
+
+void
+on_popup_subtitle_activate             (GtkMenuItem     *menuitem,
+                                        gpointer         user_data)
+{
+
+}
+
index f39fb396fa23801decfcec799ec86894594e88c0..57e91e16ca7fd68eadd08b1d67fe87e2f5e0a15e 100644 (file)
@@ -197,3 +197,27 @@ on_intf_window_drag_data_received      (GtkWidget       *widget,
                                         guint            info,
                                         guint            time,
                                         gpointer         user_data);
+
+void
+on_menubar_audio_activate              (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_menubar_subtitles_activate          (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_popup_title_activate                (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_popup_chapter_activate              (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_popup_audio_activate                (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
+on_popup_subtitle_activate             (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
index 8896d44107d3bef16af2e4f483af3ef085a0c361..72b10c59951a976dca5a1035a468e4079ebd5dab 100644 (file)
@@ -46,6 +46,21 @@ static GnomeUIInfo menubar_view_menu_uiinfo[] =
 
 static GnomeUIInfo menubar_settings_menu_uiinfo[] =
 {
+  {
+    GNOME_APP_UI_ITEM, N_("_Audio"),
+    N_("Select audio channel"),
+    (gpointer) on_menubar_audio_activate, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  {
+    GNOME_APP_UI_ITEM, N_("_Subtitles"),
+    N_("Select subtitle unit"),
+    (gpointer) on_menubar_subtitles_activate, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  GNOMEUIINFO_SEPARATOR,
   GNOMEUIINFO_MENU_PREFERENCES_ITEM (on_menubar_preferences_activate, NULL),
   GNOMEUIINFO_END
 };
@@ -143,10 +158,25 @@ create_intf_window (void)
                             (GtkDestroyNotify) gtk_widget_unref);
 
   gtk_widget_ref (menubar_settings_menu_uiinfo[0].widget);
-  gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_preferences",
+  gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_audio",
                             menubar_settings_menu_uiinfo[0].widget,
                             (GtkDestroyNotify) gtk_widget_unref);
-  gtk_widget_set_sensitive (menubar_settings_menu_uiinfo[0].widget, FALSE);
+
+  gtk_widget_ref (menubar_settings_menu_uiinfo[1].widget);
+  gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_subtitles",
+                            menubar_settings_menu_uiinfo[1].widget,
+                            (GtkDestroyNotify) gtk_widget_unref);
+
+  gtk_widget_ref (menubar_settings_menu_uiinfo[2].widget);
+  gtk_object_set_data_full (GTK_OBJECT (intf_window), "separator5",
+                            menubar_settings_menu_uiinfo[2].widget,
+                            (GtkDestroyNotify) gtk_widget_unref);
+
+  gtk_widget_ref (menubar_settings_menu_uiinfo[3].widget);
+  gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_preferences",
+                            menubar_settings_menu_uiinfo[3].widget,
+                            (GtkDestroyNotify) gtk_widget_unref);
+  gtk_widget_set_sensitive (menubar_settings_menu_uiinfo[3].widget, FALSE);
 
   gtk_widget_ref (menubar_uiinfo[3].widget);
   gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_help",
@@ -394,6 +424,18 @@ create_intf_window (void)
   return intf_window;
 }
 
+static GnomeUIInfo popup_title_menu_uiinfo[] =
+{
+  {
+    GNOME_APP_UI_ITEM, N_("_Chapter"),
+    NULL,
+    (gpointer) on_popup_chapter_activate, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  GNOMEUIINFO_END
+};
+
 static GnomeUIInfo intf_popup_uiinfo[] =
 {
   {
@@ -427,6 +469,28 @@ static GnomeUIInfo intf_popup_uiinfo[] =
   GNOMEUIINFO_SEPARATOR,
   GNOMEUIINFO_MENU_OPEN_ITEM (on_popup_open_activate, NULL),
   GNOMEUIINFO_SEPARATOR,
+  {
+    GNOME_APP_UI_SUBTREE, N_("_Title"),
+    N_("Select Title"),
+    popup_title_menu_uiinfo, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  {
+    GNOME_APP_UI_ITEM, N_("Audio"),
+    N_("Select audio channel"),
+    (gpointer) on_popup_audio_activate, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  {
+    GNOME_APP_UI_ITEM, N_("_Subtitle"),
+    NULL,
+    (gpointer) on_popup_subtitle_activate, NULL, NULL,
+    GNOME_APP_PIXMAP_NONE, NULL,
+    0, (GdkModifierType) 0, NULL
+  },
+  GNOMEUIINFO_SEPARATOR,
   GNOMEUIINFO_MENU_ABOUT_ITEM (on_popup_about_activate, NULL),
   GNOMEUIINFO_MENU_EXIT_ITEM (on_popup_exit_activate, NULL),
   GNOMEUIINFO_END
@@ -478,15 +542,40 @@ create_intf_popup (void)
                             (GtkDestroyNotify) gtk_widget_unref);
 
   gtk_widget_ref (intf_popup_uiinfo[7].widget);
-  gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_about",
+  gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_title",
                             intf_popup_uiinfo[7].widget,
                             (GtkDestroyNotify) gtk_widget_unref);
 
+  gtk_widget_ref (popup_title_menu_uiinfo[0].widget);
+  gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_chapter",
+                            popup_title_menu_uiinfo[0].widget,
+                            (GtkDestroyNotify) gtk_widget_unref);
+
   gtk_widget_ref (intf_popup_uiinfo[8].widget);
-  gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_exit",
+  gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_audio",
                             intf_popup_uiinfo[8].widget,
                             (GtkDestroyNotify) gtk_widget_unref);
 
+  gtk_widget_ref (intf_popup_uiinfo[9].widget);
+  gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_subtitle",
+                            intf_popup_uiinfo[9].widget,
+                            (GtkDestroyNotify) gtk_widget_unref);
+
+  gtk_widget_ref (intf_popup_uiinfo[10].widget);
+  gtk_object_set_data_full (GTK_OBJECT (intf_popup), "separator4",
+                            intf_popup_uiinfo[10].widget,
+                            (GtkDestroyNotify) gtk_widget_unref);
+
+  gtk_widget_ref (intf_popup_uiinfo[11].widget);
+  gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_about",
+                            intf_popup_uiinfo[11].widget,
+                            (GtkDestroyNotify) gtk_widget_unref);
+
+  gtk_widget_ref (intf_popup_uiinfo[12].widget);
+  gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_exit",
+                            intf_popup_uiinfo[12].widget,
+                            (GtkDestroyNotify) gtk_widget_unref);
+
   return intf_popup;
 }
 
index 663b8f4e367adbd51cb09f1d269f82bb622dd27d..4af6b49e86bce4c82c0b4237be8c26ae348b2d77 100644 (file)
            <class>GtkMenu</class>
            <name>menubar_settings_menu</name>
 
+           <widget>
+             <class>GtkMenuItem</class>
+             <name>menubar_audio</name>
+             <tooltip>Select audio channel</tooltip>
+             <signal>
+               <name>activate</name>
+               <handler>on_menubar_audio_activate</handler>
+               <last_modification_time>Thu, 22 Feb 2001 05:42:43 GMT</last_modification_time>
+             </signal>
+             <label>_Audio</label>
+             <right_justify>False</right_justify>
+           </widget>
+
+           <widget>
+             <class>GtkMenuItem</class>
+             <name>menubar_subtitles</name>
+             <tooltip>Select subtitle unit</tooltip>
+             <signal>
+               <name>activate</name>
+               <handler>on_menubar_subtitles_activate</handler>
+               <last_modification_time>Thu, 22 Feb 2001 05:42:43 GMT</last_modification_time>
+             </signal>
+             <label>_Subtitles</label>
+             <right_justify>False</right_justify>
+           </widget>
+
+           <widget>
+             <class>GtkMenuItem</class>
+             <name>separator5</name>
+             <right_justify>False</right_justify>
+           </widget>
+
            <widget>
              <class>GtkPixmapMenuItem</class>
              <name>menubar_preferences</name>
     <right_justify>False</right_justify>
   </widget>
 
+  <widget>
+    <class>GtkMenuItem</class>
+    <name>popup_title</name>
+    <tooltip>Select Title</tooltip>
+    <signal>
+      <name>activate</name>
+      <handler>on_popup_title_activate</handler>
+      <last_modification_time>Thu, 22 Feb 2001 05:35:57 GMT</last_modification_time>
+    </signal>
+    <label>_Title</label>
+    <right_justify>False</right_justify>
+
+    <widget>
+      <class>GtkMenu</class>
+      <name>popup_title_menu</name>
+
+      <widget>
+       <class>GtkMenuItem</class>
+       <name>popup_chapter</name>
+       <signal>
+         <name>activate</name>
+         <handler>on_popup_chapter_activate</handler>
+         <last_modification_time>Thu, 22 Feb 2001 05:48:48 GMT</last_modification_time>
+       </signal>
+       <label>_Chapter</label>
+       <right_justify>False</right_justify>
+      </widget>
+    </widget>
+  </widget>
+
+  <widget>
+    <class>GtkMenuItem</class>
+    <name>popup_audio</name>
+    <tooltip>Select audio channel</tooltip>
+    <signal>
+      <name>activate</name>
+      <handler>on_popup_audio_activate</handler>
+      <last_modification_time>Thu, 22 Feb 2001 05:35:57 GMT</last_modification_time>
+    </signal>
+    <label>Audio</label>
+    <right_justify>False</right_justify>
+  </widget>
+
+  <widget>
+    <class>GtkMenuItem</class>
+    <name>popup_subtitle</name>
+    <signal>
+      <name>activate</name>
+      <handler>on_popup_subtitle_activate</handler>
+      <last_modification_time>Thu, 22 Feb 2001 05:35:57 GMT</last_modification_time>
+    </signal>
+    <label>_Subtitle</label>
+    <right_justify>False</right_justify>
+  </widget>
+
+  <widget>
+    <class>GtkMenuItem</class>
+    <name>separator4</name>
+    <right_justify>False</right_justify>
+  </widget>
+
   <widget>
     <class>GtkPixmapMenuItem</class>
     <name>popup_about</name>
index 785f0e07637cd38625aa4ba48f58df648211779c..69cd64696625ece697df4952acba463650b8bcaf 100644 (file)
@@ -2,7 +2,7 @@
  * input_programs.c: es_descriptor_t, pgrm_descriptor_t management
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
- * $Id: input_programs.c,v 1.33 2001/02/20 08:47:25 stef Exp $
+ * $Id: input_programs.c,v 1.34 2001/02/22 08:44:45 stef Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -263,7 +263,7 @@ input_area_t * input_AddArea( input_thread_t * p_input )
     p_input->stream.pp_areas[i_area_index]->i_start = 0;
     p_input->stream.pp_areas[i_area_index]->i_size = 0;
     p_input->stream.pp_areas[i_area_index]->i_tell = 0;
-    p_input->stream.pp_areas[i_area_index]->i_seek = 0;
+    p_input->stream.pp_areas[i_area_index]->i_seek = NO_SEEK;
     p_input->stream.pp_areas[i_area_index]->i_part_nb = 0;
     p_input->stream.pp_areas[i_area_index]->i_part= 0;
 
@@ -281,7 +281,7 @@ void input_DelArea( input_thread_t * p_input, input_area_t * p_area )
 
     ASSERT( p_area );
 
-    intf_DbgMsg("Deleting description for area %d", p_area->i_number);
+    intf_DbgMsg("Deleting description for area %d", p_area->i_n);
 
     /* Find the area in the areas table */
     for( i_area_index = 0; i_area_index < p_input->stream.i_area_nb;
@@ -303,7 +303,7 @@ void input_DelArea( input_thread_t * p_input, input_area_t * p_area )
     if( p_input->stream.i_area_nb && p_input->stream.pp_areas == NULL)
     {
         intf_ErrMsg( "input error: unable to realloc area list"
-                     " in input_Delarea" );
+                     " in input_DelArea" );
     }
 
     /* Free the description of this area */
@@ -680,3 +680,49 @@ int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
     }
     return( 0 );
 }
+
+/*****************************************************************************
+ * input_UnSelectES: removes an ES from the list of selected ES
+ *****************************************************************************/
+int input_UnSelectES( input_thread_t * p_input, es_descriptor_t * p_es )
+{
+
+    int     i_index = 0;
+
+#ifdef DEBUG_INPUT
+    intf_DbgMsg( "UnSelecting ES 0x%x", p_es->i_id );
+#endif
+
+    if( p_es->p_decoder_fifo == NULL )
+    {
+        intf_ErrMsg( "ES %d is not selected", p_es->i_id );
+        return( -1 );
+    }
+
+    input_EndDecoder( p_input, p_es );
+
+    if( p_es->p_decoder_fifo == NULL )
+    {
+        p_input->stream.i_selected_es_number--;
+
+        while( ( i_index < p_input->stream.i_selected_es_number ) &&
+               ( p_input->stream.pp_selected_es[i_index] != p_es ) )
+        {
+            i_index++;
+        }
+
+        p_input->stream.pp_selected_es[i_index] = 
+          p_input->stream.pp_selected_es[p_input->stream.i_selected_es_number];
+
+        p_input->stream.pp_selected_es = realloc(
+                                           p_input->stream.pp_selected_es,
+                                           p_input->stream.i_selected_es_number
+                                            * sizeof(es_descriptor_t *) );
+        if( p_input->stream.pp_selected_es == NULL )
+        {
+            intf_ErrMsg( "Unable to realloc memory in input_SelectES" );
+            return(-1);
+        }
+    }
+    return( 0 );
+}
index c54dddc80976c717cb14e9e2c120cbd92ab22b85..7a82964776a4d3eeaef38c88f5df74b54305d62c 100644 (file)
@@ -140,6 +140,8 @@ static const struct option longopts[] =
     {   "overlay",          0,          0,      OPT_OVERLAY },
 
     /* DVD options */
+    {   "dvdtitle",         1,          0,      't' },
+    {   "dvdchapter",       1,          0,      'T' },
     {   "dvdaudio",         1,          0,      'a' },
     {   "dvdchannel",       1,          0,      'c' },
     {   "dvdsubtitle",      1,          0,      's' },
@@ -157,7 +159,7 @@ static const struct option longopts[] =
 };
 
 /* Short options */
-static const char *psz_shortopts = "hHvga:s:c:";
+static const char *psz_shortopts = "hHvgt:T:a:s:c:";
 #endif
 
 
@@ -624,6 +626,12 @@ static int GetConfiguration( int i_argc, char *ppsz_argv[], char *ppsz_env[] )
             break;
 
         /* DVD options */
+        case 't':
+            main_PutIntVariable( INPUT_TITLE_VAR, atoi(optarg) );
+            break;
+        case 'T':
+            main_PutIntVariable( INPUT_CHAPTER_VAR, atoi(optarg) );
+            break;
         case 'a':
             if ( ! strcmp(optarg, "ac3") )
                 main_PutIntVariable( INPUT_AUDIO_VAR, REQUESTED_AC3 );
@@ -734,6 +742,8 @@ static void Usage( int i_fashion )
           "\n      --yuv <module>             \tYUV method"
           "\n      --synchro <type>           \tforce synchro algorithm"
           "\n"
+          "\n  -t, --dvdtitle <num>           \tchoose DVD title"
+          "\n  -T, --dvdchapter <num>         \tchoose DVD chapter"
           "\n  -a, --dvdaudio <type>          \tchoose DVD audio type"
           "\n  -c, --dvdchannel <channel>     \tchoose DVD audio channel"
           "\n  -s, --dvdsubtitle <channel>    \tchoose DVD subtitle channel"
@@ -783,6 +793,8 @@ static void Usage( int i_fashion )
     /* DVD parameters */
     intf_MsgImm( "\nDVD parameters:"
         "\n  " INPUT_DVD_DEVICE_VAR "=<device>           \tDVD device"
+        "\n  " INPUT_TITLE_VAR "=<title>                 \ttitle number"
+        "\n  " INPUT_CHAPTER_VAR "=<chapter>             \tchapter number"
         "\n  " INPUT_AUDIO_VAR "={ac3|lpcm|mpeg|off}     \taudio type"
         "\n  " INPUT_CHANNEL_VAR "=[0-15]                \taudio channel"
         "\n  " INPUT_SUBTITLE_VAR "=[0-31]               \tsubtitle channel" );