X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Fvcd%2Fvcd.c;h=97e74547a2c2cdebd213b2f1a8557488be6c5958;hb=ae2c9e4fb61cd0be61d160d1d0c6aae353706497;hp=07956c8152256b5171c34b95c81c13233ec88037;hpb=7d2f6de57c4def2f33ff81c1f602621255c63a3c;p=vlc diff --git a/modules/access/vcd/vcd.c b/modules/access/vcd/vcd.c index 07956c8152..97e74547a2 100644 --- a/modules/access/vcd/vcd.c +++ b/modules/access/vcd/vcd.c @@ -1,8 +1,8 @@ /***************************************************************************** * vcd.c : VCD input module for vlc ***************************************************************************** - * Copyright (C) 2000 VideoLAN - * $Id: vcd.c,v 1.5 2002/08/29 23:53:22 massiot Exp $ + * Copyright (C) 2000-2004 the VideoLAN team + * $Id$ * * Author: Johan Bilien * @@ -10,396 +10,493 @@ * 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. + * 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., + * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ -#include -#include - -#include -#include -#include "../../demux/mpeg/system.h" - -#ifdef HAVE_UNISTD_H -# include +#ifdef HAVE_CONFIG_H +# include "config.h" #endif -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include -#if defined( WIN32 ) -# include /* read() */ -#endif - -#include "vcd.h" #include "cdrom.h" -/* how many blocks VCDRead will read in each loop */ -#define VCD_BLOCKS_ONCE 20 -#define VCD_DATA_ONCE (VCD_BLOCKS_ONCE * VCD_DATA_SIZE) - /***************************************************************************** - * Local prototypes + * Module descriptior *****************************************************************************/ -static int VCDOpen ( vlc_object_t * ); -static void VCDClose ( vlc_object_t * ); -static int VCDRead ( input_thread_t *, byte_t *, size_t ); -static void VCDSeek ( input_thread_t *, off_t ); -static int VCDSetArea ( input_thread_t *, input_area_t * ); -static int VCDSetProgram ( input_thread_t *, pgrm_descriptor_t * ); +static int Open ( vlc_object_t * ); +static void Close( vlc_object_t * ); + +#define CACHING_TEXT N_("Caching value in ms") +#define CACHING_LONGTEXT N_( \ + "Caching value for VCDs. This " \ + "value should be set in milliseconds." ) + +vlc_module_begin () + set_shortname( N_("VCD")) + set_description( N_("VCD input") ) + set_capability( "access", 60 ) + set_callbacks( Open, Close ) + set_category( CAT_INPUT ) + set_subcategory( SUBCAT_INPUT_ACCESS ) + + add_usage_hint( N_("[vcd:][device][@[title][,[chapter]]]") ) + add_integer( "vcd-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, + CACHING_LONGTEXT, true ) + add_shortcut( "vcd" ) + add_shortcut( "svcd" ) +vlc_module_end () /***************************************************************************** - * Module descriptior + * Local prototypes *****************************************************************************/ -vlc_module_begin(); - set_description( _("VCD input module") ); - set_capability( "access", 80 ); - set_callbacks( VCDOpen, VCDClose ); - add_shortcut( "svcd" ); -vlc_module_end(); -/* - * Data reading functions - */ +/* how many blocks VCDRead will read in each loop */ +#define VCD_BLOCKS_ONCE 20 +#define VCD_DATA_ONCE (VCD_BLOCKS_ONCE * VCD_DATA_SIZE) + +struct access_sys_t +{ + vcddev_t *vcddev; /* vcd device descriptor */ + + /* Title infos */ + int i_titles; + input_title_t *title[99]; /* No more that 99 track in a vcd ? */ + + + int i_sector; /* Current Sector */ + int *p_sectors; /* Track sectors */ +}; + +static block_t *Block( access_t * ); +static int Seek( access_t *, uint64_t ); +static int Control( access_t *, int, va_list ); +static int EntryPoints( access_t * ); /***************************************************************************** * VCDOpen: open vcd *****************************************************************************/ -static int VCDOpen( vlc_object_t *p_this ) +static int Open( vlc_object_t *p_this ) { - input_thread_t * p_input = (input_thread_t *)p_this; - char * psz_orig; - char * psz_parser; - char * psz_source; - char * psz_next; - struct stat stat_info; - thread_vcd_data_t * p_vcd; - int i; - input_area_t * p_area; - int i_title = 1; - int i_chapter = 1; - - p_input->pf_read = VCDRead; - p_input->pf_seek = VCDSeek; - p_input->pf_set_area = VCDSetArea; - p_input->pf_set_program = VCDSetProgram; - - /* parse the options passed in command line : */ - psz_orig = psz_parser = psz_source = strdup( p_input->psz_name ); - - if( !psz_orig ) - { - return( -1 ); - } - - while( *psz_parser && *psz_parser != '@' ) + access_t *p_access = (access_t *)p_this; + access_sys_t *p_sys; + if( p_access->psz_filepath == NULL ) + return VLC_EGENERIC; + + char *psz_dup = ToLocaleDup( p_access->psz_filepath ); + char *psz; + int i_title = 0; + int i_chapter = 0; + int i; + vcddev_t *vcddev; + + /* Command line: vcd://[dev_path][@title[,chapter]] */ + if( ( psz = strchr( psz_dup, '@' ) ) ) { - psz_parser++; + *psz++ = '\0'; + + i_title = strtol( psz, &psz, 0 ); + if( *psz ) + i_chapter = strtol( psz+1, &psz, 0 ); } - if( *psz_parser == '@' ) + if( *psz_dup == '\0' ) { - /* Found options */ - *psz_parser = '\0'; - ++psz_parser; - - i_title = (int)strtol( psz_parser, &psz_next, 10 ); - if( *psz_next ) - { - psz_parser = psz_next + 1; - i_chapter = (int)strtol( psz_parser, &psz_next, 10 ); - } + free( psz_dup ); - i_title = i_title ? i_title : 1; - i_chapter = i_chapter ? i_chapter : 1; - } + /* Only when selected */ + if( strcmp( p_access->psz_access, "vcd" ) && + strcmp( p_access->psz_access, "svcd" ) ) + return VLC_EGENERIC; - if( !*psz_source ) - { - if( !p_input->psz_access ) + psz_dup = var_CreateGetString( p_access, "vcd" ); + if( *psz_dup == '\0' ) { - free( psz_orig ); - return -1; + free( psz_dup ); + return VLC_EGENERIC; } - psz_source = config_GetPsz( p_input, "vcd" ); - } - - /* test the type of file given */ - - if( stat( psz_source, &stat_info ) == -1 ) - { - msg_Err( p_input, "cannot stat() source `%s' (%s)", - psz_source, strerror(errno)); - return( -1 ); } - - if( !S_ISBLK(stat_info.st_mode) && !S_ISCHR(stat_info.st_mode)) - { - msg_Warn( p_input, "vcd module discarded (not a valid drive)" ); - return -1; - } - - - p_vcd = malloc( sizeof(thread_vcd_data_t) ); - - if( p_vcd == NULL ) - { - msg_Err( p_input, "out of memory" ); - return -1; - } - - p_input->p_access_data = (void *)p_vcd; - - p_input->i_mtu = VCD_DATA_ONCE; - - vlc_mutex_lock( &p_input->stream.stream_lock ); - - p_input->stream.b_pace_control = 1; - p_input->stream.b_seekable = 1; - p_input->stream.p_selected_area->i_size = 0; - p_input->stream.p_selected_area->i_tell = 0; - - vlc_mutex_unlock( &p_input->stream.stream_lock ); +#ifdef WIN32 + if( psz_dup[0] && psz_dup[1] == ':' && + psz_dup[2] == '\\' && psz_dup[3] == '\0' ) psz_dup[2] = '\0'; +#endif - p_vcd->i_handle = open( psz_source, O_RDONLY | O_NONBLOCK ); - - if( p_vcd->i_handle == -1 ) - { - msg_Err( p_input, "could not open %s\n", psz_source ); - free (p_vcd); - return -1; - } + /* Open VCD */ + vcddev = ioctl_Open( p_this, psz_dup ); + free( psz_dup ); + if( !vcddev ) + return VLC_EGENERIC; + + /* Set up p_access */ + p_access->pf_read = NULL; + p_access->pf_block = Block; + p_access->pf_control = Control; + p_access->pf_seek = Seek; + p_access->info.i_update = 0; + p_access->info.i_size = 0; + p_access->info.i_pos = 0; + p_access->info.b_eof = false; + p_access->info.i_title = 0; + p_access->info.i_seekpoint = 0; + p_access->p_sys = p_sys = calloc( 1, sizeof( access_sys_t ) ); + if( !p_sys ) + goto error; + p_sys->vcddev = vcddev; /* We read the Table Of Content information */ - p_vcd->nb_tracks = ioctl_GetTrackCount( VLC_OBJECT( p_input), - p_vcd->i_handle, psz_source ); - if( p_vcd->nb_tracks < 0 ) + p_sys->i_titles = ioctl_GetTracksMap( VLC_OBJECT(p_access), + p_sys->vcddev, &p_sys->p_sectors ); + if( p_sys->i_titles < 0 ) { - msg_Err( p_input, "unable to count tracks" ); - close( p_vcd->i_handle ); - free( p_vcd ); - return -1; + msg_Err( p_access, "unable to count tracks" ); + goto error; } - else if( p_vcd->nb_tracks <= 1 ) + else if( p_sys->i_titles <= 1 ) { - msg_Err( p_input, "no movie tracks found" ); - close( p_vcd->i_handle ); - free( p_vcd ); - return -1; + msg_Err( p_access, "no movie tracks found" ); + goto error; } + /* The first title isn't usable */ + p_sys->i_titles--; - p_vcd->p_sectors = ioctl_GetSectors( VLC_OBJECT( p_input), - p_vcd->i_handle, psz_source ); - if( p_vcd->p_sectors == NULL ) + /* Build title table */ + for( i = 0; i < p_sys->i_titles; i++ ) { - input_BuffersEnd( p_input, p_input->p_method_data ); - close( p_vcd->i_handle ); - free( p_vcd ); - return -1; - } - - /* Set stream and area data */ - vlc_mutex_lock( &p_input->stream.stream_lock ); + input_title_t *t = p_sys->title[i] = vlc_input_title_New(); - /* Initialize ES structures */ - input_InitStream( p_input, sizeof( stream_ps_data_t ) ); + msg_Dbg( p_access, "title[%d] start=%d", i, p_sys->p_sectors[1+i] ); + msg_Dbg( p_access, "title[%d] end=%d", i, p_sys->p_sectors[i+2] ); - /* disc input method */ - p_input->stream.i_method = INPUT_METHOD_VCD; + t->i_size = ( p_sys->p_sectors[i+2] - p_sys->p_sectors[i+1] ) * + (int64_t)VCD_DATA_SIZE; + } -#define area p_input->stream.pp_areas - for( i = 1 ; i <= p_vcd->nb_tracks - 1 ; i++ ) + /* Map entry points into chapters */ + if( EntryPoints( p_access ) ) { - input_AddArea( p_input ); - - /* Titles are Program Chains */ - area[i]->i_id = i; - - /* Absolute start offset and size */ - area[i]->i_start = (off_t)p_vcd->p_sectors[i] * (off_t)VCD_DATA_SIZE; - area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i]) - * (off_t)VCD_DATA_SIZE; - - /* Number of chapters */ - area[i]->i_part_nb = 0; /* will be the entry points */ - area[i]->i_part = 1; - - area[i]->i_plugin_data = p_vcd->p_sectors[i]; + msg_Warn( p_access, "could not read entry points, will not use them" ); } -#undef area - p_area = p_input->stream.pp_areas[i_title]; + /* Starting title/chapter and sector */ + if( i_title >= p_sys->i_titles ) + i_title = 0; + if( i_chapter >= p_sys->title[i_title]->i_seekpoint ) + i_chapter = 0; - VCDSetArea( p_input, p_area ); + p_sys->i_sector = p_sys->p_sectors[1+i_title]; + if( i_chapter > 0 ) + { + p_sys->i_sector += + ( p_sys->title[i_title]->seekpoint[i_chapter]->i_byte_offset / + VCD_DATA_SIZE ); + } + p_access->info.i_title = i_title; + p_access->info.i_seekpoint = i_chapter; + p_access->info.i_size = p_sys->title[i_title]->i_size; + p_access->info.i_pos = ( p_sys->i_sector - p_sys->p_sectors[1+i_title] ) * + VCD_DATA_SIZE; - vlc_mutex_unlock( &p_input->stream.stream_lock ); + free( p_access->psz_demux ); + p_access->psz_demux = strdup( "ps" ); - p_input->psz_demux = "ps"; + return VLC_SUCCESS; - return 0; +error: + ioctl_Close( VLC_OBJECT(p_access), vcddev ); + free( p_sys ); + return VLC_EGENERIC; } /***************************************************************************** - * VCDClose: closes vcd + * Close: closes vcd *****************************************************************************/ -static void VCDClose( vlc_object_t *p_this ) +static void Close( vlc_object_t *p_this ) { - input_thread_t * p_input = (input_thread_t *)p_this; - thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data; + access_t *p_access = (access_t *)p_this; + access_sys_t *p_sys = p_access->p_sys; - close( p_vcd->i_handle ); - free( p_vcd ); + ioctl_Close( p_this, p_sys->vcddev ); + free( p_sys ); } /***************************************************************************** - * VCDRead: reads from the VCD into PES packets. - ***************************************************************************** - * Returns -1 in case of error, 0 in case of EOF, otherwise the number of - * bytes. + * Control: *****************************************************************************/ -static int VCDRead( input_thread_t * p_input, byte_t * p_buffer, - size_t i_len ) +static int Control( access_t *p_access, int i_query, va_list args ) { - thread_vcd_data_t * p_vcd; - int i_blocks; - int i_index; - int i_read; - byte_t p_last_sector[ VCD_DATA_SIZE ]; + access_sys_t *p_sys = p_access->p_sys; + input_title_t ***ppp_title; + int i; - p_vcd = (thread_vcd_data_t *)p_input->p_access_data; + switch( i_query ) + { + /* */ + case ACCESS_CAN_SEEK: + case ACCESS_CAN_FASTSEEK: + case ACCESS_CAN_PAUSE: + case ACCESS_CAN_CONTROL_PACE: + *va_arg( args, bool* ) = true; + break; + + /* */ + case ACCESS_GET_PTS_DELAY: + *va_arg( args, int64_t * ) + = (int64_t)var_GetInteger(p_access,"vcd-caching") * 1000; + break; + + /* */ + case ACCESS_SET_PAUSE_STATE: + break; + + case ACCESS_GET_TITLE_INFO: + ppp_title = va_arg( args, input_title_t*** ); + *va_arg( args, int* ) = p_sys->i_titles; + + /* Duplicate title infos */ + *ppp_title = malloc( sizeof(input_title_t **) * p_sys->i_titles ); + for( i = 0; i < p_sys->i_titles; i++ ) + { + (*ppp_title)[i] = vlc_input_title_Duplicate( p_sys->title[i] ); + } + break; + + case ACCESS_SET_TITLE: + i = va_arg( args, int ); + if( i != p_access->info.i_title ) + { + /* Update info */ + p_access->info.i_update |= + INPUT_UPDATE_TITLE|INPUT_UPDATE_SEEKPOINT|INPUT_UPDATE_SIZE; + p_access->info.i_title = i; + p_access->info.i_seekpoint = 0; + p_access->info.i_size = p_sys->title[i]->i_size; + p_access->info.i_pos = 0; + + /* Next sector to read */ + p_sys->i_sector = p_sys->p_sectors[1+i]; + } + break; + + case ACCESS_SET_SEEKPOINT: + { + input_title_t *t = p_sys->title[p_access->info.i_title]; + i = va_arg( args, int ); + if( t->i_seekpoint > 0 ) + { + p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT; + p_access->info.i_seekpoint = i; + + p_sys->i_sector = p_sys->p_sectors[1+p_access->info.i_title] + + t->seekpoint[i]->i_byte_offset / VCD_DATA_SIZE; + + p_access->info.i_pos = (uint64_t)(p_sys->i_sector - + p_sys->p_sectors[1+p_access->info.i_title]) *VCD_DATA_SIZE; + } + return VLC_SUCCESS; + } - i_read = 0; + case ACCESS_SET_PRIVATE_ID_STATE: + case ACCESS_GET_CONTENT_TYPE: + return VLC_EGENERIC; - /* Compute the number of blocks we have to read */ + default: + msg_Warn( p_access, "unimplemented query in control" ); + return VLC_EGENERIC; - i_blocks = i_len / VCD_DATA_SIZE; + } + return VLC_SUCCESS; +} - for ( i_index = 0 ; i_index < i_blocks ; i_index++ ) +/***************************************************************************** + * Block: + *****************************************************************************/ +static block_t *Block( access_t *p_access ) +{ + access_sys_t *p_sys = p_access->p_sys; + int i_blocks = VCD_BLOCKS_ONCE; + block_t *p_block; + int i_read; + + /* Check end of file */ + if( p_access->info.b_eof ) return NULL; + + /* Check end of title */ + while( p_sys->i_sector >= p_sys->p_sectors[p_access->info.i_title + 2] ) { - if ( ioctl_ReadSector( VLC_OBJECT(p_input), p_vcd->i_handle, - p_vcd->i_sector, p_buffer + i_index * VCD_DATA_SIZE ) < 0 ) + if( p_access->info.i_title + 2 >= p_sys->i_titles ) { - msg_Err( p_input, "could not read sector %d", p_vcd->i_sector ); - return -1; + p_access->info.b_eof = true; + return NULL; } - p_vcd->i_sector ++; - if ( p_vcd->i_sector == p_vcd->p_sectors[p_vcd->i_track + 1] ) - { - input_area_t *p_area; - - if ( p_vcd->i_track >= p_vcd->nb_tracks - 1 ) - return 0; /* EOF */ - - p_area = p_input->stream.pp_areas[ - p_input->stream.p_selected_area->i_id + 1 ]; - - msg_Dbg( p_input, "new title" ); - - p_area->i_part = 1; - VCDSetArea( p_input, p_area ); - - } - i_read += VCD_DATA_SIZE; + p_access->info.i_update |= + INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT | INPUT_UPDATE_SIZE; + p_access->info.i_title++; + p_access->info.i_seekpoint = 0; + p_access->info.i_size = + p_sys->title[p_access->info.i_title]->i_size; + p_access->info.i_pos = 0; + } + + /* Don't read after the end of a title */ + if( p_sys->i_sector + i_blocks >= + p_sys->p_sectors[p_access->info.i_title + 2] ) + { + i_blocks = p_sys->p_sectors[p_access->info.i_title + 2 ] - + p_sys->i_sector; + } + + /* Do the actual reading */ + if( !( p_block = block_New( p_access, i_blocks * VCD_DATA_SIZE ) ) ) + { + msg_Err( p_access, "cannot get a new block of size: %i", + i_blocks * VCD_DATA_SIZE ); + return NULL; } - - if ( i_len % VCD_DATA_SIZE ) /* this should not happen */ - { - if ( ioctl_ReadSector( VLC_OBJECT(p_input), p_vcd->i_handle, - p_vcd->i_sector, p_last_sector ) < 0 ) + + if( ioctl_ReadSectors( VLC_OBJECT(p_access), p_sys->vcddev, + p_sys->i_sector, p_block->p_buffer, i_blocks, VCD_TYPE ) < 0 ) + { + msg_Err( p_access, "cannot read sector %i", p_sys->i_sector ); + block_Release( p_block ); + + /* Try to skip one sector (in case of bad sectors) */ + p_sys->i_sector++; + p_access->info.i_pos += VCD_DATA_SIZE; + return NULL; + } + + /* Update seekpoints */ + for( i_read = 0; i_read < i_blocks; i_read++ ) + { + input_title_t *t = p_sys->title[p_access->info.i_title]; + + if( t->i_seekpoint > 0 && + p_access->info.i_seekpoint + 1 < t->i_seekpoint && + p_access->info.i_pos + i_read * VCD_DATA_SIZE >= + t->seekpoint[p_access->info.i_seekpoint+1]->i_byte_offset ) { - msg_Err( p_input, "could not read sector %d", p_vcd->i_sector ); - return -1; + msg_Dbg( p_access, "seekpoint change" ); + p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT; + p_access->info.i_seekpoint++; } - - p_input->p_vlc->pf_memcpy( p_buffer + i_blocks * VCD_DATA_SIZE, - p_last_sector, i_len % VCD_DATA_SIZE ); - i_read += i_len % VCD_DATA_SIZE; } - - p_input->stream.p_selected_area->i_tell = - (off_t)p_vcd->i_sector * (off_t)VCD_DATA_SIZE - - p_input->stream.p_selected_area->i_start; - return i_read; -} + /* Update a few values */ + p_sys->i_sector += i_blocks; + p_access->info.i_pos += p_block->i_buffer; + return p_block; +} /***************************************************************************** - * VCDSetProgram: Does nothing since a VCD is mono_program + * Seek: *****************************************************************************/ -static int VCDSetProgram( input_thread_t * p_input, - pgrm_descriptor_t * p_program) +static int Seek( access_t *p_access, uint64_t i_pos ) { - return 0; -} + access_sys_t *p_sys = p_access->p_sys; + input_title_t *t = p_sys->title[p_access->info.i_title]; + int i_seekpoint; + /* Next sector to read */ + p_access->info.i_pos = i_pos; + p_sys->i_sector = i_pos / VCD_DATA_SIZE + + p_sys->p_sectors[p_access->info.i_title + 1]; + + /* Update current seekpoint */ + for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ ) + { + if( i_seekpoint + 1 >= t->i_seekpoint ) break; + if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break; + } + + if( i_seekpoint != p_access->info.i_seekpoint ) + { + msg_Dbg( p_access, "seekpoint change" ); + p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT; + p_access->info.i_seekpoint = i_seekpoint; + } + + /* Reset eof */ + p_access->info.b_eof = false; + + return VLC_SUCCESS; +} /***************************************************************************** - * VCDSetArea: initialize input data for title x, chapter y. - * It should be called for each user navigation request. - ****************************************************************************/ -static int VCDSetArea( input_thread_t * p_input, input_area_t * p_area ) + * EntryPoints: Reads the information about the entry points on the disc. + *****************************************************************************/ +static int EntryPoints( access_t *p_access ) { - thread_vcd_data_t * p_vcd; - - p_vcd = (thread_vcd_data_t*)p_input->p_access_data; + access_sys_t *p_sys = p_access->p_sys; + uint8_t sector[VCD_DATA_SIZE]; - /* we can't use the interface slider until initilization is complete */ - p_input->stream.b_seekable = 0; + entries_sect_t entries; + int i_nb, i; - if( p_area != p_input->stream.p_selected_area ) + /* Read the entry point sector */ + if( ioctl_ReadSectors( VLC_OBJECT(p_access), p_sys->vcddev, + VCD_ENTRIES_SECTOR, sector, 1, VCD_TYPE ) < 0 ) { - /* Reset the Chapter position of the current title */ - p_input->stream.p_selected_area->i_part = 1; - p_input->stream.p_selected_area->i_tell = 0; - - /* Change the default area */ - p_input->stream.p_selected_area = p_area; + msg_Err( p_access, "could not read entry points sector" ); + return VLC_EGENERIC; + } + memcpy( &entries, sector, CD_SECTOR_SIZE ); - /* Change the current track */ - /* The first track is not a valid one */ - p_vcd->i_track = p_area->i_id; - p_vcd->i_sector = p_vcd->p_sectors[p_vcd->i_track]; + i_nb = GetWBE( &entries.i_entries_nb ); + if( i_nb > 500 ) + { + msg_Err( p_access, "invalid entry points number" ); + return VLC_EGENERIC; } - /* warn interface that something has changed */ - p_input->stream.b_seekable = 1; - p_input->stream.b_changed = 1; + if( strncmp( entries.psz_id, "ENTRYVCD", sizeof( entries.psz_id ) ) && + strncmp( entries.psz_id, "ENTRYSVD", sizeof( entries.psz_id ) ) ) + { + msg_Err( p_access, "unrecognized entry points format" ); + return VLC_EGENERIC; + } - return 0; -} + for( i = 0; i < i_nb; i++ ) + { + const int i_title = BCD_TO_BIN(entries.entry[i].i_track) - 2; + const int i_sector = + (MSF_TO_LBA2( BCD_TO_BIN( entries.entry[i].msf.minute ), + BCD_TO_BIN( entries.entry[i].msf.second ), + BCD_TO_BIN( entries.entry[i].msf.frame ) )); + seekpoint_t *s; + if( i_title < 0 ) continue; /* Should not occur */ + if( i_title >= p_sys->i_titles ) continue; -/**************************************************************************** - * VCDSeek - ****************************************************************************/ -static void VCDSeek( input_thread_t * p_input, off_t i_off ) -{ - thread_vcd_data_t * p_vcd; + msg_Dbg( p_access, "Entry[%d] title=%d sector=%d", + i, i_title, i_sector ); - p_vcd = (thread_vcd_data_t *) p_input->p_access_data; + s = vlc_seekpoint_New(); + s->i_byte_offset = (i_sector - p_sys->p_sectors[i_title+1]) * + VCD_DATA_SIZE; - p_vcd->i_sector = p_vcd->p_sectors[p_vcd->i_track] - + i_off / (off_t)VCD_DATA_SIZE; + TAB_APPEND( p_sys->title[i_title]->i_seekpoint, + p_sys->title[i_title]->seekpoint, s ); + } - p_input->stream.p_selected_area->i_tell = - (off_t)p_vcd->i_sector * (off_t)VCD_DATA_SIZE - - p_input->stream.p_selected_area->i_start; + return VLC_SUCCESS; } +