. Parsing of ifo file almost completed.
. Still does not work well.
INPUT = src/input/input_ps.o \
src/input/input_ts.o \
+ src/input/dvd_ifo.o \
+ src/input/input_dvd.o \
src/input/mpeg_system.o \
src/input/input_ext-dec.o \
src/input/input_dec.o \
* mark it to be presented */
#define DEFAULT_PTS_DELAY (.2*CLOCK_FREQ)
+#define INPUT_DVD_DEVICE_VAR "vlc_dvd_device"
+#define INPUT_DVD_DEVICE_DEFAULT "/dev/dvd"
#define INPUT_DVD_AUDIO_VAR "vlc_dvd_audio"
#define INPUT_DVD_CHANNEL_VAR "vlc_dvd_channel"
#define INPUT_DVD_SUBTITLE_VAR "vlc_dvd_subtitle"
#define AOUT_STEREO_DEFAULT 1
/* Volume */
-#define VOLUME_DEFAULT 256
-#define VOLUME_STEP 5
-#define VOLUME_MAX 765
+#define VOLUME_DEFAULT 512
+#define VOLUME_STEP 128
+#define VOLUME_MAX 1024
/* Environment variable for output rate, and default value */
#define AOUT_RATE_VAR "vlc_audio_rate"
* control the pace of reading.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
- * $Id: input_ext-intf.h,v 1.8 2000/12/21 19:24:26 massiot Exp $
+ * $Id: input_ext-intf.h,v 1.9 2001/01/14 07:08:00 stef Exp $
*
* Authors:
*
/* Input methods */
#define INPUT_METHOD_NONE 0 /* input thread is inactive */
#define INPUT_METHOD_FILE 10 /* stream is read from file p_source */
+#define INPUT_METHOD_DVD 11 /* stream is read from dvd device */
#define INPUT_METHOD_UCAST 20 /* UDP unicast */
#define INPUT_METHOD_MCAST 21 /* UDP multicast */
#define INPUT_METHOD_BCAST 22 /* UDP broadcast */
boolean_t b_audio; /* is audio output allowed ? */
boolean_t b_video; /* is video output allowed ? */
boolean_t b_vlans; /* are vlans supported ? */
+ boolean_t b_dvd; /* DVD mode ? */
/* Unique threads */
p_aout_thread_t p_aout; /* audio output thread */
--- /dev/null
+/*****************************************************************************
+ * dvd_ifo.c: Functions for ifo parsing
+ *****************************************************************************
+ * Copyright (C) 1999-2001 VideoLAN
+ *
+ * Author: Stéphane Borel <stef@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <malloc.h>
+
+#include "common.h"
+
+#include "intf_msg.h"
+#include "dvd_ifo.h"
+
+/*
+ * IFO Management.
+ */
+
+/*****************************************************************************
+ * IfoFindStart : When reading directly on a device, finds the offset to the
+ * beginning of video_ts.ifo.
+ *****************************************************************************/
+static int IfoFindStart( ifo_t* p_ifo )
+{
+ char psz_ifo_start[12] = "DVDVIDEO-VMG";
+ char psz_test[12];
+
+ read( p_ifo->i_fd, psz_test, 12 );
+
+ while( strncmp( psz_test, psz_ifo_start, 12 ) != 0 )
+ {
+ /* The start of ifo file is on a sector boundary */
+ p_ifo->i_pos = lseek( p_ifo->i_fd,
+ p_ifo->i_pos + DVD_LB_SIZE,
+ SEEK_SET );
+ read( p_ifo->i_fd, psz_test, 12 );
+ }
+ p_ifo->i_off = p_ifo->i_pos;
+
+fprintf( stderr, "VMG Off : %d\n", p_ifo->i_off );
+
+ return 0;
+}
+
+/*****************************************************************************
+ * IfoFindVTS : beginning of vts_*.ifo.
+ *****************************************************************************/
+static int IfoFindVTS( ifo_t* p_ifo )
+{
+ char psz_ifo_start[12] = "DVDVIDEO-VTS";
+ char psz_test[12];
+
+ read( p_ifo->i_fd, psz_test, 12 );
+
+ while( strncmp( psz_test, psz_ifo_start, 12 ) != 0 )
+ {
+ /* The start of ifo file is on a sector boundary */
+ p_ifo->i_pos = lseek( p_ifo->i_fd,
+ p_ifo->i_pos + DVD_LB_SIZE,
+ SEEK_SET );
+ read( p_ifo->i_fd, psz_test, 12 );
+ }
+ p_ifo->i_off = p_ifo->i_pos;
+
+fprintf( stderr, "VTS Off : %d\n", p_ifo->i_off );
+
+ return 0;
+}
+
+/*****************************************************************************
+ * IfoInit : Creates an ifo structure and prepares for parsing directly
+ * on DVD device.
+ *****************************************************************************/
+ifo_t IfoInit( int i_fd )
+{
+ ifo_t ifo;
+
+ /* If we are here the dvd device has already been opened */
+ ifo.i_fd = i_fd;
+ /* No data at the beginning of the disk
+ * 512000 bytes is just another value :) */
+ ifo.i_pos = lseek( ifo.i_fd, 250 *DVD_LB_SIZE, SEEK_SET );
+ /* FIXME : use udf filesystem to find the beginning of the file */
+ IfoFindStart( &ifo );
+
+ return ifo;
+}
+
+/*****************************************************************************
+ * IfoEnd : Frees all the memory allocated to ifo structures
+ *****************************************************************************/
+void IfoEnd( ifo_t* p_ifo )
+{
+ int i,j;
+
+ /* Free structures from video title sets */
+ for( j=0 ; j<p_ifo->vmg.mat.i_tts_nb ; j++ )
+ {
+ free( p_ifo->p_vts[j].vobu_admap.pi_vobu_ssector );
+ free( p_ifo->p_vts[j].c_adt.p_cell_inf );
+ free( p_ifo->p_vts[j].m_vobu_admap.pi_vobu_ssector );
+ free( p_ifo->p_vts[j].m_c_adt.p_cell_inf );
+ for( i=0 ; i<p_ifo->p_vts[j].tmap_ti.i_nb ; i++ )
+ {
+ free( p_ifo->p_vts[j].tmap_ti.p_tmap[i].pi_sector );
+ }
+ free( p_ifo->p_vts[j].tmap_ti.pi_sbyte );
+ free( p_ifo->p_vts[j].tmap_ti.p_tmap );
+ free( p_ifo->p_vts[j].pgci_ti.p_lu_desc );
+ free( p_ifo->p_vts[j].pgci_ti.p_lu );
+ free( p_ifo->p_vts[j].pgci_ut.p_lu_desc );
+ free( p_ifo->p_vts[j].pgci_ut.p_lu );
+ }
+
+ free( p_ifo->p_vts );
+
+ /* Free structures from video manager */
+ free( p_ifo->vmg.vobu_admap.pi_vobu_ssector );
+ free( p_ifo->vmg.c_adt.p_cell_inf );
+ for( i=0 ; i<p_ifo->vmg.pgci_ut.i_lu_nb ; i++ )
+ {
+ free( p_ifo->vmg.pgci_ut.p_lu[i].p_srp );
+ }
+ free( p_ifo->vmg.pgci_ut.p_lu_desc );
+ free( p_ifo->vmg.pgci_ut.p_lu );
+ for( i=1 ; i<=8 ; i++ )
+ {
+ free( p_ifo->vmg.ptl_mait.p_ptl_mask->ppi_ptl_mask[i] );
+ }
+ free( p_ifo->vmg.ptl_mait.p_ptl_desc );
+ free( p_ifo->vmg.ptl_mait.p_ptl_mask );
+ free( p_ifo->vmg.vts_atrt.pi_vts_atrt_sbyte );
+ free( p_ifo->vmg.vts_atrt.p_vts_atrt );
+ free( p_ifo->vmg.pgc.p_cell_pos_inf );
+ free( p_ifo->vmg.pgc.p_cell_play_inf );
+ free( p_ifo->vmg.pgc.prg_map.pi_entry_cell );
+ free( p_ifo->vmg.pgc.com_tab.psz_cell_com );
+ free( p_ifo->vmg.pgc.com_tab.psz_post_com );
+ free( p_ifo->vmg.pgc.com_tab.psz_pre_com );
+
+ return;
+}
+
+/*
+ * Macros to process ifo files
+ */
+
+#define GET( p_field , i_len ) \
+ { \
+ read( p_ifo->i_fd , p_field , i_len ); \
+fprintf(stderr, "Pos : %d\n", p_ifo->i_pos - i_start); \
+ p_ifo->i_pos = lseek( p_ifo->i_fd , p_ifo->i_pos + i_len , SEEK_SET );\
+ }
+
+#define GETC( p_field ) \
+ { \
+ read( p_ifo->i_fd , p_field , 1 ); \
+fprintf(stderr, "Pos : %d Value : %d\n", p_ifo->i_pos - i_start, \
+ *p_field ); \
+ p_ifo->i_pos = lseek( p_ifo->i_fd , p_ifo->i_pos + 1 , SEEK_SET ); \
+ }
+
+#define GETS( p_field ) \
+ { \
+ read( p_ifo->i_fd , p_field , 2 ); \
+ *p_field = ntohs( *p_field ); \
+fprintf(stderr, "Pos : %d Value : %d\n", p_ifo->i_pos - i_start, \
+ *p_field ); \
+ p_ifo->i_pos = lseek( p_ifo->i_fd , p_ifo->i_pos + 2 , SEEK_SET ); \
+ }
+
+#define GETL( p_field ) \
+ { \
+ read( p_ifo->i_fd , p_field , 4 ); \
+ *p_field = ntohl( *p_field ); \
+fprintf(stderr, "Pos : %d Value : %d\n", p_ifo->i_pos - i_start, \
+ *p_field ); \
+ p_ifo->i_pos = lseek( p_ifo->i_fd , p_ifo->i_pos + 4 , SEEK_SET ); \
+ }
+
+#define GETLL( p_field ) \
+ { \
+ read( p_ifo->i_fd , p_field , 8 ); \
+ *p_field = ntoh64( *p_field ); \
+fprintf(stderr, "Pos : %d Value : %lld\n", p_ifo->i_pos - i_start, \
+ *p_field ); \
+ p_ifo->i_pos = lseek( p_ifo->i_fd , p_ifo->i_pos + 8 , SEEK_SET ); \
+ }
+
+#define FLUSH( i_len ) \
+ { \
+fprintf(stderr, "Pos : %d\n", p_ifo->i_pos - i_start ); \
+ p_ifo->i_pos = lseek( p_ifo->i_fd , p_ifo->i_pos + i_len , SEEK_SET );\
+ }
+
+/*
+ * Function common to Video Manager and Video Title set Processing
+ */
+
+/*****************************************************************************
+ * ReadPGC : Fills the Program Chain structure.
+ *****************************************************************************/
+static pgc_t ReadPGC( ifo_t* p_ifo )
+{
+ pgc_t pgc;
+ int i;
+ int i_start = p_ifo->i_pos;
+
+fprintf( stderr, "PGC\n" );
+
+ FLUSH(2);
+ GETC( &pgc.i_prg_nb );
+ GETC( &pgc.i_cell_nb );
+ GETL( &pgc.i_play_time );
+ GETL( &pgc.i_prohibited_user_op );
+ for( i=0 ; i<8 ; i++ )
+ {
+ GETS( &pgc.pi_audio_status[i] );
+ }
+ for( i=0 ; i<32 ; i++ )
+ {
+ GETL( &pgc.pi_subpic_status[i] );
+ }
+ GETS( &pgc.i_next_pgc_nb );
+ GETS( &pgc.i_prev_pgc_nb );
+ GETS( &pgc.i_goup_pgc_nb );
+ GETC( &pgc.i_still_time );
+ GETC( &pgc.i_play_mode );
+ for( i=0 ; i<16 ; i++ )
+ {
+ GETL( &pgc.pi_yuv_color[i] );
+ /* FIXME : We have to erase the extra bit */
+ }
+ GETS( &pgc.i_com_tab_sbyte );
+ GETS( &pgc.i_prg_map_sbyte );
+ GETS( &pgc.i_cell_play_inf_sbyte );
+ GETS( &pgc.i_cell_pos_inf_sbyte );
+
+ /* Parsing of pgc_com_tab_t */
+ if( pgc.i_com_tab_sbyte )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
+ + pgc.i_com_tab_sbyte, SEEK_SET );
+ GETS( &pgc.com_tab.i_pre_com_nb );
+ GETS( &pgc.com_tab.i_post_com_nb );
+ GETS( &pgc.com_tab.i_cell_com_nb );
+ pgc.com_tab.psz_pre_com = malloc(sizeof(8*pgc.com_tab.i_pre_com_nb));
+ if( pgc.com_tab.psz_pre_com == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return pgc;
+ }
+ GET( pgc.com_tab.psz_pre_com, 8*pgc.com_tab.i_pre_com_nb );
+ pgc.com_tab.psz_post_com = malloc(sizeof(8*pgc.com_tab.i_pre_com_nb));
+ if( pgc.com_tab.psz_post_com == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return pgc;
+ }
+ GET( pgc.com_tab.psz_post_com, 8*pgc.com_tab.i_post_com_nb );
+ pgc.com_tab.psz_cell_com = malloc(sizeof(8*pgc.com_tab.i_pre_com_nb));
+ if( pgc.com_tab.psz_cell_com == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return pgc;
+ }
+ GET( pgc.com_tab.psz_cell_com, 8*pgc.com_tab.i_cell_com_nb );
+ }
+ /* Parsing of pgc_prg_map_t */
+ if( pgc.i_prg_map_sbyte )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
+ + pgc.i_prg_map_sbyte, SEEK_SET );
+ pgc.prg_map.pi_entry_cell = malloc( sizeof(pgc.i_prg_nb) );
+ if( pgc.prg_map.pi_entry_cell == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return pgc;
+ }
+ GET( pgc.prg_map.pi_entry_cell, pgc.i_prg_nb );
+ /* FIXME : check endianness here */
+ }
+ /* Parsing of cell_play_inf_t */
+ if( pgc.i_cell_play_inf_sbyte )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
+ + pgc.i_cell_play_inf_sbyte, SEEK_SET );
+ pgc.p_cell_play_inf = malloc( pgc.i_cell_nb *sizeof(cell_play_inf_t) );
+ if( pgc.p_cell_play_inf == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return pgc;
+ }
+ for( i=0 ; i<pgc.i_cell_nb ; i++ )
+ {
+ GETS( &pgc.p_cell_play_inf[i].i_cat );
+ GETC( &pgc.p_cell_play_inf[i].i_still_time );
+ GETS( &pgc.p_cell_play_inf[i].i_com_nb );
+ GETL( &pgc.p_cell_play_inf[i].i_play_time );
+ GETL( &pgc.p_cell_play_inf[i].i_entry_sector );
+ GETL( &pgc.p_cell_play_inf[i].i_first_ilvu_vobu_esector );
+ GETL( &pgc.p_cell_play_inf[i].i_lvobu_ssector );
+ GETL( &pgc.p_cell_play_inf[i].i_lsector );
+ }
+ }
+ /* Parsing of cell_pos_inf_map */
+ if( pgc.i_cell_pos_inf_sbyte )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, i_start
+ + pgc.i_cell_pos_inf_sbyte, SEEK_SET );
+ pgc.p_cell_pos_inf = malloc( pgc.i_cell_nb *sizeof(cell_pos_inf_t) );
+ if( pgc.p_cell_play_inf == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return pgc;
+ }
+ for( i=0 ; i<pgc.i_cell_nb ; i++ )
+ {
+ GETS( &pgc.p_cell_pos_inf[i].i_vob_id );
+ FLUSH( 1 );
+ GETC( &pgc.p_cell_pos_inf[i].i_cell_id );
+ }
+ }
+
+ return pgc;
+}
+
+/*****************************************************************************
+ * ReadUnitTable : Fills the Language Unit structure.
+ *****************************************************************************/
+static pgci_ut_t ReadUnitTable( ifo_t* p_ifo )
+{
+ pgci_ut_t lang;
+ int i, j;
+ int i_start = p_ifo->i_pos;
+
+fprintf( stderr, "LU\n" );
+
+ GETS( &lang.i_lu_nb );
+ FLUSH( 2 );
+ GETL( &lang.i_ebyte );
+ lang.p_lu_desc = malloc( lang.i_lu_nb *sizeof(pgci_lu_desc_t) );
+ if( lang.p_lu_desc == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return lang;
+ }
+ for( i=0 ; i<lang.i_lu_nb ; i++ )
+ {
+ GETS( &lang.p_lu_desc[i].i_lang_code );
+ FLUSH( 1 );
+ GETC( &lang.p_lu_desc[i].i_existence_mask );
+ GETL( &lang.p_lu_desc[i].i_lu_sbyte );
+ }
+ lang.p_lu = malloc( lang.i_lu_nb *sizeof(pgci_lu_t) );
+ if( lang.p_lu == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return lang;
+ }
+ for( i=0 ; i<lang.i_lu_nb ; i++ )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
+ lang.p_lu_desc[i].i_lu_sbyte,
+ SEEK_SET );
+ GETS( &lang.p_lu[i].i_srp_nb );
+ FLUSH( 2 );
+ GETL( &lang.p_lu[i].i_lu_ebyte );
+ lang.p_lu[i].p_srp = malloc( lang.p_lu[i].i_srp_nb *
+ sizeof(pgci_srp_t) );
+ if( lang.p_lu[i].p_srp == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return lang;
+ }
+ for( j=0 ; j<lang.p_lu[i].i_srp_nb ; j++ )
+ {
+ GETC( &lang.p_lu[i].p_srp[j].i_pgc_cat_mask );
+ GETC( &lang.p_lu[i].p_srp[j].i_pgc_cat );
+ GETS( &lang.p_lu[i].p_srp[j].i_par_mask );
+ GETL( &lang.p_lu[i].p_srp[j].i_pgci_sbyte );
+ }
+ for( j=0 ; j<lang.p_lu[i].i_srp_nb ; j++ )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd,
+ i_start + lang.p_lu[i].p_srp[j].i_pgci_sbyte,
+ SEEK_SET );
+ /* FIXME : Bad parsing somiewhere by here : various information
+ * don't match */
+ //lang.p_lu[i].p_srp[j].pgc = ReadPGC( p_ifo );
+ }
+ }
+
+ return lang;
+}
+
+/*****************************************************************************
+ * ReadCellInf : Fills the Cell Information structure.
+ *****************************************************************************/
+static c_adt_t ReadCellInf( ifo_t* p_ifo )
+{
+ c_adt_t c_adt;
+ int i, i_max;
+ int i_start = p_ifo->i_pos;
+
+fprintf( stderr, "CELL ADD\n" );
+
+ GETS( &c_adt.i_vob_nb );
+ FLUSH( 2 );
+ GETL( &c_adt.i_ebyte );
+ i_max = ( i_start + c_adt.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(cell_inf_t);
+ c_adt.p_cell_inf = malloc( i_max *sizeof(cell_inf_t) );
+ if( c_adt.p_cell_inf == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return c_adt;
+ }
+ for( i=0 ; i<i_max ; i++ )
+ {
+ GETS( &c_adt.p_cell_inf[i].i_vob_id );
+ GETC( &c_adt.p_cell_inf[i].i_cell_id );
+ FLUSH( 1 );
+ GETL( &c_adt.p_cell_inf[i].i_ssector );
+ GETL( &c_adt.p_cell_inf[i].i_esector );
+ }
+
+ return c_adt;
+}
+
+/*****************************************************************************
+ * ReadMap : Fills the VOBU Map structure.
+ *****************************************************************************/
+static vobu_admap_t ReadMap( ifo_t* p_ifo )
+{
+ vobu_admap_t map;
+ int i, i_max;
+ int i_start = p_ifo->i_pos;
+
+fprintf( stderr, "VOBU ADMAP\n" );
+
+ GETL( &map.i_ebyte );
+ i_max = ( i_start + map.i_ebyte + 1 - p_ifo->i_pos ) / sizeof(u32);
+ map.pi_vobu_ssector = malloc( i_max *sizeof(u32) );
+ for( i=0 ; i<i_max ; i++ )
+ {
+ GETL( &map.pi_vobu_ssector[i] );
+ }
+
+ return map;
+}
+
+/*
+ * Video Manager Information Processing.
+ * This is what is contained in video_ts.ifo.
+ */
+
+/*****************************************************************************
+ * ReadVMGInfMat : Fills the Management Information structure.
+ *****************************************************************************/
+static vmgi_mat_t ReadVMGInfMat( ifo_t* p_ifo )
+{
+ vmgi_mat_t mat;
+ int i;
+ int i_start = p_ifo->i_pos;
+
+fprintf( stderr, "VMGI\n" );
+
+ GET( mat.psz_id , 12 );
+ mat.psz_id[12] = '\0';
+ GETL( &mat.i_lsector );
+ FLUSH( 12 );
+ GETL( &mat.i_i_lsector );
+ FLUSH( 1 );
+ GETC( &mat.i_spec_ver );
+ GETL( &mat.i_cat );
+ GETS( &mat.i_vol_nb );
+ GETS( &mat.i_vol );
+ GETC( &mat.i_disc_side );
+ FLUSH( 19 );
+ GETS( &mat.i_tts_nb );
+ GET( mat.psz_provider_id, 32 );
+ GETLL( &mat.i_pos_code );
+ FLUSH( 24 );
+ GETL( &mat.i_i_mat_ebyte );
+ GETL( &mat.i_fp_pgc_sbyte );
+ FLUSH( 56 );
+ GETL( &mat.i_vobs_ssector );
+ GETL( &mat.i_ptt_srpt_ssector );
+ GETL( &mat.i_pgci_ut_ssector );
+ GETL( &mat.i_ptl_mait_ssector );
+ GETL( &mat.i_vts_atrt_ssector );
+ GETL( &mat.i_txtdt_mg_ssector );
+ GETL( &mat.i_c_adt_ssector );
+ GETL( &mat.i_vobu_admap_ssector );
+ FLUSH( 32 );
+ GETS( &mat.i_video_atrt );
+ FLUSH( 1 );
+ GETC( &mat.i_audio_nb );
+ for( i=0 ; i < 8 ; i++ )
+ {
+ GETLL( &mat.pi_audio_atrt[i] );
+ }
+ FLUSH( 17 );
+ GETC( &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 */
+ }
+
+ return mat;
+}
+
+/*****************************************************************************
+ * ReadVMGTitlePointer : Fills the Part Of Title Search Pointer structure.
+ *****************************************************************************/
+static vmg_ptt_srpt_t ReadVMGTitlePointer( ifo_t* p_ifo )
+{
+ vmg_ptt_srpt_t ptr;
+ int i;
+ int i_start = p_ifo->i_pos;
+
+fprintf( stderr, "PTR\n" );
+
+ GETS( &ptr.i_ttu_nb );
+ FLUSH( 2 );
+ GETL( &ptr.i_ebyte );
+ /* Parsing of tts */
+ ptr.p_tts = malloc( ptr.i_ttu_nb *sizeof(tts_t) );
+ if( ptr.p_tts == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return ptr;
+ }
+ for( i=0 ; i<ptr.i_ttu_nb ; i++ )
+ {
+ GETC( &ptr.p_tts[i].i_play_type );
+ GETC( &ptr.p_tts[i].i_angle_nb );
+ GETS( &ptr.p_tts[i].i_ptt_nb );
+ GETS( &ptr.p_tts[i].i_parental_id );
+ GETC( &ptr.p_tts[i].i_tts_nb );
+ GETC( &ptr.p_tts[i].i_vts_ttn );
+ GETL( &ptr.p_tts[i].i_ssector );
+ }
+
+ return ptr;
+}
+
+/*****************************************************************************
+ * ReadParentalInf : Fills the Parental Management structure.
+ *****************************************************************************/
+static vmg_ptl_mait_t ReadParentalInf( ifo_t* p_ifo )
+{
+ vmg_ptl_mait_t par;
+ int i, j, k;
+ int i_start = p_ifo->i_pos;
+
+fprintf( stderr, "PTL\n" );
+
+ GETS( &par.i_country_nb );
+ GETS( &par.i_vts_nb );
+ GETL( &par.i_ebyte );
+ par.p_ptl_desc = malloc( par.i_country_nb *sizeof(vmg_ptl_mai_desc_t) );
+ if( par.p_ptl_desc == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return par;
+ }
+ for( i=0 ; i<par.i_country_nb ; i++ )
+ {
+ GETS( &par.p_ptl_desc[i].i_country_code );
+ FLUSH( 2 );
+ GETS( &par.p_ptl_desc[i].i_ptl_mai_sbyte );
+ FLUSH( 2 );
+ }
+ par.p_ptl_mask = malloc( par.i_country_nb *sizeof(vmg_ptl_mask_t) );
+ if( par.p_ptl_mask == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return par;
+ }
+ for( i=0 ; i<par.i_country_nb ; i++ )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
+ par.p_ptl_desc[i].i_ptl_mai_sbyte, SEEK_SET );
+ for( j=1 ; j<=8 ; j++ )
+ {
+ par.p_ptl_mask[i].ppi_ptl_mask[j] =
+ malloc( par.i_vts_nb *sizeof(u16) );
+ if( par.p_ptl_mask[i].ppi_ptl_mask[j] == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return par;
+ }
+ for( k=0 ; k<par.i_vts_nb ; k++ )
+ {
+ GETS( &par.p_ptl_mask[i].ppi_ptl_mask[j][k] );
+ }
+ }
+ }
+
+ return par;
+}
+
+/*****************************************************************************
+ * ReadVTSAttr : Fills the structure about VTS attributes.
+ *****************************************************************************/
+static vmg_vts_atrt_t ReadVTSAttr( ifo_t* p_ifo )
+{
+ vmg_vts_atrt_t atrt;
+ int i, j;
+ int i_start = p_ifo->i_pos;
+
+fprintf( stderr, "VTS ATTR\n" );
+
+ GETS( &atrt.i_vts_nb );
+ FLUSH( 2 );
+ GETL( &atrt.i_ebyte );
+ atrt.pi_vts_atrt_sbyte = malloc( atrt.i_vts_nb *sizeof(u32) );
+ if( atrt.pi_vts_atrt_sbyte == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return atrt;
+ }
+ for( i=0 ; i<atrt.i_vts_nb ; i++ )
+ {
+ GETL( &atrt.pi_vts_atrt_sbyte[i] );
+ }
+ atrt.p_vts_atrt = malloc( atrt.i_vts_nb *sizeof(vts_atrt_t) );
+ if( atrt.p_vts_atrt == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return atrt;
+ }
+ for( i=0 ; i<atrt.i_vts_nb ; i++ )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, i_start + atrt.pi_vts_atrt_sbyte[i],
+ 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 );
+ FLUSH( 1 );
+ GETC( &atrt.p_vts_atrt[i].i_vtsm_audio_nb );
+ for( j=0 ; j<atrt.p_vts_atrt[i].i_vtsm_audio_nb ; j++ )
+ {
+ GETLL( &atrt.p_vts_atrt[i].pi_vtsm_audio_atrt[j] );
+ }
+ FLUSH( 1 );
+ GETC( &atrt.p_vts_atrt[i].i_vtsm_subpic_nb );
+ for( j=0 ; j<atrt.p_vts_atrt[i].i_vtsm_subpic_nb ; j++ )
+ {
+ GET( &atrt.p_vts_atrt[i].pi_vtsm_subpic_atrt[j], 6 );
+ /* FIXME : Fix endianness issue here */
+ }
+ GETS( &atrt.p_vts_atrt[i].i_vtstt_video_atrt );
+ FLUSH( 1 );
+ GETL( &atrt.p_vts_atrt[i].i_vtstt_audio_nb );
+ for( j=0 ; j<atrt.p_vts_atrt[i].i_vtstt_audio_nb ; j++ )
+ {
+ GETLL( &atrt.p_vts_atrt[i].pi_vtstt_audio_atrt[j] );
+ }
+ FLUSH( 1 );
+ GETC( &atrt.p_vts_atrt[i].i_vtstt_subpic_nb );
+ for( j=0 ; j<atrt.p_vts_atrt[i].i_vtstt_subpic_nb ; j++ )
+ {
+ GET( &atrt.p_vts_atrt[i].pi_vtstt_subpic_atrt[j], 6 );
+ /* FIXME : Fix endianness issue here */
+ }
+ }
+
+ return atrt;
+}
+
+/*****************************************************************************
+ * ReadVMG : Parse video_ts.ifo file to fill the Video Manager structure.
+ *****************************************************************************/
+static vmg_t ReadVMG( ifo_t* p_ifo )
+{
+ vmg_t vmg;
+
+ p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off, SEEK_SET);
+ vmg.mat = ReadVMGInfMat( p_ifo );
+ p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
+ vmg.mat.i_fp_pgc_sbyte, SEEK_SET );
+ vmg.pgc = ReadPGC( p_ifo );
+ if( vmg.mat.i_ptt_srpt_ssector )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
+ vmg.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
+ SEEK_SET );
+ vmg.ptt_srpt = ReadVMGTitlePointer( p_ifo );
+ }
+ if( vmg.mat.i_pgci_ut_ssector )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
+ vmg.mat.i_pgci_ut_ssector *DVD_LB_SIZE,
+ SEEK_SET );
+ vmg.pgci_ut = ReadUnitTable( p_ifo );
+ }
+ if( vmg.mat.i_ptl_mait_ssector )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
+ vmg.mat.i_ptl_mait_ssector *DVD_LB_SIZE,
+ SEEK_SET );
+ vmg.ptl_mait = ReadParentalInf( p_ifo );
+ }
+ if( vmg.mat.i_vts_atrt_ssector )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
+ vmg.mat.i_vts_atrt_ssector *DVD_LB_SIZE,
+ SEEK_SET );
+ vmg.vts_atrt = ReadVTSAttr( p_ifo );
+ }
+ if( vmg.mat.i_c_adt_ssector )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
+ vmg.mat.i_c_adt_ssector *DVD_LB_SIZE,
+ SEEK_SET );
+ vmg.c_adt = ReadCellInf( p_ifo );
+ }
+ if( vmg.mat.i_vobu_admap_ssector )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
+ vmg.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
+ SEEK_SET );
+ vmg.vobu_admap = ReadMap( p_ifo );
+ }
+ return vmg;
+}
+
+/*
+ * Video Title Set Information Processing.
+ * This is what is contained in vts_*.ifo.
+ */
+
+/*****************************************************************************
+ * ReadVTSInfMat : Fills the Title Set Information structure.
+ *****************************************************************************/
+static vtsi_mat_t ReadVTSInfMat( ifo_t* p_ifo )
+{
+ vtsi_mat_t mat;
+ int i;
+ int i_start = p_ifo->i_pos;
+
+fprintf( stderr, "VTSI\n" );
+
+ GET( mat.psz_id , 12 );
+ mat.psz_id[12] = '\0';
+ GETL( &mat.i_lsector );
+ FLUSH( 12 );
+ GETL( &mat.i_i_lsector );
+ FLUSH( 1 );
+ GETC( &mat.i_spec_ver );
+ GETL( &mat.i_cat );
+ FLUSH( 90 );
+ GETL( &mat.i_mat_ebyte );
+ FLUSH( 60 );
+ GETL( &mat.i_m_vobs_ssector );
+ GETL( &mat.i_tt_vobs_ssector );
+ GETL( &mat.i_ptt_srpt_ssector );
+ GETL( &mat.i_pgcit_ssector );
+ GETL( &mat.i_m_pgci_ut_ssector );
+ GETL( &mat.i_tmap_ti_ssector );
+ GETL( &mat.i_m_c_adt_ssector );
+ GETL( &mat.i_m_vobu_admap_ssector );
+ GETL( &mat.i_c_adt_ssector );
+ GETL( &mat.i_vobu_admap_ssector );
+ FLUSH( 24 );
+ GETS( &mat.i_m_video_atrt );
+ FLUSH( 1 );
+ GETC( &mat.i_m_audio_nb );
+ for( i=0 ; i<8 ; i++ )
+ {
+ GETLL( &mat.pi_m_audio_atrt[i] );
+ }
+ FLUSH( 17 );
+ GETC( &mat.i_m_subpic_nb );
+ for( i=0 ; i<28 ; i++ )
+ {
+ GET( &mat.pi_m_subpic_atrt[i], 6 );
+ /* FIXME : take care of endianness */
+ }
+ FLUSH( 2 );
+ GETS( &mat.i_video_atrt );
+ FLUSH( 1 );
+ GETC( &mat.i_audio_nb );
+ for( i=0 ; i<8 ; i++ )
+ {
+ GETLL( &mat.pi_audio_atrt[i] );
+ }
+ FLUSH( 17 );
+ GETC( &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 */
+ }
+
+ return mat;
+}
+
+/*****************************************************************************
+ * ReadVTSTitlePointer : Fills the Part Of Title Search Pointer structure.
+ *****************************************************************************/
+static vts_ptt_srpt_t ReadVTSTitlePointer( ifo_t* p_ifo )
+{
+ vts_ptt_srpt_t ptr;
+ int i;
+ int i_start = p_ifo->i_pos;
+
+fprintf( stderr, "PTR\n" );
+
+ GETS( &ptr.i_ttu_nb );
+ FLUSH( 2 );
+ GETL( &ptr.i_ebyte );
+ ptr.pi_ttu_sbyte = malloc( ptr.i_ttu_nb *sizeof(u32) );
+ if( ptr.pi_ttu_sbyte == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return ptr;
+ }
+ for( i=0 ; i<ptr.i_ttu_nb ; i++ )
+ {
+ GETL( &ptr.pi_ttu_sbyte[i] );
+ }
+ /* Parsing of tts */
+ ptr.p_ttu = malloc( ptr.i_ttu_nb *sizeof(ttu_t) );
+ if( ptr.p_ttu == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return ptr;
+ }
+ for( i=0 ; i<ptr.i_ttu_nb ; i++ )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, i_start +
+ ptr.pi_ttu_sbyte[i], SEEK_SET );
+ GETS( &ptr.p_ttu[i].i_pgc_nb );
+ GETS( &ptr.p_ttu[i].i_prg_nb );
+ }
+
+ return ptr;
+}
+
+/*****************************************************************************
+ * ReadVTSTimeMap : Fills the time map table
+ *****************************************************************************/
+static vts_tmap_ti_t ReadVTSTimeMap( ifo_t* p_ifo )
+{
+ vts_tmap_ti_t tmap;
+ int i,j;
+ int i_start = p_ifo->i_pos;
+
+fprintf( stderr, "TMAP\n" );
+
+ GETS( &tmap.i_nb );
+ FLUSH( 2 );
+ GETL( &tmap.i_ebyte );
+ tmap.pi_sbyte = malloc( tmap.i_nb *sizeof(u32) );
+ if( tmap.pi_sbyte == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return tmap;
+ }
+ for( i=0 ; i<tmap.i_nb ; i++ )
+ {
+ GETL( &tmap.pi_sbyte[i] );
+ }
+ tmap.p_tmap = malloc( tmap.i_nb *sizeof(tmap_t) );
+ if( tmap.p_tmap == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return tmap;
+ }
+ for( i=0 ; i<tmap.i_nb ; i++ )
+ {
+ GETC( &tmap.p_tmap[i].i_time_unit );
+ FLUSH( 1 );
+ GETS( &tmap.p_tmap[i].i_entry_nb );
+ tmap.p_tmap[i].pi_sector =
+ malloc( tmap.p_tmap[i].i_entry_nb *sizeof(u32) );
+ if( tmap.p_tmap[i].pi_sector == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return tmap;
+ }
+ for( j=0 ; j<tmap.p_tmap[i].i_entry_nb ; j++ )
+ {
+ GETL( &tmap.p_tmap[i].pi_sector[j] );
+ }
+ }
+
+ return tmap;
+}
+
+
+/*****************************************************************************
+ * ReadVTS : Parse vts*.ifo files to fill the Video Title Set structure.
+ *****************************************************************************/
+static vts_t ReadVTS( ifo_t* p_ifo )
+{
+ vts_t vts;
+
+ vts.i_pos = p_ifo->i_pos;
+
+ vts.mat = ReadVTSInfMat( p_ifo );
+ if( vts.mat.i_ptt_srpt_ssector )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
+ vts.mat.i_ptt_srpt_ssector *DVD_LB_SIZE,
+ SEEK_SET );
+ vts.ptt_srpt = ReadVTSTitlePointer( p_ifo );
+ }
+ if( vts.mat.i_m_pgci_ut_ssector )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
+ vts.mat.i_m_pgci_ut_ssector *DVD_LB_SIZE,
+ SEEK_SET );
+ vts.pgci_ut = ReadUnitTable( p_ifo );
+ }
+ if( vts.mat.i_pgcit_ssector )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
+ vts.mat.i_pgcit_ssector *DVD_LB_SIZE,
+ SEEK_SET );
+ vts.pgci_ti = ReadUnitTable( p_ifo );
+ }
+ if( vts.mat.i_tmap_ti_ssector )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
+ vts.mat.i_tmap_ti_ssector *DVD_LB_SIZE,
+ SEEK_SET );
+ vts.tmap_ti = ReadVTSTimeMap( p_ifo );
+ }
+ if( vts.mat.i_m_c_adt_ssector )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
+ vts.mat.i_m_c_adt_ssector *DVD_LB_SIZE,
+ SEEK_SET );
+ vts.m_c_adt = ReadCellInf( p_ifo );
+ }
+ if( vts.mat.i_m_vobu_admap_ssector )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
+ vts.mat.i_m_vobu_admap_ssector *DVD_LB_SIZE,
+ SEEK_SET );
+ vts.m_vobu_admap = ReadMap( p_ifo );
+ }
+ if( vts.mat.i_c_adt_ssector )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
+ vts.mat.i_c_adt_ssector *DVD_LB_SIZE,
+ SEEK_SET );
+ vts.c_adt = ReadCellInf( p_ifo );
+ }
+ if( vts.mat.i_vobu_admap_ssector )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd, p_ifo->i_off +
+ vts.mat.i_vobu_admap_ssector *DVD_LB_SIZE,
+ SEEK_SET );
+ vts.vobu_admap = ReadMap( p_ifo );
+ }
+
+ return vts;
+}
+
+/*
+ * DVD Information Management
+ */
+
+/*****************************************************************************
+ * IfoRead : Function that fills structure and calls specified functions
+ * to do it.
+ *****************************************************************************/
+void IfoRead( ifo_t* p_ifo )
+{
+ int i;
+ p_ifo->vmg = ReadVMG( p_ifo );
+ p_ifo->p_vts = malloc( p_ifo->vmg.mat.i_tts_nb *sizeof(vts_t) );
+ if( p_ifo->p_vts == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_ifo->b_error = 1;
+ return;
+ }
+ for( i=0 ; i<1/*p_ifo->vmg.mat.i_tts_nb*/ ; i++ )
+ {
+ p_ifo->i_pos = lseek( p_ifo->i_fd,
+ p_ifo->vmg.ptt_srpt.p_tts[i].i_ssector *DVD_LB_SIZE,
+ SEEK_SET );
+ /* FIXME : use udf filesystem to avoid this */
+ IfoFindVTS( p_ifo );
+ p_ifo->p_vts[i] = ReadVTS( p_ifo );
+ }
+ return;
+}
--- /dev/null
+/*****************************************************************************
+ * ifo.h: Structures for ifo parsing
+ *****************************************************************************
+ * Copyright (C) 1999-2001 VideoLAN
+ *
+ * Author: Stéphane Borel <stef@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#define DVD_LB_SIZE 2048
+
+/*****************************************************************************
+ * Common structures for Video Management and Video Title sets
+ *****************************************************************************/
+
+/*
+ * Program Chain structures
+ */
+
+/* Program Chain Command Table
+ - start at i_pgc_com_tab_sbyte */
+typedef struct pgc_com_tab_s
+{
+ u16 i_pre_com_nb; // 2 bytes
+ u16 i_post_com_nb; // 2 bytes
+ u16 i_cell_com_nb; // 2 bytes
+// char[2] ???
+ char* psz_pre_com; // i_pre_com_nb * 8 bytes
+ char* psz_post_com; // i_post_com_nb * 8 bytes
+ char* psz_cell_com; // i_cell_com_nb * 8 bytes
+} pgc_com_tab_t;
+
+/* Program Chain Map Table
+ * - start at "i_pgc_prg_map_sbyte" */
+typedef struct pgc_prg_map_s
+{
+ u8* pi_entry_cell; // i_prg_nb * 1 byte
+} pgc_prg_map_t;
+
+/* Cell Playback Information Table
+ * we have a pointer to such a structure for each cell
+ * - first start at "i_cell_play_inf_sbyte" */
+typedef struct cell_play_inf_s
+{
+ /* This information concerns the currently selected cell */
+ u16 i_cat; // 2 bytes
+ u8 i_still_time; // 1 byte; in seconds; ff=inf
+ u8 i_com_nb; // 1 byte; 0 = no com
+ u32 i_play_time; // 4 bytes
+ u32 i_entry_sector; // 4 bytes
+ u32 i_first_ilvu_vobu_esector; // 4 bytes; ???
+ u32 i_lvobu_ssector; // 4 bytes
+ u32 i_lsector; // 4 bytes
+} cell_play_inf_t;
+
+/* Cell Position Information Table
+ * we have a pointer to such a structure for each cell
+ * - first start at "i_cell_pos_inf_sbyte" */
+typedef struct cell_pos_inf_s
+{
+ /* This information concerns the currently selected cell */
+ u16 i_vob_id; // 2 bytes
+// char ???
+ u8 i_cell_id; // 1 byte
+} cell_pos_inf_t;
+
+/* Main structure for Program Chain
+ * - start at i_fp_pgc_sbyte
+ * - or at i_vmgm_pgci_sbyte in vmgm_pgci_srp_t */
+typedef struct pgc_s
+{
+ /* Global features of program chain */
+// char[2] ???
+ u8 i_prg_nb; // 1 byte
+ u8 i_cell_nb; // 1 byte
+ u32 i_play_time; // 4 bytes
+ u32 i_prohibited_user_op; // 4 bytes
+ u16 pi_audio_status[8]; // 8*2 bytes
+ u32 pi_subpic_status[32]; // 32*4 bytes
+ u16 i_next_pgc_nb; // 2 bytes
+ u16 i_prev_pgc_nb; // 2 bytes
+ u16 i_goup_pgc_nb; // 2 bytes
+ u8 i_still_time; // 1 byte ; in seconds
+ u8 i_play_mode; // 1 byte
+ /* In video_ts.ifo, the 3 significant bytes of each color are
+ * preceded by 1 unsignificant byte */
+ u32 pi_yuv_color[16]; // 16*3 bytes
+ /* Here come the start bytes of the following structures */
+ u16 i_com_tab_sbyte; // 2 bytes
+ u16 i_prg_map_sbyte; // 2 bytes
+ u16 i_cell_play_inf_sbyte; // 2 bytes
+ u16 i_cell_pos_inf_sbyte; // 2 bytes
+ /* Predefined structures */
+ pgc_com_tab_t com_tab;
+ pgc_prg_map_t prg_map;
+ cell_play_inf_t* p_cell_play_inf; // i_cell_nb * 24 bytes
+ cell_pos_inf_t* p_cell_pos_inf; // i_cell_nb * 4 bytes
+} pgc_t;
+
+/*
+ * Menu PGCI Unit Table
+ */
+
+/* Menu PGCI Language unit Descriptor */
+typedef struct pgci_lu_desc_s
+{
+ u16 i_lang_code; // 2 bytes (ISO-xx)
+// char ???
+ u8 i_existence_mask; // 1 byte
+ u32 i_lu_sbyte; // 4 bytes
+} pgci_lu_desc_t;
+
+typedef struct pgci_srp_s
+{
+ u8 i_pgc_cat_mask; // 1 byte
+ u8 i_pgc_cat; // 1 byte
+ u16 i_par_mask; // 2 bytes
+ u32 i_pgci_sbyte; // 4 bytes
+ pgc_t pgc;
+} pgci_srp_t;
+
+/* Menu PGCI Language Unit Table
+ * - start at i_lu_sbyte */
+typedef struct pgci_lu_s
+{
+ u16 i_srp_nb; // 2 bytes
+// char[2] ???
+ u32 i_lu_ebyte; // 4 bytes
+ pgci_srp_t* p_srp; // i_srp_nb * 8 bytes
+} pgci_lu_t;
+
+/* Main Struct for Menu PGCI
+ * - start at i_*_pgci_ut_ssector */
+typedef struct pgci_ut_s
+{
+ u16 i_lu_nb; // 2 bytes; ???
+// char[2] ???
+ u32 i_ebyte; // 4 bytes
+ pgci_lu_desc_t* p_lu_desc; // i_lu_nb * 8 bytes
+ pgci_lu_t* p_lu; // i_lu_nb * 8 bytes
+} pgci_ut_t;
+
+/*
+ * Cell Adress Table Information
+ */
+typedef struct cell_inf_s
+{
+ u16 i_vob_id; // 2 bytes
+ u8 i_cell_id; // 1 byte
+// char ???
+ u32 i_ssector; // 4 bytes
+ u32 i_esector; // 4 bytes
+} cell_inf_t;
+
+typedef struct c_adt_s
+{
+ u16 i_vob_nb; // 2 bytes
+// char[2] ???
+ u32 i_ebyte; // 4 bytes
+ cell_inf_t* p_cell_inf;
+} c_adt_t;
+
+
+/*
+ * VOBU Adress Map Table
+ */
+typedef struct vobu_admap_s
+{
+ u32 i_ebyte; // 4 bytes
+ u32* pi_vobu_ssector; // (nb of vobu) * 4 bytes
+} vobu_admap_t;
+
+/*****************************************************************************
+ * Structures for Video Management (cf video_ts.ifo)
+ *****************************************************************************/
+
+/*
+ * Video Manager Information Management Table
+ */
+typedef struct vmgi_mat_s
+{
+ char psz_id[13]; // 12 bytes (DVDVIDEO-VMG)
+ u32 i_lsector; // 4 bytes
+// char[12] ???
+ u32 i_i_lsector; // 4 bytes
+// char ???
+ u8 i_spec_ver; // 1 byte
+ u32 i_cat; // 4 bytes
+ u16 i_vol_nb; // 2 bytes
+ u16 i_vol; // 2 bytes
+ u8 i_disc_side; // 1 bytes
+// char[20] ???
+ u16 i_tts_nb; // 2 bytes
+ char psz_provider_id[32]; // 32 bytes
+ u64 i_pos_code; // 8 bytes
+// char[24] ???
+ u32 i_i_mat_ebyte; // 4 bytes
+ u32 i_fp_pgc_sbyte; // 4 bytes
+// char[56] ???
+ u32 i_vobs_ssector; // 4 bytes
+ u32 i_ptt_srpt_ssector; // 4 bytes
+ u32 i_pgci_ut_ssector; // 4 bytes
+ u32 i_ptl_mait_ssector; // 4 bytes
+ u32 i_vts_atrt_ssector; // 4 bytes
+ u32 i_txtdt_mg_ssector; // 4 bytes
+ u32 i_c_adt_ssector; // 4 bytes
+ u32 i_vobu_admap_ssector; // 4 bytes
+// char[2] ???
+ u16 i_video_atrt; // 2 bytes
+// char ???
+ u8 i_audio_nb; // 1 byte
+ u64 pi_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
+} vmgi_mat_t;
+
+
+/*
+ * Part Of Title Search Pointer Table Information
+ */
+
+/* Title sets structure
+ * we have a pointer to this structure for each tts */
+typedef struct tts_s
+{
+ u8 i_play_type; // 1 byte
+ u8 i_angle_nb; // 1 byte
+ u16 i_ptt_nb; // 2 bytes; Chapters/PGs
+ u16 i_parental_id; // 2 bytes
+ u8 i_tts_nb; // 1 byte (VTS#)
+ u8 i_vts_ttn; // 1 byte ???
+ u32 i_ssector; // 4 bytes
+} tts_t;
+
+/* Main struct for tts
+ * - start at "i_vmg_ptt_srpt_ssector" */
+typedef struct vmg_ptt_srpt_s
+{
+ u16 i_ttu_nb; // 2 bytes
+// char[2] ???
+ u32 i_ebyte; // 4 bytes
+ tts_t* p_tts; // i_ttu_nb * 12 bytes
+} vmg_ptt_srpt_t;
+
+/*
+ * Parental Management Information Table
+ */
+typedef struct vmg_ptl_mai_desc_s
+{
+ u16 i_country_code; // 2 bytes
+// char[2] ???
+ u16 i_ptl_mai_sbyte; // 2 bytes
+// char[2] ???
+} vmg_ptl_mai_desc_t;
+
+typedef struct vmg_ptl_mask_s
+{
+ u16* ppi_ptl_mask[8]; // (i_vts_nb +1) * 8 * 2 bytes
+} vmg_ptl_mask_t;
+
+/* Main struct for parental management
+ * - start at i_vmg_ptl_mait_ssector */
+typedef struct vmg_ptl_mait_s
+{
+ u16 i_country_nb; // 2 bytes
+ u16 i_vts_nb; // 2 bytes
+ u32 i_ebyte; // 4 bytes
+ vmg_ptl_mai_desc_t* p_ptl_desc; // i_country_nb * 8 bytes
+ vmg_ptl_mask_t* p_ptl_mask; // i_country_nb * sizeof(vmg_ptl_mask_t)
+} vmg_ptl_mait_t;
+
+/*
+ * Video Title Set Attribute Table
+ */
+
+/* Attribute structure : one for each vts
+ * - start at pi_atrt_sbyte */
+typedef struct vts_atrt_s
+{
+ u32 i_ebyte; // 4 bytes
+ u32 i_cat_app_type; // 4 bytes
+ u16 i_vtsm_video_atrt; // 2 bytes
+// char ???
+ u8 i_vtsm_audio_nb; // 1 byte
+ u64 pi_vtsm_audio_atrt[8]; // i_vtsm_audio_nb * 8 bytes
+// char ???
+ u8 i_vtsm_subpic_nb; // 1 byte
+ u64 pi_vtsm_subpic_atrt[32]; // i_vtsm_subpic_nb * 6 bytes
+ u16 i_vtstt_video_atrt; // 2 bytes
+// char ???
+ u8 i_vtstt_audio_nb; // 1 byte
+ u64 pi_vtstt_audio_atrt[8]; // i_vtstt_audio_nb * 8 bytes
+// char ???
+ u8 i_vtstt_subpic_nb; // 1 byte
+ u64 pi_vtstt_subpic_atrt[32]; // i_vtstt_subpic_nb * 6 bytes
+} vts_atrt_t;
+
+/* Main struct for vts attributes
+ * - start at i_vmg_vts_atrt_ssector */
+typedef struct vmg_vts_atrt_s
+{
+ u16 i_vts_nb; // 2 bytes
+// char[2] ???
+ u32 i_ebyte; // 4 bytes
+ u32* pi_vts_atrt_sbyte; // i_vts_nb * 4 bytes
+ vts_atrt_t* p_vts_atrt;
+} vmg_vts_atrt_t;
+
+/*
+ * Global Structure for Video Manager
+ */
+typedef struct vmg_s
+{
+ vmgi_mat_t mat;
+ pgc_t pgc;
+ vmg_ptt_srpt_t ptt_srpt;
+ pgci_ut_t pgci_ut;
+ vmg_ptl_mait_t ptl_mait;
+ vmg_vts_atrt_t vts_atrt;
+ c_adt_t c_adt;
+ vobu_admap_t vobu_admap;
+} vmg_t;
+
+/*****************************************************************************
+ * Structures for Video Title Sets (cf vts_*.ifo)
+ ****************************************************************************/
+
+/*
+ * Video Title Sets Information Management Table
+ */
+typedef struct vtsi_mat_s
+{
+ char psz_id[13]; // 12 bytes (DVDVIDEO-VTS)
+ u32 i_lsector; // 4 bytes
+// char[12] ???
+ u32 i_i_lsector; // 4 bytes
+// char ???
+ u8 i_spec_ver; // 1 byte
+ u32 i_cat; // 4 bytes
+// char[90] ???
+ u32 i_mat_ebyte; // 4 bytes
+// char[60] ???
+ u32 i_m_vobs_ssector; // 4 bytes
+ u32 i_tt_vobs_ssector; // 4 bytes
+ u32 i_ptt_srpt_ssector; // 4 bytes
+ u32 i_pgcit_ssector; // 4 bytes
+ u32 i_m_pgci_ut_ssector; // 4 bytes
+ u32 i_tmap_ti_ssector; // 4 bytes
+ u32 i_m_c_adt_ssector; // 4 bytes
+ u32 i_m_vobu_admap_ssector; // 4 bytes
+ u32 i_c_adt_ssector; // 4 bytes
+ u32 i_vobu_admap_ssector; // 4 bytes
+// char[24] ???
+ u16 i_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
+// char[16] ???
+ u8 i_m_subpic_nb; // 1 byte
+ u64 pi_m_subpic_atrt[32]; // i_subpic_nb * 6 bytes
+ // !!! only 28 subpics ???
+// char[2] ???
+ u16 i_video_atrt; // 2 bytes
+// char ???
+ u8 i_audio_nb; // 1 byte
+ u64 pi_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
+} vtsi_mat_t;
+
+/*
+ * Part Of Title Search Pointer Table Information
+ */
+
+/* Title sets structure
+ * we have a pointer to this structure for each tts */
+typedef struct ttu_s
+{
+ u16 i_pgc_nb; // 2 bytes; Chapters/PGs
+ u16 i_prg_nb; // 2 bytes
+} ttu_t;
+
+/* Main struct for tts
+ * - start at "i_vts_ptt_srpt_ssector" */
+typedef struct vts_ptt_srpt_s
+{
+ u16 i_ttu_nb; // 2 bytes
+// char[2] ???
+ u32 i_ebyte; // 4 bytes
+ u32* pi_ttu_sbyte;
+ ttu_t* p_ttu; // i_ttu_nb * 4 bytes
+} vts_ptt_srpt_t;
+
+/*
+ * Time Map table information
+ */
+
+/* Time Map structure */
+typedef struct tmap_s
+{
+ u8 i_time_unit; // 1 byte
+// char ???
+ u16 i_entry_nb; // 2 bytes
+ u32* pi_sector; // i_entry_nb * 4 bytes
+} tmap_t;
+
+/* Main structure for tmap_ti
+ * - start at "i_tmap_ti_ssector" */
+typedef struct vts_tmap_ti_s
+{
+ u16 i_nb; // 2 bytes
+// char[2] ???
+ u32 i_ebyte; // 4 bytes
+ u32* pi_sbyte; // i_tmap_nb * 4 bytes
+ tmap_t* p_tmap;
+} vts_tmap_ti_t;
+
+/*
+ * Video Title Set
+ */
+typedef struct vts_s
+{
+ u32 i_pos;
+ vtsi_mat_t mat;
+ /* Part Of Title Search Pointer Table Info */
+ vts_ptt_srpt_t ptt_srpt;
+ /* Video Title Set Menu PGCI Unit Table */
+ pgci_ut_t pgci_ut;
+ /* Video Title Set Program Chain Info Table */
+ pgci_ut_t pgci_ti;
+ /* Video Title Set Time Map Table */
+ vts_tmap_ti_t tmap_ti;
+ /* VTSM Cell Adress Table Information */
+ c_adt_t m_c_adt;
+ /* VTSM VOBU Adress Map Table */
+ vobu_admap_t m_vobu_admap;
+ /* VTS Cell Adress Table Information */
+ c_adt_t c_adt;
+ /* VTS VOBU Adress Map Table */
+ vobu_admap_t vobu_admap;
+} vts_t;
+
+/*
+ * Global Ifo Structure
+ */
+typedef struct ifo_s
+{
+ /* File descriptor for the device */
+ int i_fd;
+ /* Offset to video_ts.ifo on the device */
+ u32 i_off;
+ /* Position of stream pointer */
+ u32 i_pos;
+ /* Error Management */
+ boolean_t b_error;
+ /* Structure described in video_ts */
+ vmg_t vmg;
+ /* Table of vts ifos */
+ vts_t * p_vts;
+} ifo_t;
+
+/*****************************************************************************
+ * Prototypes in ifo.c
+ *****************************************************************************/
+ifo_t IfoInit( int );
+void IfoRead( ifo_t* );
* decoders.
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
- * $Id: input.c,v 1.67 2001/01/07 04:31:18 henri Exp $
+ * $Id: input.c,v 1.68 2001/01/14 07:08:00 stef Exp $
*
* Authors:
*
static void EndThread ( input_thread_t *p_input );
static void NetworkOpen ( input_thread_t *p_input );
static void FileOpen ( input_thread_t *p_input );
+static void DvdOpen ( input_thread_t *p_input );
/*****************************************************************************
* input_CreateThread: creates a new input thread
* InitThread: init the input thread
*****************************************************************************/
input_capabilities_t * PSKludge( void );
+input_capabilities_t * DVDKludge( void );
static void InitThread( input_thread_t * p_input )
{
/* Initialize default settings for spawned decoders */
{
case INPUT_METHOD_FILE: /* file methods */
FileOpen( p_input );
+ /* Probe plugin (FIXME: load plugins before & write this) */
+ p_input->p_plugin = PSKludge();
+ break;
+ case INPUT_METHOD_DVD: /* DVD method */
+ DvdOpen( p_input );
+ /* DVD plugin */
+ p_input->p_plugin = DVDKludge();
break;
case INPUT_METHOD_VLAN_BCAST: /* vlan network method */
/* if( !p_main->b_vlans )
free( p_input->p_config );
- /* Probe plugin (FIXME: load plugins before & write this) */
- p_input->p_plugin = PSKludge();
p_input->p_plugin->pf_init( p_input );
*p_input->pi_status = THREAD_READY;
#undef p_config
}
+
+/*****************************************************************************
+ * DvdOpen : open the dvd device
+ *****************************************************************************/
+static void DvdOpen( input_thread_t * p_input )
+{
+ intf_Msg( "Opening DVD %s", p_input->p_config->p_source );
+ if( (p_input->i_handle = open( p_input->p_config->p_source,
+ O_RDONLY|O_LARGEFILE )) == (-1) )
+ {
+ intf_ErrMsg( "input error: cannot open device %s", strerror(errno) );
+ p_input->b_error = 1;
+ return;
+ }
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+
+ p_input->stream.b_pace_control = 1;
+ p_input->stream.b_seekable = 1;
+ p_input->stream.i_size = 0;
+ p_input->stream.i_tell = 0;
+
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+}
--- /dev/null
+/*****************************************************************************
+ * input_dvd.c: DVD reading
+ *****************************************************************************
+ * Copyright (C) 1998-2001 VideoLAN
+ *
+ * Author: Stéphane Borel <stef@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include "defs.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <errno.h>
+#include <malloc.h>
+
+#include "config.h"
+#include "common.h"
+#include "threads.h"
+#include "mtime.h"
+
+#include "intf_msg.h"
+
+#include "main.h"
+
+#include "stream_control.h"
+#include "input_ext-intf.h"
+#include "input_ext-dec.h"
+
+#include "input.h"
+
+#include "dvd_ifo.h"
+#include "input_dvd.h"
+#include "mpeg_system.h"
+
+#include "debug.h"
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static int DVDProbe ( struct input_thread_s * );
+static int DVDRead ( struct input_thread_s *,
+ data_packet_t * p_packets[INPUT_READ_ONCE] );
+static void DVDInit ( struct input_thread_s * );
+static void DVDEnd ( struct input_thread_s * );
+static int DVDSeek ( struct input_thread_s *, off_t );
+static int DVDRewind ( struct input_thread_s * );
+static struct data_packet_s * NewPacket ( void *, size_t );
+static void DeletePacket( void *, struct data_packet_s * );
+static void DeletePES ( void *, struct pes_packet_s * );
+
+/*
+ * Data reading functions
+ */
+
+/*****************************************************************************
+ * DVDProbe: check the stream
+ *****************************************************************************/
+static int DVDProbe( input_thread_t * p_input )
+{
+ /* verify that the first three bytes are 0x000001, or unscramble and
+ * re-do. */
+ return 1;
+}
+
+/*****************************************************************************
+ * DVDInit: initializes DVD structures
+ *****************************************************************************/
+static void DVDInit( input_thread_t * p_input )
+{
+ thread_dvd_data_t * p_method;
+ u32 i_start;// = 2048*90000;
+
+ if( (p_method = malloc( sizeof(thread_dvd_data_t) )) == NULL )
+ {
+ intf_ErrMsg( "Out of memory" );
+ p_input->b_error = 1;
+ return;
+ }
+
+ p_input->p_plugin_data = (void *)p_method;
+
+ lseek( p_input->i_handle, 0, SEEK_SET );
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+
+ p_method->ifo = IfoInit( p_input->i_handle );
+ IfoRead( &(p_method->ifo) );
+
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+ i_start = p_method->ifo.p_vts[0].i_pos +
+ p_method->ifo.p_vts[0].mat.i_tt_vobs_ssector *DVD_LB_SIZE;
+ fprintf(stderr, "Begin at : %d\n", i_start );
+
+ lseek( p_input->i_handle, i_start, SEEK_SET );
+
+ input_InitStream( p_input, sizeof( stream_ps_data_t ) );
+ input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
+
+ 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;
+
+ /* 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;
+
+ 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];
+
+ 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;
+ break;
+ }
+
+ for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ )
+ {
+ /* FIXME: use i_p_config_t */
+ input_ParsePS( p_input, pp_packets[i] );
+ DeletePacket( p_input->p_method_data, pp_packets[i] );
+ }
+
+ /* File too big. */
+ if( p_input->stream.i_tell > INPUT_PREPARSE_LENGTH )
+ {
+ break;
+ }
+ }
+ lseek( p_input->i_handle, i_start, SEEK_SET );
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ p_input->stream.i_tell = 0;
+ if( p_demux_data->b_has_PSM )
+ {
+ /* (The PSM decoder will care about spawning the decoders) */
+ p_input->stream.pp_programs[0]->b_is_ok = 1;
+ }
+#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_DVD_AUDIO_VAR, 0 )
+ == REQUESTED_MPEG
+ && main_GetIntVariable( INPUT_DVD_CHANNEL_VAR, 0 )
+ == (p_es->i_id & 0x1F) )
+ {
+ input_SelectES( p_input, p_es );
+ }
+ break;
+
+ case AC3_AUDIO_ES:
+ if( main_GetIntVariable( INPUT_DVD_AUDIO_VAR, 0 )
+ == REQUESTED_AC3
+ && main_GetIntVariable( INPUT_DVD_CHANNEL_VAR, 0 )
+ == ((p_es->i_id & 0xF00) >> 8) )
+ {
+ input_SelectES( p_input, p_es );
+ }
+ break;
+
+ case DVD_SPU_ES:
+ if( main_GetIntVariable( INPUT_DVD_SUBTITLE_VAR, -1 )
+ == ((p_es->i_id & 0x1F00) >> 8) )
+ {
+ input_SelectES( p_input, p_es );
+ }
+ break;
+
+ case LPCM_AUDIO_ES:
+ /* FIXME ! */
+ break;
+ }
+ }
+
+ }
+#endif
+#ifdef STATS
+ input_DumpStream( p_input );
+#endif
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ }
+ else
+ {
+ /* 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;
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ }
+}
+
+/*****************************************************************************
+ * DVDEnd: frees unused data
+ *****************************************************************************/
+static void DVDEnd( input_thread_t * p_input )
+{
+ free( p_input->stream.p_demux_data );
+ free( p_input->p_plugin_data );
+}
+
+/*****************************************************************************
+ * SafeRead: reads a chunk of stream and correctly detects errors
+ *****************************************************************************/
+static __inline__ int SafeRead( input_thread_t * p_input, byte_t * p_buffer,
+ size_t i_len )
+{
+ thread_dvd_data_t * p_method;
+ int i_nb;
+
+ p_method = (thread_dvd_data_t *)p_input->p_plugin_data;
+ i_nb = read( p_input->i_handle, p_buffer, i_len );
+ switch( i_nb )
+ {
+ case 0:
+ /* End of File */
+ return( 1 );
+ case -1:
+ intf_ErrMsg( "Read failed (%s)", strerror(errno) );
+ return( -1 );
+ default:
+ break;
+ }
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ p_input->stream.i_tell += i_nb;
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ return( 0 );
+}
+
+/*****************************************************************************
+ * DVDRead: reads data packets
+ *****************************************************************************
+ * Returns -1 in case of error, 0 if everything went well, and 1 in case of
+ * EOF.
+ *****************************************************************************/
+static int DVDRead( input_thread_t * p_input,
+ data_packet_t * pp_packets[INPUT_READ_ONCE] )
+{
+ 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;
+
+ p_method = (thread_dvd_data_t *)p_input->p_plugin_data;
+
+ memset( pp_packets, 0, INPUT_READ_ONCE * sizeof(data_packet_t *) );
+ for( i_packet = 0; i_packet < INPUT_READ_ONCE; i_packet++ )
+ {
+ /* Read what we believe to be a packet header. */
+ if( (i_error = SafeRead( p_input, p_header, 6 )) )
+ {
+ return( i_error );
+ }
+
+ if( (U32_AT(p_header) & 0xFFFFFF00) != 0x100L )
+ {
+ /* This is not the startcode of a packet. Read the stream
+ * until we find one. */
+ u32 i_startcode = U32_AT(p_header);
+ int i_dummy,i_nb;
+
+ if( i_startcode )
+ {
+ /* 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 );
+ }
+
+ while( (i_startcode & 0xFFFFFF00) != 0x100L )
+ {
+ i_startcode <<= 8;
+ if( (i_nb = read( p_input->i_handle, &i_dummy, 1 )) != 0 )
+ {
+ i_startcode |= i_dummy;
+fprintf(stderr, "tut :%d %d\n", i_dummy, i_nb );
+ }
+ else
+ {
+fprintf(stderr, "poc\n" );
+ return( 1 );
+ }
+ }
+
+ /* 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 )
+ {
+ /* MPEG-2 */
+ i_packet_size = 8;
+ }
+ else if( (p_header[4] & 0xF0) == 0x20 )
+ {
+ /* MPEG-1 */
+ i_packet_size = 6;
+ }
+ else
+ {
+ intf_ErrMsg( "Unable to determine stream type" );
+ return( -1 );
+ }
+ }
+
+ /* 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 );
+ }
+
+ /* 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 );
+}
+
+
+/*****************************************************************************
+ * DVDRewind : reads a stream backward
+ *****************************************************************************/
+static int DVDRewind( input_thread_t * p_input )
+{
+ return( -1 );
+}
+
+/*****************************************************************************
+ * DVDSeek : Goes to a given position on the stream
+ *****************************************************************************/
+static int DVDSeek( input_thread_t * p_input, off_t i_off )
+{
+ return( -1 );
+}
+
+/*
+ * Packet management utilities
+ */
+
+/*****************************************************************************
+ * NewPacket: allocates a data packet
+ *****************************************************************************/
+static struct data_packet_s * NewPacket( void * p_garbage,
+ size_t i_size )
+{
+ data_packet_t * p_data;
+
+ /* Safety check */
+ if( i_size > INPUT_MAX_PACKET_SIZE )
+ {
+ intf_ErrMsg( "Packet too big (%d)", i_size );
+ return NULL;
+ }
+
+ if( (p_data = (data_packet_t *)malloc( sizeof(data_packet_t) )) == NULL )
+ {
+ intf_DbgMsg( "Out of memory" );
+ return NULL;
+ }
+
+ if( (p_data->p_buffer = (byte_t *)malloc( i_size )) == NULL )
+ {
+ intf_DbgMsg( "Out of memory" );
+ free( p_data );
+ return NULL;
+ }
+
+ /* Initialize data */
+ p_data->p_next = NULL;
+ p_data->b_discard_payload = 0;
+
+ p_data->p_payload_start = p_data->p_buffer;
+ p_data->p_payload_end = p_data->p_buffer + i_size;
+
+ return( p_data );
+}
+
+/*****************************************************************************
+ * NewPES: allocates a pes packet
+ *****************************************************************************/
+static pes_packet_t * NewPES( void * p_garbage )
+{
+ pes_packet_t * p_pes;
+
+ if( (p_pes = (pes_packet_t *)malloc( sizeof(pes_packet_t) )) == NULL )
+ {
+ intf_DbgMsg( "Out of memory" );
+ return NULL;
+ }
+
+ p_pes->b_messed_up = p_pes->b_data_alignment = p_pes->b_discontinuity =
+ p_pes->i_pts = p_pes->i_dts = 0;
+ p_pes->i_pes_size = 0;
+ p_pes->p_first = NULL;
+
+ return( p_pes );
+}
+
+/*****************************************************************************
+ * DeletePacket: deletes a data packet
+ *****************************************************************************/
+static void DeletePacket( void * p_garbage,
+ data_packet_t * p_data )
+{
+ ASSERT(p_data);
+ ASSERT(p_data->p_buffer);
+ free( p_data->p_buffer );
+ free( p_data );
+}
+
+/*****************************************************************************
+ * DeletePES: deletes a PES packet and associated data packets
+ *****************************************************************************/
+static void DeletePES( void * p_garbage, pes_packet_t * p_pes )
+{
+ data_packet_t * p_data;
+ data_packet_t * p_next;
+
+ p_data = p_pes->p_first;
+
+ while( p_data != NULL )
+ {
+ p_next = p_data->p_next;
+ free( p_data->p_buffer );
+ free( p_data );
+ p_data = p_next;
+ }
+
+ free( p_pes );
+}
+
+/*****************************************************************************
+ * DVDKludge: fakes a DVD plugin (FIXME)
+ *****************************************************************************/
+input_capabilities_t * DVDKludge( void )
+{
+ input_capabilities_t * p_plugin;
+
+ p_plugin = (input_capabilities_t *)malloc( sizeof(input_capabilities_t) );
+ p_plugin->pf_probe = DVDProbe;
+ p_plugin->pf_init = DVDInit;
+ p_plugin->pf_end = DVDEnd;
+ p_plugin->pf_read = DVDRead;
+ p_plugin->pf_demux = input_DemuxPS; /* FIXME: use i_p_config_t ! */
+ p_plugin->pf_new_packet = NewPacket;
+ p_plugin->pf_new_pes = NewPES;
+ p_plugin->pf_delete_packet = DeletePacket;
+ p_plugin->pf_delete_pes = DeletePES;
+ p_plugin->pf_rewind = DVDRewind;
+ p_plugin->pf_seek = DVDSeek;
+
+ return( p_plugin );
+}
--- /dev/null
+/*****************************************************************************
+ * input_dvd.h: thread structure of the DVD plugin
+ *****************************************************************************
+ * Copyright (C) 1999-2001 VideoLAN
+ *
+ * Author: Stéphane Borel <stef@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * thread_dvd_data_t: extension of input_thread_t for DVD specificity
+ *****************************************************************************/
+typedef struct thread_dvd_data_s
+{
+ /* Structure that contains all information of the DVD */
+ struct ifo_s ifo;
+} thread_dvd_data_t;
p_intf->p_input = input_CreateThread( p_input_config, NULL );
}
}
+ /* DVD mode */
+ else if( p_main->b_dvd )
+ {
+ if( (p_input_config =
+ (input_config_t *)malloc( sizeof(input_config_t) )) == NULL )
+ {
+ intf_ErrMsg( "intf error: cannot create input_config_t" );
+ }
+ else
+ {
+ p_input_config->i_method = INPUT_METHOD_DVD;
+ p_input_config->p_source = main_GetPszVariable( INPUT_DVD_DEVICE_VAR, INPUT_DVD_DEVICE_DEFAULT );
+ p_input_config->p_default_aout = p_main->p_aout;
+ p_input_config->p_default_vout = p_intf->p_vout;
+ p_intf->p_input = input_CreateThread( p_input_config, NULL );
+ }
+ }
/* Or if a file was specified */
else if( p_main->p_playlist->p_list != NULL )
{
* its own error messages */
intf_SelectChannel( p_intf, k_reply.param );
break;
- case INTF_KEY_INC_VOLUME: /* volume + */
+ case INTF_KEY_INC_VOLUME: /* volume + */
if( (p_main->p_aout != NULL) && (p_main->p_aout->vol < VOLUME_MAX) )
p_main->p_aout->vol += VOLUME_STEP;
break;
- case INTF_KEY_DEC_VOLUME: /* volume - */
+ case INTF_KEY_DEC_VOLUME: /* volume - */
if( (p_main->p_aout != NULL) && (p_main->p_aout->vol > VOLUME_STEP) )
p_main->p_aout->vol -= VOLUME_STEP;
break;
- case INTF_KEY_TOGGLE_VOLUME: /* toggle mute */
+ case INTF_KEY_TOGGLE_VOLUME: /* toggle mute */
if( (p_main->p_aout != NULL) && (p_main->p_aout->vol))
{
i_volbackup = p_main->p_aout->vol;
else if( (p_main->p_aout != NULL) && (!p_main->p_aout->vol))
p_main->p_aout->vol = i_volbackup;
break;
- case INTF_KEY_DEC_GAMMA: /* gamma - */
+ case INTF_KEY_DEC_GAMMA: /* gamma - */
if( (p_intf->p_vout != NULL) && (p_intf->p_vout->f_gamma > -INTF_GAMMA_LIMIT) )
{
vlc_mutex_lock( &p_intf->p_vout->change_lock );
vlc_mutex_unlock( &p_intf->p_vout->change_lock );
}
break;
- case INTF_KEY_INC_GAMMA: /* gamma + */
+ case INTF_KEY_INC_GAMMA: /* gamma + */
if( (p_intf->p_vout != NULL) && (p_intf->p_vout->f_gamma < INTF_GAMMA_LIMIT) )
{
vlc_mutex_lock( &p_intf->p_vout->change_lock );
vlc_mutex_unlock( &p_intf->p_vout->change_lock );
}
break;
- case INTF_KEY_TOGGLE_GRAYSCALE: /* toggle grayscale */
+ case INTF_KEY_TOGGLE_GRAYSCALE: /* toggle grayscale */
if( p_intf->p_vout != NULL )
{
vlc_mutex_lock( &p_intf->p_vout->change_lock );
vlc_mutex_unlock( &p_intf->p_vout->change_lock );
}
break;
- case INTF_KEY_TOGGLE_INTERFACE: /* toggle interface */
+ case INTF_KEY_TOGGLE_INTERFACE: /* toggle interface */
if( p_intf->p_vout != NULL )
{
vlc_mutex_lock( &p_intf->p_vout->change_lock );
vlc_mutex_unlock( &p_intf->p_vout->change_lock );
}
break;
- case INTF_KEY_TOGGLE_INFO: /* toggle info */
+ case INTF_KEY_TOGGLE_INFO: /* toggle info */
if( p_intf->p_vout != NULL )
{
vlc_mutex_lock( &p_intf->p_vout->change_lock );
vlc_mutex_unlock( &p_intf->p_vout->change_lock );
}
break;
- case INTF_KEY_TOGGLE_SCALING: /* toggle scaling */
+ case INTF_KEY_TOGGLE_SCALING: /* toggle scaling */
if( p_intf->p_vout != NULL )
{
vlc_mutex_lock( &p_intf->p_vout->change_lock );
#define OPT_SERVER 171
#define OPT_PORT 172
#define OPT_BROADCAST 173
+#define OPT_DVD 174
#define OPT_SYNCHRO 180
{ "server", 1, 0, OPT_SERVER },
{ "port", 1, 0, OPT_PORT },
{ "broadcast", 0, 0, OPT_BROADCAST },
+ { "dvd", 0, 0, OPT_DVD },
/* Synchro options */
{ "synchro", 1, 0, OPT_SYNCHRO },
p_main->b_audio = 1;
p_main->b_video = 1;
p_main->b_vlans = 0;
+ p_main->b_dvd = 0;
}
/*****************************************************************************
case OPT_BROADCAST: /* --broadcast */
main_PutIntVariable( INPUT_BROADCAST_VAR, 1 );
break;
+ case OPT_DVD: /* --dvd */
+ p_main->b_dvd = 1;
+ break;
/* Synchro options */
case OPT_SYNCHRO:
"\n --server <host> \tvideo server address"
"\n --port <port> \tvideo server port"
"\n --broadcast \tlisten to a broadcast"
+ "\n --dvd \tread dvd"
"\n"
"\n --synchro <type> \tforce synchro algorithm"
"\n"
"\n " INPUT_IFACE_VAR "=<interface> \tnetwork interface"
"\n " INPUT_BROADCAST_VAR "={1|0} \tbroadcast mode"
"\n " INPUT_VLAN_SERVER_VAR "=<hostname> \tvlan server"
- "\n " INPUT_VLAN_PORT_VAR "=<port> \tvlan server port" );
+ "\n " INPUT_VLAN_PORT_VAR "=<port> \tvlan server port"
+ "\n " INPUT_DVD_DEVICE_VAR "=<device> \tDVD device"
+ );
/* Synchro parameters */
intf_Msg( "\nSynchro parameters:"