X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Fvcd%2Fvcd.c;h=575ff326686a9b0343a577442561414b1196f725;hb=6903d514d3ea8113f91b1bedde862607f7efc92a;hp=57e1cbf534f479344e134126ae312cffa30296be;hpb=8aa24cfe361b893a626016211e05f41c544f5c1b;p=vlc diff --git a/modules/access/vcd/vcd.c b/modules/access/vcd/vcd.c index 57e1cbf534..575ff32668 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.22 2003/05/22 12:00:57 gbazin Exp $ + * Copyright (C) 2000-2004 the VideoLAN team + * $Id$ * * Author: Johan Bilien * @@ -18,538 +18,493 @@ * * 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. + * 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 "cdrom.h" +/***************************************************************************** + * Module descriptior + *****************************************************************************/ +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(); + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ + /* how many blocks VCDRead will read in each loop */ #define VCD_BLOCKS_ONCE 20 #define VCD_DATA_ONCE (VCD_BLOCKS_ONCE * VCD_DATA_SIZE) -/***************************************************************************** - * thread_vcd_data_t: VCD information - *****************************************************************************/ -typedef struct thread_vcd_data_s +struct access_sys_t { vcddev_t *vcddev; /* vcd device descriptor */ - int i_nb_tracks; /* Nb of tracks (titles) */ - int i_track; /* Current track */ - int i_sector; /* Current Sector */ - int * p_sectors; /* Track sectors */ - int i_entries_nb; /* Number of entry points */ - int * p_entries; /* Entry points */ - vlc_bool_t b_valid_ep; /* Valid entry points flag */ - vlc_bool_t b_end_of_track; /* If the end of track was reached */ -} thread_vcd_data_t; + /* Title infos */ + int i_titles; + input_title_t *title[99]; /* No more that 99 track in a vcd ? */ -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -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 VCDEntryPoints ( input_thread_t * ); -/***************************************************************************** - * Module descriptior - *****************************************************************************/ -vlc_module_begin(); - set_description( _("VCD input") ); - set_capability( "access", 80 ); - set_callbacks( VCDOpen, VCDClose ); - add_shortcut( "svcd" ); -vlc_module_end(); + int i_sector; /* Current Sector */ + int *p_sectors; /* Track sectors */ +}; -/* - * Data reading functions - */ +static block_t *Block( access_t * ); +static int Seek( access_t *, int64_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; - thread_vcd_data_t * p_vcd; - int i; - input_area_t * p_area; - int i_title = 1; - int i_chapter = 1; - vcddev_t *vcddev; - - /* parse the options passed in command line : */ - psz_orig = psz_parser = psz_source = strdup( p_input->psz_name ); - - if( !psz_orig ) + access_t *p_access = (access_t *)p_this; + access_sys_t *p_sys; + char *psz_dup = ToLocaleDup( p_access->psz_path ); + 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, '@' ) ) ) { - return( -1 ); - } + *psz++ = '\0'; - while( *psz_parser && *psz_parser != '@' ) - { - psz_parser++; + 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; + free( psz_dup ); - 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 ); - } - - 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" ); - if( !psz_source ) return -1; } - /* Open VCD */ - if( !(vcddev = ioctl_Open( p_this, psz_source )) ) - { - msg_Warn( p_input, "could not open %s", psz_source ); - free( psz_source ); - return -1; - } +#ifdef WIN32 + if( psz_dup[0] && psz_dup[1] == ':' && + psz_dup[2] == '\\' && psz_dup[3] == '\0' ) psz_dup[2] = '\0'; +#endif - p_vcd = malloc( sizeof(thread_vcd_data_t) ); - if( p_vcd == NULL ) + /* Open VCD */ + if( !(vcddev = ioctl_Open( p_this, psz_dup )) ) { - msg_Err( p_input, "out of memory" ); - free( psz_source ); - return -1; + free( psz_dup ); + return VLC_EGENERIC; } - free( psz_source ); - - p_vcd->vcddev = vcddev; - 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 ); + free( psz_dup ); + + /* 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 = malloc( sizeof( access_sys_t ) ); + memset( p_sys, 0, sizeof( access_sys_t ) ); + p_sys->vcddev = vcddev; /* We read the Table Of Content information */ - p_vcd->i_nb_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input), - p_vcd->vcddev, &p_vcd->p_sectors ); - if( p_vcd->i_nb_tracks < 0 ) - msg_Err( p_input, "unable to count tracks" ); - else if( p_vcd->i_nb_tracks <= 1 ) - msg_Err( p_input, "no movie tracks found" ); - if( p_vcd->i_nb_tracks <= 1) + p_sys->i_titles = ioctl_GetTracksMap( VLC_OBJECT(p_access), + p_sys->vcddev, &p_sys->p_sectors ); + if( p_sys->i_titles < 0 ) { - ioctl_Close( p_this, p_vcd->vcddev ); - free( p_vcd ); - return -1; + msg_Err( p_access, "unable to count tracks" ); + goto error; } - - /* Allocate the entry points table */ - p_vcd->p_entries = malloc( p_vcd->i_nb_tracks * sizeof( int ) ); - - if( p_vcd->p_entries == NULL ) + else if( p_sys->i_titles <= 1 ) { - msg_Err( p_input, "not enough memory" ); - ioctl_Close( p_this, p_vcd->vcddev ); - free( p_vcd ); + msg_Err( p_access, "no movie tracks found" ); + goto error; } + /* The first title isn't usable */ + p_sys->i_titles--; - /* Set stream and area data */ - vlc_mutex_lock( &p_input->stream.stream_lock ); - - /* Initialize ES structures */ - input_InitStream( p_input, sizeof( stream_ps_data_t ) ); - - /* disc input method */ - p_input->stream.i_method = INPUT_METHOD_VCD; - - p_input->stream.i_area_nb = 1; - -#define area p_input->stream.pp_areas - for( i = 1 ; i <= p_vcd->i_nb_tracks - 1 ; i++ ) + /* Build title table */ + for( i = 0; i < p_sys->i_titles; i++ ) { - /* Titles are Program Chains */ - input_AddArea( p_input, i, 1 ); + input_title_t *t = p_sys->title[i] = vlc_input_title_New(); - /* 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; + msg_Dbg( p_access, "title[%d] start=%d\n", i, p_sys->p_sectors[1+i] ); + msg_Dbg( p_access, "title[%d] end=%d\n", i, p_sys->p_sectors[i+2] ); - /* Default Chapter */ - area[i]->i_part = 1; - - /* i_plugin_data is used to store which entry point is the first - * of the track (area) */ - area[i]->i_plugin_data = 0; + t->i_size = ( p_sys->p_sectors[i+2] - p_sys->p_sectors[i+1] ) * + (int64_t)VCD_DATA_SIZE; } -#undef area - - p_area = p_input->stream.pp_areas[i_title]; - p_vcd->b_valid_ep = 1; - if( VCDEntryPoints( p_input ) < 0 ) + /* Map entry points into chapters */ + if( EntryPoints( p_access ) ) { - msg_Warn( p_input, "could not read entry points, will not use them" ); - p_vcd->b_valid_ep = 0; + msg_Warn( p_access, "could not read entry points, will not use them" ); } - VCDSetArea( p_input, p_area ); - - vlc_mutex_unlock( &p_input->stream.stream_lock ); + /* 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; - if( !p_input->psz_demux || !*p_input->psz_demux ) + p_sys->i_sector = p_sys->p_sectors[1+i_title]; + if( i_chapter > 0 ) { - p_input->psz_demux = "ps"; + 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; - p_input->pf_read = VCDRead; - p_input->pf_seek = VCDSeek; - p_input->pf_set_area = VCDSetArea; - p_input->pf_set_program = VCDSetProgram; + free( p_access->psz_demux ); + p_access->psz_demux = strdup( "ps" ); - return 0; + return VLC_SUCCESS; + +error: + ioctl_Close( VLC_OBJECT(p_access), p_sys->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; - ioctl_Close( p_this, p_vcd->vcddev ); - 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 ]; - - p_vcd = (thread_vcd_data_t *)p_input->p_access_data; - - i_read = 0; - - /* Compute the number of blocks we have to read */ - - i_blocks = i_len / VCD_DATA_SIZE; - - for ( i_index = 0 ; i_index < i_blocks ; i_index++ ) + access_sys_t *p_sys = p_access->p_sys; + bool *pb_bool; + int *pi_int; + int64_t *pi_64; + input_title_t ***ppp_title; + int i; + + switch( i_query ) { - if ( ioctl_ReadSectors( VLC_OBJECT(p_input), p_vcd->vcddev, - p_vcd->i_sector, p_buffer + i_index * VCD_DATA_SIZE, 1, - VCD_TYPE ) < 0 ) - { - msg_Err( p_input, "could not read sector %d", p_vcd->i_sector ); - return -1; - } - - 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->i_nb_tracks - 1 ) - return 0; /* EOF */ - - vlc_mutex_lock( &p_input->stream.stream_lock ); - p_area = p_input->stream.pp_areas[ - p_input->stream.p_selected_area->i_id + 1 ]; - - msg_Dbg( p_input, "new title" ); + /* */ + case ACCESS_CAN_SEEK: + case ACCESS_CAN_FASTSEEK: + case ACCESS_CAN_PAUSE: + case ACCESS_CAN_CONTROL_PACE: + pb_bool = (bool*)va_arg( args, bool* ); + *pb_bool = true; + break; + + /* */ + case ACCESS_GET_MTU: + pi_int = (int*)va_arg( args, int * ); + *pi_int = VCD_DATA_ONCE; + break; + + case ACCESS_GET_PTS_DELAY: + pi_64 = (int64_t*)va_arg( args, int64_t * ); + *pi_64 = var_GetInteger( p_access, "vcd-caching" ) * 1000; + break; + + /* */ + case ACCESS_SET_PAUSE_STATE: + break; + + case ACCESS_GET_TITLE_INFO: + ppp_title = (input_title_t***)va_arg( args, input_title_t*** ); + pi_int = (int*)va_arg( args, int* ); + + /* Duplicate title infos */ + *pi_int = p_sys->i_titles; + *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; - p_area->i_part = 1; - VCDSetArea( p_input, p_area ); - vlc_mutex_unlock( &p_input->stream.stream_lock ); - } + case ACCESS_SET_TITLE: + i = (int)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; - /* Update chapter */ - else if( p_vcd->b_valid_ep && - /* FIXME kludge so that read does not update chapter - * when a manual chapter change was requested and not - * yet accomplished */ - !p_input->stream.p_new_area ) + case ACCESS_SET_SEEKPOINT: { - int i_entry; - - vlc_mutex_lock( &p_input->stream.stream_lock ); - i_entry = p_input->stream.p_selected_area->i_plugin_data - /* 1st entry point of the track (area)*/ - + p_input->stream.p_selected_area->i_part - 1; - if( i_entry + 1 < p_vcd->i_entries_nb && - p_vcd->i_sector >= p_vcd->p_entries[i_entry + 1] ) + input_title_t *t = p_sys->title[p_access->info.i_title]; + i = (int)va_arg( args, int ); + if( t->i_seekpoint > 0 ) { - msg_Dbg( p_input, "new chapter" ); - p_input->stream.p_selected_area->i_part ++; + 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 = (int64_t)(p_sys->i_sector - + p_sys->p_sectors[1+p_access->info.i_title]) *VCD_DATA_SIZE; } - vlc_mutex_unlock( &p_input->stream.stream_lock ); + return VLC_SUCCESS; } - i_read += VCD_DATA_SIZE; - } + case ACCESS_SET_PRIVATE_ID_STATE: + case ACCESS_GET_CONTENT_TYPE: + return VLC_EGENERIC; - if ( i_len % VCD_DATA_SIZE ) /* this should not happen */ - { - if ( ioctl_ReadSectors( VLC_OBJECT(p_input), p_vcd->vcddev, - p_vcd->i_sector, p_last_sector, 1, VCD_TYPE ) < 0 ) - { - msg_Err( p_input, "could not read sector %d", p_vcd->i_sector ); - return -1; - } + default: + msg_Warn( p_access, "unimplemented query in control" ); + return VLC_EGENERIC; - 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; } - - return i_read; + return VLC_SUCCESS; } /***************************************************************************** - * VCDSetProgram: Does nothing since a VCD is mono_program + * Block: *****************************************************************************/ -static int VCDSetProgram( input_thread_t * p_input, - pgrm_descriptor_t * p_program) -{ - return 0; -} - -/***************************************************************************** - * 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 ) +static block_t *Block( access_t *p_access ) { - thread_vcd_data_t * p_vcd; - vlc_value_t val; + access_sys_t *p_sys = p_access->p_sys; + int i_blocks = VCD_BLOCKS_ONCE; + block_t *p_block; + int i_read; - p_vcd = (thread_vcd_data_t*)p_input->p_access_data; + /* Check end of file */ + if( p_access->info.b_eof ) return NULL; - /* we can't use the interface slider until initilization is complete */ - p_input->stream.b_seekable = 0; - - if( p_area != p_input->stream.p_selected_area ) + /* Check end of title */ + while( p_sys->i_sector >= p_sys->p_sectors[p_access->info.i_title + 2] ) { - unsigned int i; - - /* 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; + if( p_access->info.i_title + 2 >= p_sys->i_titles ) + { + p_access->info.b_eof = true; + return NULL; + } - /* Change the default area */ - p_input->stream.p_selected_area = p_area; + 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; + } - /* 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]; + /* 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; + } - /* Update the navigation variables without triggering a callback */ - val.i_int = p_area->i_id; - var_Change( p_input, "title", VLC_VAR_SETVALUE, &val, NULL ); - var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL ); - for( i = 1; i <= p_area->i_part_nb; i++ ) - { - val.i_int = i; - var_Change( p_input, "chapter", VLC_VAR_ADDCHOICE, &val, NULL ); - } + /* 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( p_vcd->b_valid_ep ) + if( ioctl_ReadSectors( VLC_OBJECT(p_access), p_sys->vcddev, + p_sys->i_sector, p_block->p_buffer, i_blocks, VCD_TYPE ) < 0 ) { - int i_entry = p_area->i_plugin_data /* 1st entry point of - the track (area)*/ - + p_area->i_part - 1; - p_vcd->i_sector = p_vcd->p_entries[i_entry]; + 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; } - else - p_vcd->i_sector = p_vcd->p_sectors[p_vcd->i_track]; - 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; + /* Update seekpoints */ + for( i_read = 0; i_read < i_blocks; i_read++ ) + { + input_title_t *t = p_sys->title[p_access->info.i_title]; - /* warn interface that something has changed */ - p_input->stream.b_seekable = 1; - p_input->stream.b_changed = 1; + 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_Dbg( p_access, "seekpoint change" ); + p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT; + p_access->info.i_seekpoint++; + } + } - /* Update the navigation variables without triggering a callback */ - val.i_int = p_area->i_part; - var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &val, NULL ); + /* Update a few values */ + p_sys->i_sector += i_blocks; + p_access->info.i_pos += p_block->i_buffer; - return 0; + return p_block; } -/**************************************************************************** - * VCDSeek - ****************************************************************************/ -static void VCDSeek( input_thread_t * p_input, off_t i_off ) +/***************************************************************************** + * Seek: + *****************************************************************************/ +static int Seek( access_t *p_access, int64_t i_pos ) { - thread_vcd_data_t * p_vcd; - unsigned int i_index; + access_sys_t *p_sys = p_access->p_sys; + input_title_t *t = p_sys->title[p_access->info.i_title]; + int i_seekpoint; - p_vcd = (thread_vcd_data_t *) p_input->p_access_data; + /* 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]; - p_vcd->i_sector = p_vcd->p_sectors[p_vcd->i_track] - + i_off / (off_t)VCD_DATA_SIZE; + /* 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; + } - vlc_mutex_lock( &p_input->stream.stream_lock ); -#define p_area p_input->stream.p_selected_area - /* Find chapter */ - if( p_vcd->b_valid_ep ) + if( i_seekpoint != p_access->info.i_seekpoint ) { - for( i_index = 0 ; i_index < p_area->i_part_nb - 1 ; i_index ++ ) - { - if( p_vcd->i_sector < p_vcd->p_entries[p_area->i_plugin_data - + i_index + 1] ) - { - p_area->i_part = i_index; - break; - } - } + msg_Dbg( p_access, "seekpoint change" ); + p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT; + p_access->info.i_seekpoint = i_seekpoint; } -#undef p_area - 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; - vlc_mutex_unlock( &p_input->stream.stream_lock ); + /* Reset eof */ + p_access->info.b_eof = false; + + return VLC_SUCCESS; } /***************************************************************************** - * VCDEntryPoints: Reads the information about the entry points on the disc. + * EntryPoints: Reads the information about the entry points on the disc. *****************************************************************************/ -static int VCDEntryPoints( input_thread_t * p_input ) +static int EntryPoints( access_t *p_access ) { - thread_vcd_data_t * p_vcd; - byte_t * p_sector; - entries_sect_t entries; - uint16_t i_nb; - int i, i_entry_index = 0; - int i_previous_track = -1; + access_sys_t *p_sys = p_access->p_sys; + uint8_t sector[VCD_DATA_SIZE]; - p_vcd = (thread_vcd_data_t *) p_input->p_access_data; + entries_sect_t entries; + int i_nb, i; - p_sector = malloc( VCD_DATA_SIZE * sizeof( byte_t ) ); - if( p_sector == NULL ) + /* Read the entry point sector */ + if( ioctl_ReadSectors( VLC_OBJECT(p_access), p_sys->vcddev, + VCD_ENTRIES_SECTOR, sector, 1, VCD_TYPE ) < 0 ) { - msg_Err( p_input, "not enough memory for entry points treatment" ); - return -1; + msg_Err( p_access, "could not read entry points sector" ); + return VLC_EGENERIC; } + memcpy( &entries, sector, CD_SECTOR_SIZE ); - if( ioctl_ReadSectors( VLC_OBJECT(p_input), p_vcd->vcddev, - VCD_ENTRIES_SECTOR, p_sector, 1, VCD_TYPE ) < 0 ) + i_nb = GetWBE( &entries.i_entries_nb ); + if( i_nb > 500 ) { - msg_Err( p_input, "could not read entry points sector" ); - free( p_sector ); - return( -1 ); + msg_Err( p_access, "invalid entry points number" ); + return VLC_EGENERIC; } - memcpy( &entries, p_sector, CD_SECTOR_SIZE ); - free( p_sector ); - - if( (i_nb = U16_AT( &entries.i_entries_nb )) > 500 ) + if( strncmp( entries.psz_id, "ENTRYVCD", sizeof( entries.psz_id ) ) && + strncmp( entries.psz_id, "ENTRYSVD", sizeof( entries.psz_id ) ) ) { - msg_Err( p_input, "invalid entry points number" ); - return( -1 ); + msg_Err( p_access, "unrecognized entry points format" ); + return VLC_EGENERIC; } - p_vcd->p_entries = malloc( sizeof( int ) * i_nb ); - if( p_vcd->p_entries == NULL ) + for( i = 0; i < i_nb; i++ ) { - msg_Err( p_input, "not enough memory for entry points treatment" ); - return -1; - } + 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( strncmp( entries.psz_id, "ENTRYVCD", sizeof( entries.psz_id ) ) - && strncmp( entries.psz_id, "ENTRYSVD", sizeof( entries.psz_id ) )) - { - msg_Err( p_input, "unrecognized entry points format" ); - free( p_vcd->p_entries ); - return -1; - } + if( i_title < 0 ) continue; /* Should not occur */ + if( i_title >= p_sys->i_titles ) continue; - p_vcd->i_entries_nb = 0; + msg_Dbg( p_access, "Entry[%d] title=%d sector=%d\n", + i, i_title, i_sector ); -#define i_track BCD_TO_BIN(entries.entry[i].i_track) - for( i = 0 ; i < i_nb ; i++ ) - { - if( i_track <= p_input->stream.i_area_nb ) - { - p_vcd->p_entries[i_entry_index] = - (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 ) )); - p_input->stream.pp_areas[i_track-1]->i_part_nb ++; - /* if this entry belongs to a new track */ - if( i_track != i_previous_track ) - { - /* i_plugin_data is used to store the first entry of the area*/ - p_input->stream.pp_areas[i_track-1]->i_plugin_data = - i_entry_index; - i_previous_track = i_track; - } - i_entry_index ++; - p_vcd->i_entries_nb ++; - } - else - msg_Warn( p_input, "wrong track number found in entry points" ); + s = vlc_seekpoint_New(); + s->i_byte_offset = (i_sector - p_sys->p_sectors[i_title+1]) * + VCD_DATA_SIZE; + + TAB_APPEND( p_sys->title[i_title]->i_seekpoint, + p_sys->title[i_title]->seekpoint, s ); } -#undef i_track - return 0; + + return VLC_SUCCESS; } +