X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=plugins%2Fvcd%2Finput_vcd.c;h=fa850ba7c5e2aa6af189645016d34ff2c870ea00;hb=d4f18c4eadb23de73e7ae1d1e2e899cbbfbef567;hp=ad5d1813e1030f7f429916114edc2127a162bdf6;hpb=248eb0b5b90523c8929c33dae781ca5b500c906d;p=vlc diff --git a/plugins/vcd/input_vcd.c b/plugins/vcd/input_vcd.c index ad5d1813e1..fa850ba7c5 100644 --- a/plugins/vcd/input_vcd.c +++ b/plugins/vcd/input_vcd.c @@ -20,50 +20,34 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************/ -#define MODULE_NAME vcd -#include "modules_inner.h" - /***************************************************************************** * Preamble *****************************************************************************/ -#include "defs.h" - #include #include +#include + #ifdef HAVE_UNISTD_H # include #endif #include #include +#include #include #include -#ifdef STRNCASECMP_IN_STRINGS_H -# include -#endif - #if defined( WIN32 ) # include /* read() */ #else # include /* struct iovec */ #endif - -#include "config.h" -#include "common.h" -#include "intf_msg.h" -#include "threads.h" -#include "mtime.h" -#include "tests.h" - #if defined( WIN32 ) # include "input_iovec.h" #endif -#include "main.h" - #include "stream_control.h" #include "input_ext-intf.h" #include "input_ext-dec.h" @@ -71,236 +55,193 @@ #include "debug.h" -#include "modules.h" -#include "modules_export.h" - -#include "../mpeg/input_ps.h" #include "input_vcd.h" -#include "linux_cdrom_tools.h" +#include "cdrom_tools.h" /* how many blocks VCDRead will read in each loop */ -#define VCD_BLOCKS_ONCE 64 -#define VCD_DATA_ONCE (2 * VCD_BLOCKS_ONCE) -#define BUFFER_SIZE VCD_DATA_SIZE - - +#define VCD_BLOCKS_ONCE 20 +#define VCD_DATA_ONCE (VCD_BLOCKS_ONCE * VCD_DATA_SIZE) /***************************************************************************** * Local prototypes *****************************************************************************/ /* called from outside */ -static int VCDProbe ( probedata_t *p_data ); -static void VCDInit ( struct input_thread_s * ); -static int VCDRead ( struct input_thread_s *, data_packet_t ** ); -static int VCDSetArea ( struct input_thread_s *, struct input_area_s * ); -static void VCDOpen ( struct input_thread_s *); -static void VCDClose ( struct input_thread_s *); -static void VCDEnd ( struct input_thread_s *); -static void VCDSeek ( struct input_thread_s *, off_t ); -static int VCDRewind ( struct input_thread_s * ); -static struct data_packet_s * NewPacket( void *, size_t ); -static pes_packet_t * NewPES ( void * ); -static void DeletePacket ( void *, data_packet_t * ); -static void DeletePES ( void *, pes_packet_t *); - - +static int VCDInit ( struct input_thread_s * ); +static void VCDEnd ( struct input_thread_s * ); +static int VCDDemux ( struct input_thread_s * ); +static int VCDRewind ( struct input_thread_s * ); + +static int VCDOpen ( struct input_thread_s *); +static void VCDClose ( struct input_thread_s *); +static int VCDRead ( struct input_thread_s *, byte_t *, size_t ); +static void VCDSeek ( struct input_thread_s *, off_t ); +static int VCDSetArea ( struct input_thread_s *, struct input_area_s * ); +static int VCDSetProgram ( struct input_thread_s *, pgrm_descriptor_t * ); /***************************************************************************** * Functions exported as capabilities. They are declared as static so that * we don't pollute the namespace too much. *****************************************************************************/ -void _M( input_getfunctions )( function_list_t * p_function_list ) +void _M( access_getfunctions )( function_list_t * p_function_list ) { -#define input p_function_list->functions.input - p_function_list->pf_probe = VCDProbe ; - input.pf_init = VCDInit ; - input.pf_open = VCDOpen ; - input.pf_close = VCDClose ; - input.pf_end = VCDEnd ; - input.pf_init_bit_stream = InitBitstream; - input.pf_read = VCDRead ; - input.pf_set_area = VCDSetArea ; - input.pf_demux = input_DemuxPS; - input.pf_new_packet = NewPacket; - input.pf_new_pes = NewPES; - input.pf_delete_packet = DeletePacket; - input.pf_delete_pes = DeletePES; - input.pf_rewind = VCDRewind ; - input.pf_seek = VCDSeek ; -#undef input +#define access p_function_list->functions.access + access.pf_open = VCDOpen; + access.pf_close = VCDClose; + access.pf_read = VCDRead; + access.pf_set_area = VCDSetArea; + access.pf_set_program = VCDSetProgram; + access.pf_seek = VCDSeek; +#undef access } -/* - * Data reading functions - */ -/***************************************************************************** - * VCDProbe: verifies that the stream is a PS stream - *****************************************************************************/ -static int VCDProbe( probedata_t *p_data ) +void _M( demux_getfunctions )( function_list_t * p_function_list ) { - - input_thread_t * p_input = (input_thread_t *)p_data; - - char * psz_name = p_input->p_source; - int i_score = 5; - - if( TestMethod( INPUT_METHOD_VAR, "vcd" ) ) - { - return( 999 ); - } - - if( ( strlen(psz_name) > 4 ) && !strncasecmp( psz_name, "vcd:", 4 ) ) - { - /* If the user specified "vcd:" then it's probably a VCD */ - i_score = 100; - psz_name += 4; - } - return( i_score ); +#define demux p_function_list->functions.demux + demux.pf_init = VCDInit; + demux.pf_end = VCDEnd; + demux.pf_demux = VCDDemux; + demux.pf_rewind = VCDRewind; +#undef demux } +/* + * Data reading functions + */ + /***************************************************************************** * VCDOpen: open vcd *****************************************************************************/ -static void VCDOpen( struct input_thread_s *p_input ) +static int VCDOpen( struct input_thread_s *p_input ) { - int vcdhandle; - - vlc_mutex_lock( &p_input->stream.stream_lock ); - - /* If we are here we can control the pace... */ - 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; + 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; - vlc_mutex_unlock( &p_input->stream.stream_lock ); + + /* parse the options passed in command line : */ + psz_orig = psz_parser = psz_source = strdup( p_input->psz_name ); - /* XXX: put this shit in an access plugin */ - if( strlen( p_input->p_source ) > 4 - && !strncasecmp( p_input->p_source, "vcd:", 4 ) ) + if( !psz_orig ) { - vcdhandle = open( p_input->p_source + 4, O_RDONLY | O_NONBLOCK ); + return( -1 ); } - else + + while( *psz_parser && *psz_parser != '@' ) { - vcdhandle = open( p_input->p_source + 4, O_RDONLY | O_NONBLOCK ); + psz_parser++; } - if( vcdhandle == -1 ) + if( *psz_parser == '@' ) { - p_input->b_error = 1; - return; - } + /* Found options */ + *psz_parser = '\0'; + ++psz_parser; - p_input->i_handle = (int) vcdhandle; -} + 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 ); + } -/***************************************************************************** - * VCDClose: close vcd - *****************************************************************************/ -static void VCDClose( struct input_thread_s *p_input ) -{ - close( p_input->i_handle ); -} + i_title = i_title ? i_title : 1; + i_chapter = i_chapter ? i_chapter : 1; + } -/***************************************************************************** - * VCDInit: initializes VCD structures - *****************************************************************************/ -static void VCDInit( input_thread_t * p_input ) -{ - thread_vcd_data_t * p_vcd; - int i_title; - int i_chapter; - int i; - input_area_t * p_area; - es_descriptor_t * p_es; - packet_cache_t * p_packet_cache; - - p_vcd = malloc( sizeof(thread_vcd_data_t) ); - - if( p_vcd == NULL ) + if( !*psz_source ) { - intf_ErrMsg( "vcd error: out of memory" ); - p_input->b_error = 1; - return; + if( !p_input->psz_access ) + { + free( psz_orig ); + return -1; + } + psz_source = config_GetPszVariable( "vcd_device" ); } + /* test the type of file given */ - - p_input->p_plugin_data = (void *)p_vcd; - p_input->p_method_data = NULL; - - p_vcd->vcdhandle = p_input->i_handle; - p_vcd->b_end_of_track = 0; - - /* we read the Table Of Content information */ - if ( read_toc(p_vcd) == -1 ) + if( stat( psz_source, &stat_info ) == -1 ) { - intf_ErrMsg("An error occured when reading vcd's TOC"); + intf_ErrMsg( "input: vcd: cannot stat() source `%s' (%s)", + psz_source, strerror(errno)); + return( -1 ); } - p_input->i_read_once = VCD_DATA_ONCE; + if( !S_ISBLK(stat_info.st_mode) ) + { + intf_WarnMsg( 3, "input : VCD plugin discarded" + " (not a valid drive)" ); + return -1; + } - p_packet_cache = malloc( sizeof(packet_cache_t) ); - if ( p_packet_cache == NULL ) + p_vcd = malloc( sizeof(thread_vcd_data_t) ); + + if( p_vcd == NULL ) { intf_ErrMsg( "vcd error: out of memory" ); - p_input->b_error = 1; - return; + return -1; } - p_input->p_method_data = (void *)p_packet_cache; - /* Initialize packet cache mutex */ - vlc_mutex_init( &p_packet_cache->lock ); + p_input->p_access_data = (void *)p_vcd; - /* allocates the data cache */ - p_packet_cache->data.p_stack = malloc( DATA_CACHE_SIZE * - sizeof(data_packet_t*) ); - if ( p_packet_cache->data.p_stack == NULL ) + 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 ); + + p_vcd->i_handle = open( psz_source, O_RDONLY | O_NONBLOCK ); + + if( p_vcd->i_handle == -1 ) { - intf_ErrMsg( "Out of memory" ); - p_input->b_error = 1; - return; + intf_ErrMsg( "input: vcd: Could not open %s\n", psz_source ); + free (p_vcd); + return -1; } - p_packet_cache->data.l_index = 0; - - /* allocates the PES cache */ - p_packet_cache->pes.p_stack = malloc( PES_CACHE_SIZE * - sizeof(pes_packet_t*) ); - if ( p_packet_cache->pes.p_stack == NULL ) + + /* We read the Table Of Content information */ + p_vcd->nb_tracks = ioctl_GetTrackCount( p_vcd->i_handle, + psz_source ); + if( p_vcd->nb_tracks < 0 ) { - intf_ErrMsg( "Out of memory" ); - p_input->b_error = 1; - return; + intf_ErrMsg( "input: vcd: was unable to count tracks" ); + close( p_vcd->i_handle ); + free( p_vcd ); + return -1; } - p_packet_cache->pes.l_index = 0; - - /* allocates the small buffer cache */ - p_packet_cache->smallbuffer.p_stack = malloc( SMALL_CACHE_SIZE * - sizeof(packet_buffer_t) ); - if ( p_packet_cache->smallbuffer.p_stack == NULL ) + else if( p_vcd->nb_tracks <= 1 ) { - intf_ErrMsg( "Out of memory" ); - p_input->b_error = 1; - return; + intf_ErrMsg( "input: vcd: no movie tracks found" ); + close( p_vcd->i_handle ); + free( p_vcd ); + return -1; } - p_packet_cache->smallbuffer.l_index = 0; - - /* allocates the large buffer cache */ - p_packet_cache->largebuffer.p_stack = malloc( LARGE_CACHE_SIZE * - sizeof(packet_buffer_t) ); - if ( p_packet_cache->largebuffer.p_stack == NULL ) + + p_vcd->p_sectors = ioctl_GetSectors( p_vcd->i_handle, + psz_source ); + if( p_vcd->p_sectors == NULL ) { - intf_ErrMsg( "Out of memory" ); - p_input->b_error = 1; - return; + input_BuffersEnd( p_input->p_method_data ); + close( p_vcd->i_handle ); + free( p_vcd ); + return -1; } - p_packet_cache->largebuffer.l_index = 0; /* Set stream and area data */ vlc_mutex_lock( &p_input->stream.stream_lock ); @@ -311,7 +252,6 @@ static void VCDInit( input_thread_t * p_input ) /* disc input method */ p_input->stream.i_method = INPUT_METHOD_VCD; - #define area p_input->stream.pp_areas for( i = 1 ; i <= p_vcd->nb_tracks - 1 ; i++ ) { @@ -321,336 +261,162 @@ static void VCDInit( input_thread_t * p_input ) area[i]->i_id = i; /* Absolute start offset and size */ - area[i]->i_start = p_vcd->tracks_sector[i+1]; - area[i]->i_size = p_vcd->tracks_sector[i+2] - p_vcd->tracks_sector[i+1]; + 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; - /* Number of angles */ - area[i]->i_angle_nb = 1; // no angle support in VCDs - area[i]->i_angle = 1; - - area[i]->i_plugin_data = p_vcd->tracks_sector[i+1]; - } -#undef area - - /* Get requested title - if none try the first title */ - i_title = main_GetIntVariable( INPUT_TITLE_VAR, 1 ); - if( i_title <= 0) - { - i_title = 2; + area[i]->i_plugin_data = p_vcd->p_sectors[i]; } - - // p_vcd->current_track = i_title-1 ; - - /* Get requested chapter - if none defaults to first one */ - i_chapter = main_GetIntVariable( INPUT_CHAPTER_VAR, 1 ); - if( i_chapter <= 0 ) - { - i_chapter = 1; - } - - - p_input->stream.pp_areas[i_title]->i_part = i_chapter; +#undef area p_area = p_input->stream.pp_areas[i_title]; VCDSetArea( p_input, p_area ); - /* Set program information. */ - - input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) ); - - /* No PSM to read in disc mode, we already have all information */ - p_input->stream.pp_programs[0]->b_is_ok = 1; - - p_es = input_AddES( p_input, p_input->stream.pp_programs[0], 0xe0, 0 ); - p_es->i_stream_id = 0xe0; - p_es->i_type = MPEG1_VIDEO_ES; - p_es->i_cat = VIDEO_ES; - - if( p_main->b_video ) - { - input_SelectES( p_input, p_es ); - } - - p_es = input_AddES( p_input, - p_input->stream.pp_programs[0], 0xc0, 0 ); - p_es->i_stream_id = 0xc0; - p_es->i_type = MPEG1_AUDIO_ES; - p_es->b_audio = 1; - p_es->i_cat = AUDIO_ES; - - if( p_main->b_audio ) - { - input_SelectES( p_input, p_es ); - } - vlc_mutex_unlock( &p_input->stream.stream_lock ); - - return; -} + p_input->psz_demux = "vcd"; + return 0; +} /***************************************************************************** - * VCDEnd: frees unused data + * VCDClose: closes vcd *****************************************************************************/ -static void VCDEnd( input_thread_t * p_input ) +static void VCDClose( struct input_thread_s *p_input ) { - thread_vcd_data_t * p_vcd; - - p_vcd = (thread_vcd_data_t*)p_input->p_plugin_data; + thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data; + close( p_vcd->i_handle ); free( p_vcd ); - } -/***************************************************************************** - * 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 ) -{ - thread_vcd_data_t * p_vcd; - - p_vcd = (thread_vcd_data_t*)p_input->p_plugin_data; - - /* 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 ) - { - /* Reset the Chapter position of the old title */ - p_input->stream.p_selected_area->i_part = 0; - - /* Change the default area */ - p_input->stream.p_selected_area = - p_input->stream.pp_areas[p_area->i_id]; - - /* Change the current track */ - /* The first track is not a valid one */ - p_vcd->current_track = p_area->i_id + 1 ; - p_vcd->current_sector = p_vcd->tracks_sector[p_vcd->current_track] ; - } - /* warn interface that something has changed */ - p_input->stream.b_seekable = 1; - p_input->stream.b_changed = 1; - return 0 ; - -} - - - /***************************************************************************** * VCDRead: reads from the VCD into PES packets. ***************************************************************************** - * Returns -1 in case of error, 0 if everything went well, and 1 in case of - * EOF. + * Returns -1 in case of error, 0 in case of EOF, otherwise the number of + * bytes. *****************************************************************************/ -static int VCDRead( input_thread_t * p_input, - data_packet_t ** pp_packets ) +static int VCDRead( input_thread_t * p_input, byte_t * p_buffer, + size_t i_len ) { thread_vcd_data_t * p_vcd; - data_packet_t * p_data; - int i_packet_size; + int i_blocks; int i_index; - int i_packet; - boolean_t b_eof; - byte_t * p_buffer; - boolean_t b_no_packet; - /* boolean_t b_eoc; No chapters yet */ - - p_vcd = (thread_vcd_data_t *)p_input->p_plugin_data; - + int i_read; + byte_t p_last_sector[ VCD_DATA_SIZE ]; - p_buffer = malloc ( VCD_DATA_SIZE ); + p_vcd = (thread_vcd_data_t *)p_input->p_access_data; - if ( p_buffer == NULL ) - { - intf_ErrMsg("Could not malloc the read buffer"); - return -1; - } + i_read = 0; - - i_packet = 0; - b_no_packet = 0; + /* Compute the number of blocks we have to read */ + + i_blocks = i_len / VCD_DATA_SIZE; - while( i_packet < VCD_DATA_ONCE ) + for ( i_index = 0 ; i_index < i_blocks ; i_index++ ) { - i_index = 0; - - if ( VCD_sector_read( p_vcd, p_buffer ) == -1 ) + if ( ioctl_ReadSector( p_vcd->i_handle, p_vcd->i_sector, + p_buffer + i_index * VCD_DATA_SIZE ) < 0 ) { - return -1; + intf_ErrMsg( "input: vcd: could not read sector %d\n", + p_vcd->i_sector ); + return -1; } - - while (i_index < BUFFER_SIZE - 6) + + p_vcd->i_sector ++; + if ( p_vcd->i_sector == p_vcd->p_sectors[p_vcd->i_track + 1] ) { + input_area_t *p_area; - if( (U32_AT(p_buffer + i_index) & 0xFFFFFF00) != 0x100L ) - { - /* This is not the startcode of a packet. Read the stream - * until we find one. */ - - if( !U32_AT( p_buffer + i_index ) ) - { - /* 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( 3, "Garbage at input" ); - } - - while( ( (U32_AT(p_buffer + i_index) & 0xFFFFFF00) != 0x100L ) - && ( i_index < BUFFER_SIZE - 4 ) ) - { - i_index ++; - } - - if ( i_index == BUFFER_SIZE - 4 ) - { - b_no_packet = 1; - } - /* Packet found. */ - } - - if (b_no_packet) - { - b_no_packet = 0; - intf_WarnMsg(3, "No packet found on sector %d\n", - p_vcd->current_sector -1 ); - break; /* go to the next sector */ - } - -#ifdef DEBUG - intf_DbgMsg("packet start code : %X\n", - U32_AT(p_buffer + i_index)); -#endif - /* 0x1B9 == SYSTEM_END_CODE, it is only 4 bytes long. */ - if( U32_AT(p_buffer + i_index) != 0x1B9 ) - { - /* The packet is at least 6 bytes long. */ - - if( U32_AT(p_buffer + i_index) != 0x1BA ) - { - /* That's the case for all packets, except pack header. */ - i_packet_size = U16_AT((p_buffer + ( i_index + 4 ))); - } - else - { - /* Pack header. */ - if( ( *( p_buffer + ( i_index + 4 ) ) & 0xC0) == 0x40 ) - { - /* MPEG-2 */ - i_packet_size = 8; - } - else if( (*(p_buffer + ( i_index + 4 ) ) & 0xF0) == 0x20 ) - { - /* MPEG-1 */ - i_packet_size = 6; - } - else - { - intf_ErrMsg( "Unable to determine stream type" ); - return( -1 ); - } - } - } - else - { - /* System End Code */ - i_packet_size = -2; - } -#ifdef DEBUG - intf_DbgMsg("i_index : %d\n", i_index); - intf_DbgMsg("i_packet_size : %d\n", i_packet_size); -#endif - if ( i_index + i_packet_size > BUFFER_SIZE ) - { - intf_ErrMsg( "Too long packet"); - continue; - } + if ( p_vcd->i_track >= p_vcd->nb_tracks - 1 ) + return 0; /* EOF */ - /* Fetch a packet of the appropriate size. */ + p_area = p_input->stream.pp_areas[ + p_input->stream.p_selected_area->i_id + 1 ]; - p_data = NewPacket( p_input->p_method_data, i_packet_size + 6 ); + intf_WarnMsg( 4, "input: vcd info: new title" ); - if( p_data == NULL ) - { - intf_ErrMsg( "Out of memory" ); - return( -1 ); - } - - if( U32_AT(p_buffer) != 0x1B9 ) - { - memcpy( p_data->p_buffer, p_buffer + i_index, - 6 + i_packet_size ); - i_index += ( 6 + i_packet_size ); + p_area->i_part = 1; + VCDSetArea( p_input, p_area ); - } - else - { - /* Copy the small header. */ - memcpy( p_data->p_buffer, p_buffer + i_index, 4 ); - i_index += 4; - } + } + i_read += VCD_DATA_SIZE; + } - /* Give the packet to the other input stages. */ - pp_packets[i_packet] = p_data; - i_packet ++; + if ( i_len % VCD_DATA_SIZE ) /* this should not happen */ + { + if ( ioctl_ReadSector( p_vcd->i_handle, p_vcd->i_sector, + p_last_sector ) < 0 ) + { + intf_ErrMsg( "input: vcd: could not read sector %d\n", + p_vcd->i_sector ); + return -1; } - if ( p_vcd->b_end_of_track ) - break; + FAST_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; +} +/***************************************************************************** + * VCDSetProgram: Does nothing since a VCD is mono_program + *****************************************************************************/ +static int VCDSetProgram( input_thread_t * p_input, + pgrm_descriptor_t * p_program) +{ + return 0; +} - - vlc_mutex_lock( &p_input->stream.stream_lock ); +/***************************************************************************** + * 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 ) +{ + thread_vcd_data_t * p_vcd; - p_input->stream.p_selected_area->i_tell = - p_vcd->current_sector - - p_input->stream.p_selected_area->i_start ; - - /* no chapter for the moment*/ - /*if( b_eoc ) - { - * We modify i_part only at end of chapter not to erase - * some modification from the interface * - p_input->stream.p_selected_area->i_part = p_vcd->i_chapter; - }*/ + p_vcd = (thread_vcd_data_t*)p_input->p_access_data; - - b_eof = p_vcd->b_end_of_track && - ( ( p_vcd->current_track + 1 ) >= p_vcd->nb_tracks ); + /* we can't use the interface slider until initilization is complete */ + p_input->stream.b_seekable = 0; - if( b_eof ) + if( p_area != p_input->stream.p_selected_area ) { - vlc_mutex_unlock( &p_input->stream.stream_lock ); - return 1; - } + /* 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_vcd->b_end_of_track ) - { - intf_WarnMsg( 4, "vcd info: new title" ); - p_vcd->current_track++; - p_vcd->b_end_of_track = 0; - VCDSetArea( p_input, p_input->stream.pp_areas[p_vcd->current_track] ); - vlc_mutex_unlock( &p_input->stream.stream_lock ); - return 0; + /* Change the default area */ + p_input->stream.p_selected_area = p_area; + + /* 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]; } - - vlc_mutex_unlock( &p_input->stream.stream_lock ); + /* warn interface that something has changed */ + p_input->stream.b_seekable = 1; + p_input->stream.b_changed = 1; return 0; } + /***************************************************************************** * VCDRewind : reads a stream backward *****************************************************************************/ @@ -659,7 +425,6 @@ static int VCDRewind( input_thread_t * p_input ) return( -1 ); } - /**************************************************************************** * VCDSeek ****************************************************************************/ @@ -667,370 +432,102 @@ static void VCDSeek( input_thread_t * p_input, off_t i_off ) { thread_vcd_data_t * p_vcd; - p_vcd = (thread_vcd_data_t *) p_input->p_plugin_data; + p_vcd = (thread_vcd_data_t *) p_input->p_access_data; - p_vcd->current_sector = p_vcd->tracks_sector[p_vcd->current_track] - + i_off; + p_vcd->i_sector = p_vcd->p_sectors[p_vcd->i_track] + + i_off / (off_t)VCD_DATA_SIZE; - p_input->stream.p_selected_area->i_tell = p_vcd->current_sector - - p_input->stream.p_selected_area->i_start; - - return ; + 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; } - - /* - * Packet management utilities + * Demux functions */ /***************************************************************************** - * NewPacket: allocates a data packet + * VCDInit: initializes VCD structures *****************************************************************************/ -static struct data_packet_s * NewPacket( void * p_packet_cache, - size_t l_size ) -{ - packet_cache_t * p_cache; - data_packet_t * p_data; - long l_index; - - p_cache = (packet_cache_t *)p_packet_cache; - -#ifdef DEBUG - if ( p_cache == NULL ) - { - intf_ErrMsg( "PPacket cache not initialized" ); - return NULL; - } -#endif - - /* Safety check */ - if( l_size > INPUT_MAX_PACKET_SIZE ) - { - intf_ErrMsg( "Packet too big (%d)", l_size ); - return NULL; - } - - vlc_mutex_lock( &p_cache->lock ); - - /* Checks whether the data cache is empty */ - if( p_cache->data.l_index == 0 ) - { - /* Allocates a new packet */ - p_data = malloc( sizeof(data_packet_t) ); - if( p_data == NULL ) - { - intf_ErrMsg( "Out of memory" ); - vlc_mutex_unlock( &p_cache->lock ); - return NULL; - } -#ifdef TRACE_INPUT - intf_DbgMsg( "PS input: data packet allocated" ); -#endif - } - else - { - /* Takes the packet out from the cache */ - if( (p_data = p_cache->data.p_stack[ -- p_cache->data.l_index ]) - == NULL ) - { - intf_ErrMsg( "NULL packet in the data cache" ); - vlc_mutex_unlock( &p_cache->lock ); - return NULL; - } - } +static int VCDInit( input_thread_t * p_input ) +{ + es_descriptor_t * p_es; - if( l_size < MAX_SMALL_SIZE ) - { - /* Small buffer */ - - /* Checks whether the buffer cache is empty */ - if( p_cache->smallbuffer.l_index == 0 ) - { - /* Allocates a new packet */ - p_data->p_buffer = malloc( l_size ); - if( p_data->p_buffer == NULL ) - { - intf_DbgMsg( "Out of memory" ); - free( p_data ); - vlc_mutex_unlock( &p_cache->lock ); - return NULL; - } -#ifdef TRACE_INPUT - intf_DbgMsg( "PS input: small buffer allocated" ); -#endif - p_data->l_size = l_size; - } - else - { - /* Takes the packet out from the cache */ - l_index = -- p_cache->smallbuffer.l_index; - if( (p_data->p_buffer = p_cache->smallbuffer.p_stack[l_index].p_data) - == NULL ) - { - intf_ErrMsg( "NULL packet in the small buffer cache" ); - free( p_data ); - vlc_mutex_unlock( &p_cache->lock ); - return NULL; - } - /* Reallocates the packet if it is too small or too large */ - if( p_cache->smallbuffer.p_stack[l_index].l_size < l_size || - p_cache->smallbuffer.p_stack[l_index].l_size > 2*l_size ) - { - p_data->p_buffer = realloc( p_data->p_buffer, l_size ); - p_data->l_size = l_size; - } - else - { - p_data->l_size = p_cache->smallbuffer.p_stack[l_index].l_size; - } - } - } - else + if( p_input->stream.i_method != INPUT_METHOD_VCD ) { - /* Large buffer */ - - /* Checks whether the buffer cache is empty */ - if( p_cache->largebuffer.l_index == 0 ) - { - /* Allocates a new packet */ - p_data->p_buffer = malloc( l_size ); - if ( p_data->p_buffer == NULL ) - { - intf_ErrMsg( "Out of memory" ); - free( p_data ); - vlc_mutex_unlock( &p_cache->lock ); - return NULL; - } -#ifdef TRACE_INPUT - intf_DbgMsg( "PS input: large buffer allocated" ); -#endif - p_data->l_size = l_size; - } - else - { - /* Takes the packet out from the cache */ - l_index = -- p_cache->largebuffer.l_index; - p_data->p_buffer = p_cache->largebuffer.p_stack[l_index].p_data; - if( p_data->p_buffer == NULL ) - { - intf_ErrMsg( "NULL packet in the small buffer cache" ); - free( p_data ); - vlc_mutex_unlock( &p_cache->lock ); - return NULL; - } - /* Reallocates the packet if it is too small or too large */ - if( p_cache->largebuffer.p_stack[l_index].l_size < l_size || - p_cache->largebuffer.p_stack[l_index].l_size > 2*l_size ) - { - p_data->p_buffer = realloc( p_data->p_buffer, l_size ); - p_data->l_size = l_size; - } - else - { - p_data->l_size = p_cache->largebuffer.p_stack[l_index].l_size; - } - } + return -1; } - vlc_mutex_unlock( &p_cache->lock ); - - /* 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 + l_size; - - return( p_data ); - -} - + vlc_mutex_lock( &p_input->stream.stream_lock ); + + /* Set program information. */ + input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) ); + p_input->stream.p_selected_program = p_input->stream.pp_programs[0]; -/***************************************************************************** - * NewPES: allocates a pes packet - *****************************************************************************/ -static pes_packet_t * NewPES( void * p_packet_cache ) -{ - packet_cache_t * p_cache; - pes_packet_t * p_pes; + /* No PSM to read in disc mode, we already have all the information */ + p_input->stream.p_selected_program->b_is_ok = 1; - p_cache = (packet_cache_t *)p_packet_cache; + p_es = input_AddES( p_input, p_input->stream.p_selected_program, 0xe0, 0 ); + p_es->i_stream_id = 0xe0; + p_es->i_type = MPEG1_VIDEO_ES; + p_es->i_cat = VIDEO_ES; -#ifdef DEBUG - if ( p_cache == NULL ) + if( p_main->b_video ) { - intf_ErrMsg( "Packet cache not initialized" ); - return NULL; + input_SelectES( p_input, p_es ); } -#endif - vlc_mutex_lock( &p_cache->lock ); + p_es = input_AddES( p_input, p_input->stream.p_selected_program, 0xc0, 0 ); + p_es->i_stream_id = 0xc0; + p_es->i_type = MPEG1_AUDIO_ES; + p_es->b_audio = 1; + p_es->i_cat = AUDIO_ES; - /* Checks whether the PES cache is empty */ - if( p_cache->pes.l_index == 0 ) - { - /* Allocates a new packet */ - p_pes = malloc( sizeof(pes_packet_t) ); - if( p_pes == NULL ) - { - intf_DbgMsg( "Out of memory" ); - vlc_mutex_unlock( &p_cache->lock ); - return NULL; - } -#ifdef TRACE_INPUT - intf_DbgMsg( "PS input: PES packet allocated" ); -#endif - } - else + if( p_main->b_audio ) { - /* Takes the packet out from the cache */ - p_pes = p_cache->pes.p_stack[ -- p_cache->pes.l_index ]; - if( p_pes == NULL ) - { - intf_ErrMsg( "NULL packet in the data cache" ); - vlc_mutex_unlock( &p_cache->lock ); - return NULL; - } + input_SelectES( p_input, p_es ); } - vlc_mutex_unlock( &p_cache->lock ); - - 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 ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); + return 0; } /***************************************************************************** - * DeletePacket: deletes a data packet + * VCDEnd: frees unused data *****************************************************************************/ -static void DeletePacket( void * p_packet_cache, - data_packet_t * p_data ) +static void VCDEnd( input_thread_t * p_input ) { - packet_cache_t * p_cache; - - p_cache = (packet_cache_t *)p_packet_cache; - -#ifdef DEBUG - if ( p_cache == NULL ) - { - intf_ErrMsg( "Packet cache not initialized" ); - return; - } -#endif - - ASSERT( p_data ); - - vlc_mutex_lock( &p_cache->lock ); - - /* Checks whether the data cache is full */ - if ( p_cache->data.l_index < DATA_CACHE_SIZE ) - { - /* Cache not full: store the packet in it */ - p_cache->data.p_stack[ p_cache->data.l_index ++ ] = p_data; - /* Small buffer or large buffer? */ - if ( p_data->l_size < MAX_SMALL_SIZE ) - { - /* Checks whether the small buffer cache is full */ - if ( p_cache->smallbuffer.l_index < SMALL_CACHE_SIZE ) - { - p_cache->smallbuffer.p_stack[ - p_cache->smallbuffer.l_index ].l_size = p_data->l_size; - p_cache->smallbuffer.p_stack[ - p_cache->smallbuffer.l_index++ ].p_data = p_data->p_buffer; - } - else - { - ASSERT( p_data->p_buffer ); - free( p_data->p_buffer ); -#ifdef TRACE_INPUT - intf_DbgMsg( "PS input: small buffer freed" ); -#endif - } - } - else - { - /* Checks whether the large buffer cache is full */ - if ( p_cache->largebuffer.l_index < LARGE_CACHE_SIZE ) - { - p_cache->largebuffer.p_stack[ - p_cache->largebuffer.l_index ].l_size = p_data->l_size; - p_cache->largebuffer.p_stack[ - p_cache->largebuffer.l_index++ ].p_data = p_data->p_buffer; - } - else - { - ASSERT( p_data->p_buffer ); - free( p_data->p_buffer ); -#ifdef TRACE_INPUT - intf_DbgMsg( "PS input: large buffer freed" ); -#endif - } - } - } - else - { - /* Cache full: the packet must be freed */ - free( p_data->p_buffer ); - free( p_data ); -#ifdef TRACE_INPUT - intf_DbgMsg( "PS input: data packet freed" ); -#endif - } - - vlc_mutex_unlock( &p_cache->lock ); + ; } + /***************************************************************************** - * DeletePES: deletes a PES packet and associated data packets + * VCDDemux: reads and demuxes data packets + ***************************************************************************** + * Returns -1 in case of error, 0 in case of EOF, otherwise the number of + * packets. *****************************************************************************/ -static void DeletePES( void * p_packet_cache, pes_packet_t * p_pes ) +static int VCDDemux( input_thread_t * p_input ) { - packet_cache_t * p_cache; - data_packet_t * p_data; - data_packet_t * p_next; - - p_cache = (packet_cache_t *)p_packet_cache; + int i; -#ifdef DEBUG - if ( p_cache == NULL ) + for( i = 0; i < VCD_BLOCKS_ONCE; i++ ) { - intf_ErrMsg( "Packet cache not initialized" ); - return; - } -#endif - - ASSERT( p_pes); + data_packet_t * p_data; + ssize_t i_result; - p_data = p_pes->p_first; + i_result = input_ReadPS( p_input, &p_data ); - while( p_data != NULL ) - { - p_next = p_data->p_next; - DeletePacket( p_cache, p_data ); - p_data = p_next; - } - - vlc_mutex_lock( &p_cache->lock ); + if( i_result <= 0 ) + { + return( i_result ); + } - /* Checks whether the PES cache is full */ - if ( p_cache->pes.l_index < PES_CACHE_SIZE ) - { - /* Cache not full: store the packet in it */ - p_cache->pes.p_stack[ p_cache->pes.l_index ++ ] = p_pes; - } - else - { - /* Cache full: the packet must be freed */ - free( p_pes ); -#ifdef TRACE_INPUT - intf_DbgMsg( "PS input: PES packet freed" ); -#endif + input_DemuxPS( p_input, p_data ); } - vlc_mutex_unlock( &p_cache->lock ); + return( i ); } +