X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Fvcdx%2Faccess.c;h=ae44dd07865eecd131664acd1018c5e8594fd091;hb=5ca0ebcca2e3f55a1087811048684a3b9b1eecbf;hp=bc99a73226618a89c92dc247269954699c87760c;hpb=fd05dc698e736455dfa075fdb93f3600365f4e9d;p=vlc diff --git a/modules/access/vcdx/access.c b/modules/access/vcdx/access.c index bc99a73226..ae44dd0786 100644 --- a/modules/access/vcdx/access.c +++ b/modules/access/vcdx/access.c @@ -3,11 +3,11 @@ * using libcdio, libvcd and libvcdinfo. vlc-specific things tend * to go here. ***************************************************************************** - * Copyright (C) 2000 VideoLAN - * $Id: access.c,v 1.1 2003/10/04 18:55:13 gbazin Exp $ + * Copyright (C) 2000, 2003 VideoLAN + * $Id: access.c,v 1.13 2003/12/22 14:32:55 sam Exp $ * - * Authors: Johan Bilien - * Rocky Bernstein + * Authors: Rocky Bernstein + * Johan Bilien * * 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 @@ -28,16 +28,17 @@ * Preamble *****************************************************************************/ -#if 0 // Disabled until this is working #include #include +#include #include "../../demux/mpeg/system.h" #include "vcd.h" -#include "intf.h" #include "vcdplayer.h" +#include "intf.h" #include +#include #include #include #include @@ -49,77 +50,44 @@ #define VCD_BLOCKS_ONCE 20 #define VCD_DATA_ONCE (VCD_BLOCKS_ONCE * M2F2_SECTOR_SIZE) +#define VCD_MRL_PREFIX "vcdx://" + /***************************************************************************** * Local prototypes *****************************************************************************/ /* First those which are accessed from outside (via pointers). */ -static int VCDOpen ( vlc_object_t * ); -static void VCDClose ( vlc_object_t * ); -static int VCDRead ( input_thread_t *, byte_t *, size_t ); static int VCDRead ( input_thread_t *, byte_t *, size_t ); static int VCDSetProgram ( input_thread_t *, pgrm_descriptor_t * ); /* Now those which are strictly internal */ -static void VCDSetOrigin ( input_thread_t *, lsn_t origin_lsn, - lsn_t cur_lsn, lsn_t end_lsn, +static void VCDSetOrigin ( input_thread_t *, lsn_t origin_lsn, + lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t track ); static int VCDEntryPoints ( input_thread_t * ); static int VCDLIDs ( input_thread_t * ); static int VCDSegments ( input_thread_t * ); static void VCDTracks ( input_thread_t * ); -static int VCDReadSector ( vlc_object_t *p_this, - const vcdinfo_obj_t *p_vcd, lsn_t cur_lsn, +static int VCDReadSector ( vlc_object_t *p_this, + const vcdinfo_obj_t *p_vcd, lsn_t cur_lsn, byte_t * p_buffer ); -static char *VCDParse ( input_thread_t *, - /*out*/ vcdinfo_itemid_t * p_itemid ); +static char *VCDParse ( input_thread_t *, + /*out*/ vcdinfo_itemid_t * p_itemid , + /*out*/ bool *play_single_item ); static void VCDUpdateVar( input_thread_t *p_input, int i_entry, int i_action, const char *varname, const char *label ); static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev ); -static int debug_callback ( vlc_object_t *p_this, const char *psz_name, - vlc_value_t oldval, vlc_value_t val, - void *p_data ); - -#define DEBUG_TEXT N_("set debug mask for additional debugging.") -#define DEBUG_LONGTEXT N_( \ - "This integer when viewed in binary is a debugging mask\n" \ - "MRL 1\n" \ - "external call 2\n" \ - "all calls 4\n" \ - "LSN 8\n" \ - "PBC (10) 16\n" \ - "libcdio (20) 32\n" \ - "seeks (40) 64\n" \ - "still (80) 128\n" \ - "vcdinfo (100) 256\n" ) - /**************************************************************************** * Private functions ****************************************************************************/ -/* FIXME: This variable is a hack. Would be nice to eliminate the - global-ness. */ -static input_thread_t *p_vcd_input = NULL; - -int -vcd_debug_callback ( vlc_object_t *p_this, const char *psz_name, - vlc_value_t oldval, vlc_value_t val, void *p_data ) -{ - thread_vcd_data_t *p_vcd; - if (NULL == p_vcd_input) return VLC_EGENERIC; - - p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data; +/* FIXME: This variable is a hack. Would be nice to eliminate the + global-ness. */ - if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) { - msg_Dbg( p_vcd_input, "Old debug (x%0x) %d, new debug (x%0x) %d", - p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int); - } - p_vcd->i_debug = val.i_int; - return VLC_SUCCESS; -} +static input_thread_t *p_vcd_input = NULL; /* process messages that originate from libcdio. */ static void @@ -129,7 +97,7 @@ cdio_log_handler (cdio_log_level_t level, const char message[]) switch (level) { case CDIO_LOG_DEBUG: case CDIO_LOG_INFO: - if (p_vcd->i_debug & INPUT_DBG_CDIO) + if (p_vcd->i_debug & INPUT_DBG_CDIO) msg_Dbg( p_vcd_input, message); break; case CDIO_LOG_WARN: @@ -141,7 +109,7 @@ cdio_log_handler (cdio_log_level_t level, const char message[]) break; default: msg_Warn( p_vcd_input, message, - _("The above message had unknown vcdimager log level"), + _("The above message had unknown log level"), level); } return; @@ -167,176 +135,19 @@ vcd_log_handler (vcd_log_level_t level, const char message[]) break; default: msg_Warn( p_vcd_input, "%s\n%s %d", message, - _("The above message had unknown vcdimager log level"), + _("The above message had unknown vcdimager log level"), level); } return; } -/* - * Data reading functions - */ - -/***************************************************************************** - VCDOpen: open VCD. - read in meta-information about VCD: the number of tracks, segments, - entries, size and starting information. Then set up state variables so - that we read/seek starting at the location specified. - - On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM, - and VLC_EGENERIC for some other error. - *****************************************************************************/ -static int -VCDOpen( vlc_object_t *p_this ) -{ - input_thread_t * p_input = (input_thread_t *)p_this; - thread_vcd_data_t * p_vcd; - char * psz_source; - vcdinfo_itemid_t itemid; - bool play_ok; - - p_input->pf_read = VCDRead; - p_input->pf_seek = VCDSeek; - p_input->pf_set_area = VCDSetArea; - p_input->pf_set_program = VCDSetProgram; - - p_vcd = malloc( sizeof(thread_vcd_data_t) ); - - if( p_vcd == NULL ) - { - LOG_ERR ("out of memory" ); - return VLC_ENOMEM; - } - - p_input->p_access_data = (void *)p_vcd; - p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" ); - psz_source = VCDParse( p_input, &itemid ); - - if ( NULL == psz_source ) - { - free( p_vcd ); - return( VLC_EGENERIC ); - } - - dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source ); - - p_vcd->p_segments = NULL; - p_vcd->p_entries = NULL; - - /* set up input */ - p_input->i_mtu = VCD_DATA_ONCE; - - 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; - - vlc_mutex_unlock( &p_input->stream.stream_lock ); - - if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) ) - { - msg_Warn( p_input, "could not open %s", psz_source ); - free( psz_source ); - free( p_vcd ); - return VLC_EGENERIC; - } - - /* Get track information. */ - p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input), - vcdinfo_get_cd_image(p_vcd->vcd), - &p_vcd->p_sectors ); - free( psz_source ); - if( p_vcd->num_tracks < 0 ) - LOG_ERR ("unable to count tracks" ); - else if( p_vcd->num_tracks <= 1 ) - LOG_ERR ("no movie tracks found" ); - if( p_vcd->num_tracks <= 1) - { - vcdinfo_close( p_vcd->vcd ); - free( p_vcd ); - return VLC_EGENERIC; - } - - /* 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; - - - /* Initialize segment information. */ - VCDSegments( p_input ); - - /* Initialize track area information. */ - VCDTracks( p_input ); - - if( VCDEntryPoints( p_input ) < 0 ) - { - msg_Warn( p_input, "could not read entry points, will not use them" ); - p_vcd->b_valid_ep = false; - } - - if( VCDLIDs( p_input ) < 0 ) - { - msg_Warn( p_input, "could not read entry LIDs" ); - } - - play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid )); - - vlc_mutex_unlock( &p_input->stream.stream_lock ); - - if ( ! play_ok ) { - vcdinfo_close( p_vcd->vcd ); - free( p_vcd ); - return VLC_EGENERIC; - } - - if( !p_input->psz_demux || !*p_input->psz_demux ) - { -#if FIXED - p_input->psz_demux = "vcdx"; -#else - p_input->psz_demux = "ps"; -#endif - } - - return VLC_SUCCESS; -} - -/***************************************************************************** - * VCDClose: closes VCD releasing allocated memory. - *****************************************************************************/ -static void -VCDClose( 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; - - dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" ); - vcdinfo_close( p_vcd->vcd ); - - free( p_vcd->p_entries ); - free( p_vcd->p_segments ); - free( p_vcd ); - p_vcd_input = NULL; -} - /***************************************************************************** * VCDRead: reads i_len bytes from the VCD into p_buffer. ***************************************************************************** * Returns -1 in case of error, 0 in case of EOF, otherwise the number of * bytes. *****************************************************************************/ -static int +static int VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len ) { thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data; @@ -347,6 +158,8 @@ VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len ) i_read = 0; + dbg_print( (INPUT_DBG_CALL), "lsn: %u", p_vcd->cur_lsn ); + /* Compute the number of blocks we have to read */ i_blocks = i_len / M2F2_SECTOR_SIZE; @@ -358,11 +171,11 @@ VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len ) vcdplayer_read_status_t read_status; /* We've run off of the end of this entry. Do we continue or stop? */ - dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), + dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "end reached, cur: %u", p_vcd->cur_lsn ); - read_status = vcdplayer_pbc_is_on( p_vcd ) - ? vcdplayer_pbc_nav( p_input ) + read_status = vcdplayer_pbc_is_on( p_vcd ) + ? vcdplayer_pbc_nav( p_input ) : vcdplayer_non_pbc_nav( p_input ); switch (read_status) { @@ -371,14 +184,37 @@ VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len ) case READ_ERROR: /* Some sort of error. */ return i_read; - case READ_STILL_FRAME: + + case READ_STILL_FRAME: { + /* Reached the end of a still frame. */ + byte_t * p_buf = p_buffer; + pgrm_descriptor_t * p_pgrm = p_input->stream.p_selected_program;; + p_buf += (i_index*M2F2_SECTOR_SIZE); memset(p_buf, 0, M2F2_SECTOR_SIZE); p_buf += 2; *p_buf = 0x01; - dbg_print(INPUT_DBG_STILL, "Handled still event\n"); + dbg_print(INPUT_DBG_STILL, "Handled still event"); + +#if 1 + p_vcd->p_intf->p_sys->b_still = 1; + input_SetStatus( p_input, INPUT_STATUS_PAUSE ); +#endif + + vlc_mutex_lock( &p_input->stream.stream_lock ); + + p_pgrm = p_input->stream.p_selected_program; + p_pgrm->i_synchro_state = SYNCHRO_REINIT; + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + input_ClockManageControl( p_input, p_pgrm, 0 ); + + p_vcd->p_intf->p_sys->b_still = 1; + input_SetStatus( p_input, INPUT_STATUS_PAUSE ); + return i_read + M2F2_SECTOR_SIZE; } default: @@ -388,15 +224,15 @@ VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len ) } if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd, - p_vcd->cur_lsn, + p_vcd->cur_lsn, p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 ) { LOG_ERR ("could not read sector %d", p_vcd->cur_lsn ); return -1; } - + p_vcd->cur_lsn ++; - + /* Update chapter */ if( p_vcd->b_valid_ep && /* FIXME kludge so that read does not update chapter @@ -405,17 +241,17 @@ VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len ) !p_input->stream.p_new_area ) { unsigned int i_entry = p_input->stream.p_selected_area->i_part; - + vlc_mutex_lock( &p_input->stream.stream_lock ); - + if( i_entry < p_vcd->num_entries && p_vcd->cur_lsn >= p_vcd->p_entries[i_entry+1] ) { - dbg_print( INPUT_DBG_PBC, + dbg_print( INPUT_DBG_PBC, "new entry, i_entry %d, sector %d, es %d", - i_entry, p_vcd->cur_lsn, + i_entry, p_vcd->cur_lsn, p_vcd->p_entries[i_entry] ); - p_vcd->play_item.num = + p_vcd->play_item.num = ++ p_input->stream.p_selected_area->i_part; p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY; VCDUpdateVar( p_input, p_vcd->play_item.num, VLC_VAR_SETVALUE, @@ -448,7 +284,7 @@ VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len ) /***************************************************************************** * VCDSetProgram: Does nothing since a VCD is mono_program *****************************************************************************/ -static int +static int VCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program) { thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data; @@ -458,13 +294,13 @@ VCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program) /***************************************************************************** - * VCDSetArea: initialize internal data structures and input stream data + * VCDSetArea: initialize internal data structures and input stream data so set subsequent reading and seeking to reflect that we are at track x, entry or segment y. - This is called for each user navigation request, e.g. the GUI - Chapter/Title selections or in initial MRL parsing. + This is called for each user navigation request, e.g. the GUI + Chapter/Title selections or in initial MRL parsing. ****************************************************************************/ -int +int VCDSetArea( input_thread_t * p_input, input_area_t * p_area ) { thread_vcd_data_t *p_vcd = (thread_vcd_data_t*)p_input->p_access_data; @@ -474,8 +310,10 @@ VCDSetArea( input_thread_t * p_input, input_area_t * p_area ) unsigned int i_nb = p_area->i_plugin_data + p_area->i_part_nb; dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), - "track: %d, entry %d, seekable %d", - i_track, i_entry, old_seekable ); + "track: %d, entry %d, seekable %d, area %lx, select area %lx ", + i_track, i_entry, old_seekable, + (long unsigned int) p_area, + (long unsigned int) p_input->stream.p_selected_area ); /* we can't use the interface slider until initilization is complete */ p_input->stream.b_seekable = 0; @@ -485,31 +323,31 @@ VCDSetArea( input_thread_t * p_input, input_area_t * p_area ) unsigned int i; /* If is the result of a track change, make the entry valid. */ - if (i_entry < p_area->i_plugin_data || i_entry >= i_nb) + if (i_entry < p_area->i_plugin_data || i_entry >= i_nb) i_entry = p_area->i_plugin_data; /* Change the default area */ p_input->stream.p_selected_area = p_area; /* Update the navigation variables without triggering a callback */ - VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title", + VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title", "Setting track"); var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL ); for( i = p_area->i_plugin_data; i < i_nb; i++ ) { - VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE, + VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE, "chapter", "Adding entry choice"); } } - if (i_track == 0) - VCDSetOrigin( p_input, p_vcd->p_segments[i_entry], + if (i_track == 0) + VCDSetOrigin( p_input, p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry+1], i_entry, 0 ); else - VCDSetOrigin( p_input, p_vcd->p_sectors[i_track], - vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry), + VCDSetOrigin( p_input, p_vcd->p_sectors[i_track], + vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry), p_vcd->p_sectors[i_track+1], i_entry, i_track ); @@ -524,7 +362,7 @@ VCDSetArea( input_thread_t * p_input, input_area_t * p_area ) /**************************************************************************** * VCDSeek ****************************************************************************/ -void +void VCDSeek( input_thread_t * p_input, off_t i_off ) { thread_vcd_data_t * p_vcd; @@ -539,11 +377,11 @@ VCDSeek( input_thread_t * p_input, off_t i_off ) /* Find entry */ if( p_vcd->b_valid_ep ) { - for( i_entry = 1 ; i_entry < p_vcd->num_entries ; i_entry ++ ) + for( i_entry = 0 ; i_entry < p_vcd->num_entries ; i_entry ++ ) { if( p_vcd->cur_lsn < p_vcd->p_entries[i_entry] ) { - VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE, + VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE, "chapter", "Setting entry" ); break; } @@ -556,8 +394,8 @@ VCDSeek( input_thread_t * p_input, off_t i_off ) p_input->stream.p_selected_area->i_tell = i_off; dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK), - "orig %d, cur: %d, offset: %lld, start: %lld, entry %d", - p_vcd->origin_lsn, p_vcd->cur_lsn, i_off, + "orig %d, cur: %d, offset: %lld, start: %lld, entry %d", + p_vcd->origin_lsn, p_vcd->cur_lsn, i_off, p_input->stream.p_selected_area->i_start, i_entry ); vlc_mutex_unlock( &p_input->stream.stream_lock ); @@ -567,16 +405,22 @@ VCDSeek( input_thread_t * p_input, off_t i_off ) VCDPlay: set up internal structures so seeking/reading places an item. itemid: the thing to play. user_entry: true if itemid is a user selection (rather than internally- - generated selection such as via PBC) in which case we may have to adjust - for differences in numbering. + generated selection such as via PBC) in which case we may have to adjust + for differences in numbering. *****************************************************************************/ int VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid ) { thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data; input_area_t * p_area; - - p_vcd->in_still = 0; + + dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n", + itemid.num, itemid.type); + + if (!p_input->p_access_data) return VLC_EGENERIC; + + p_vcd->in_still = false; + p_vcd->cur_lid = VCDINFO_INVALID_LID; #define area p_input->stream.pp_areas @@ -594,22 +438,22 @@ VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid ) p_area->i_part = p_area->i_plugin_data; p_input->stream.b_seekable = 1; break; - case VCDINFO_ITEM_TYPE_SEGMENT: + case VCDINFO_ITEM_TYPE_SEGMENT: /* Valid segments go from 0...num_segments-1. */ if (itemid.num >= p_vcd->num_segments) { LOG_ERR ( "Invalid segment number: %d", itemid.num ); return VLC_EGENERIC; } else { - vcdinfo_video_segment_type_t segtype = + vcdinfo_video_segment_type_t segtype = vcdinfo_get_video_type(p_vcd->vcd, itemid.num); - - dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d", - vcdinfo_video_type2str(p_vcd->vcd, itemid.num), + + dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d", + vcdinfo_video_type2str(p_vcd->vcd, itemid.num), (int) segtype, itemid.num); - + p_area = area[0]; p_area->i_part = itemid.num; - + switch (segtype) { case VCDINFO_FILES_VIDEO_NTSC_STILL: @@ -617,15 +461,15 @@ VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid ) case VCDINFO_FILES_VIDEO_PAL_STILL: case VCDINFO_FILES_VIDEO_PAL_STILL2: p_input->stream.b_seekable = 0; - p_vcd->in_still = -5; + p_vcd->in_still = true; break; default: p_input->stream.b_seekable = 1; - p_vcd->in_still = 0; + p_vcd->in_still = false; } } break; - + case VCDINFO_ITEM_TYPE_LID: /* LIDs go from 1..num_lids. */ if (itemid.num == 0 || itemid.num > p_vcd->num_lids) { @@ -634,14 +478,14 @@ VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid ) } else { p_vcd->cur_lid = itemid.num; vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num); - + switch (p_vcd->pxd.descriptor_type) { - + case PSD_TYPE_SELECTION_LIST: case PSD_TYPE_EXT_SELECTION_LIST: { vcdinfo_itemid_t trans_itemid; uint16_t trans_itemid_num; - + if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC; trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd); vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid); @@ -650,18 +494,18 @@ VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid ) return VCDPlay( p_input, trans_itemid ); break; } - + case PSD_TYPE_PLAY_LIST: { if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC; p_vcd->pdi = -1; - return vcdplayer_inc_play_item(p_input) + return vcdplayer_inc_play_item(p_input) ? VLC_SUCCESS : VLC_EGENERIC; break; } - + case PSD_TYPE_END_LIST: case PSD_TYPE_COMMAND_LIST: - + default: ; } @@ -690,11 +534,11 @@ VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid ) p_vcd->play_item = itemid; - dbg_print( (INPUT_DBG_CALL), - "i_start %lld, i_size: %lld, i_tell: %lld, lsn %d", - p_area->i_start, p_area->i_size, + dbg_print( (INPUT_DBG_CALL), + "i_start %lld, i_size: %lld, i_tell: %lld, lsn %d", + p_area->i_start, p_area->i_size, p_area->i_tell, p_vcd->cur_lsn ); - + return VLC_SUCCESS; } @@ -703,7 +547,7 @@ VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid ) and initializes area information with that. Before calling this track information should have been read in. *****************************************************************************/ -static int +static int VCDEntryPoints( input_thread_t * p_input ) { thread_vcd_data_t * p_vcd; @@ -714,9 +558,9 @@ VCDEntryPoints( input_thread_t * p_input ) p_vcd = (thread_vcd_data_t *) p_input->p_access_data; i_nb = vcdinfo_get_num_entries(p_vcd->vcd); - if (0 == i_nb) + if (0 == i_nb) return -1; - + p_vcd->p_entries = malloc( sizeof( lba_t ) * i_nb ); if( p_vcd->p_entries == NULL ) @@ -732,7 +576,7 @@ VCDEntryPoints( input_thread_t * p_input ) track_t i_track = vcdinfo_get_track(p_vcd->vcd, i); if( i_track <= p_input->stream.i_area_nb ) { - p_vcd->p_entries[i] = + p_vcd->p_entries[i] = vcdinfo_get_entry_lsn(p_vcd->vcd, i); p_input->stream.pp_areas[i_track]->i_part_nb ++; @@ -764,7 +608,7 @@ VCDSegments( input_thread_t * p_input ) thread_vcd_data_t * p_vcd; unsigned int i; unsigned int num_segments; - + p_vcd = (thread_vcd_data_t *) p_input->p_access_data; num_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd); @@ -776,23 +620,24 @@ VCDSegments( input_thread_t * p_input ) area[0]->i_plugin_data = 0; input_DelArea( p_input, area[0] ); input_AddArea( p_input, 0, 0 ); - - area[0]->i_start = (off_t)p_vcd->p_sectors[0] + + area[0]->i_start = (off_t)p_vcd->p_sectors[0] * (off_t)M2F2_SECTOR_SIZE; area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0]) * (off_t)M2F2_SECTOR_SIZE; - + /* Default Segment */ area[0]->i_part = 0; - + /* i_plugin_data is used to store which entry point is the first of the track (area) */ area[0]->i_plugin_data = 0; area[0]->i_part_nb = 0; - - dbg_print( INPUT_DBG_MRL, "area id %d, for segment track %d", - area[0]->i_id, 0 ); + + dbg_print( INPUT_DBG_MRL, + "area[0] id: %d, i_start: %lld, i_size: %lld", + area[0]->i_id, area[0]->i_start, area[0]->i_size ); if (num_segments == 0) return 0; @@ -809,12 +654,12 @@ VCDSegments( input_thread_t * p_input ) /* Update the navigation variables without triggering a callback */ VCDUpdateVar( p_input, 0, VLC_VAR_SETVALUE, "title", "Setting track" ); var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL ); - + for( i = 0 ; i < num_segments ; i++ ) { p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i); area[0]->i_part_nb ++; - VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE, + VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE, "chapter", "Adding segment choice"); } @@ -822,12 +667,12 @@ VCDSegments( input_thread_t * p_input ) p_vcd->p_segments[num_segments] = p_vcd->p_segments[num_segments-1]+ vcdinfo_get_seg_sector_count(p_vcd->vcd, num_segments-1); - + return 0; } /***************************************************************************** - VCDTracks: initializes area information. + VCDTracks: initializes area information. Before calling this track information should have been read in. *****************************************************************************/ static void @@ -849,7 +694,7 @@ VCDTracks( input_thread_t * p_input ) input_AddArea( p_input, i, i ); /* Absolute start byte offset and byte size */ - area[i]->i_start = (off_t) p_vcd->p_sectors[i] + area[i]->i_start = (off_t) p_vcd->p_sectors[i] * (off_t)M2F2_SECTOR_SIZE; area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i]) * (off_t)M2F2_SECTOR_SIZE; @@ -861,8 +706,8 @@ VCDTracks( input_thread_t * p_input ) * of the track (area) */ area[i]->i_plugin_data = 0; - dbg_print( INPUT_DBG_MRL, - "area[%d] id: %d, i_start: %lld, i_size: %lld", + dbg_print( INPUT_DBG_MRL, + "area[%d] id: %d, i_start: %lld, i_size: %lld", i, area[i]->i_id, area[i]->i_start, area[i]->i_size ); } @@ -874,7 +719,7 @@ VCDTracks( input_thread_t * p_input ) /***************************************************************************** VCDLIDs: Reads the LIST IDs from the LOT. *****************************************************************************/ -static int +static int VCDLIDs( input_thread_t * p_input ) { thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data; @@ -883,14 +728,22 @@ VCDLIDs( input_thread_t * p_input ) p_vcd->cur_lid = VCDINFO_INVALID_ENTRY; if (vcdinfo_read_psd (p_vcd->vcd)) { - + vcdinfo_visit_lot (p_vcd->vcd, false); - + +#if FIXED + /* + We need to change libvcdinfo to be more robust when there are + problems reading the extended PSD. Given that area-highlighting and + selection features in the extended PSD haven't been implemented, + it's best then to not try to read this at all. + */ if (vcdinfo_get_psd_x_size(p_vcd->vcd)) vcdinfo_visit_lot (p_vcd->vcd, true); +#endif } - dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL), + dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL), "num LIDs=%d", p_vcd->num_lids); return 0; @@ -899,17 +752,24 @@ VCDLIDs( input_thread_t * p_input ) /***************************************************************************** * VCDParse: parse command line *****************************************************************************/ -static char * -VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid ) +static char * +VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid, + /*out*/ bool *play_single_item ) { thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data; char * psz_parser; char * psz_source; char * psz_next; - p_itemid->type=VCDINFO_ITEM_TYPE_TRACK; - p_itemid->num=1; - + if ( config_GetInt( p_input, MODULE_STRING "-PBC" ) ) { + p_itemid->type=VCDINFO_ITEM_TYPE_LID; + p_itemid->num=1; + *play_single_item=false; + } else { + p_itemid->type=VCDINFO_ITEM_TYPE_ENTRY; + p_itemid->num=0; + } + #ifdef WIN32 /* On Win32 we want the VCD access plugin to be explicitly requested, * we end up with lots of problems otherwise */ @@ -932,65 +792,85 @@ VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid ) if( *psz_parser == '@' ) { - /* Found the divide between the source name and the + /* Found the divide between the source name and the type+entry number. */ unsigned int num; - + *psz_parser = '\0'; ++psz_parser; if( *psz_parser ) { switch(*psz_parser) { - case 'E': + case 'E': p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY; ++psz_parser; + *play_single_item = true; break; - case 'P': + case 'P': p_itemid->type = VCDINFO_ITEM_TYPE_LID; ++psz_parser; + *play_single_item = false; break; - case 'S': + case 'S': p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT; ++psz_parser; + *play_single_item = true; break; - case 'T': + case 'T': p_itemid->type = VCDINFO_ITEM_TYPE_TRACK; ++psz_parser; + *play_single_item = true; break; default: ; } } - + num = strtol( psz_parser, &psz_next, 10 ); - if ( *psz_parser != '\0' && *psz_next == '\0') + if ( *psz_parser != '\0' && *psz_next == '\0') { p_itemid->num = num; } - + + } else { + *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type ); } - if( !*psz_source ) - { - if( !p_input->psz_access ) - { - return NULL; + + if( !*psz_source ) { + + /* No source specified, so figure it out. */ + if( !p_input->psz_access ) return NULL; + + psz_source = config_GetPsz( p_input, "vcd" ); + + if( !psz_source || 0==strlen(psz_source) ) { + /* Scan for a CD-ROM drive with a VCD in it. */ + char **cd_drives = cdio_get_devices_with_cap(NULL, + (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD + |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN), + true); + if (NULL == cd_drives) return NULL; + if (cd_drives[0] == NULL) { + cdio_free_device_list(cd_drives); + return NULL; } - psz_source = config_GetPsz( p_input, "vcd" ); - if( !psz_source ) return NULL; + psz_source = strdup(cd_drives[0]); + cdio_free_device_list(cd_drives); + } } - dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL), + dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL), "source=%s entry=%d type=%d", psz_source, p_itemid->num, p_itemid->type); return psz_source; } -/* +/* Set's start origin subsequent seeks/reads */ -static void -VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn, +static void +VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn, lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t cur_track ) { thread_vcd_data_t * p_vcd = (thread_vcd_data_t *) p_input->p_access_data; @@ -1001,7 +881,7 @@ VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn, p_vcd->cur_track = cur_track; p_vcd->play_item.num = cur_entry; p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY; - + dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN), "origin: %d, cur_lsn: %d, end_lsn: %d, entry: %d, track: %d", origin_lsn, cur_lsn, end_lsn, cur_entry, cur_track ); @@ -1009,7 +889,7 @@ VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn, p_input->stream.p_selected_area->i_tell = (off_t) (p_vcd->cur_lsn - p_vcd->origin_lsn) * (off_t)M2F2_SECTOR_SIZE; - VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE, + VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE, "chapter", "Setting entry"); } @@ -1024,13 +904,8 @@ vcd_Open( vlc_object_t *p_this, const char *psz_dev ) if( !psz_dev ) return NULL; - /* Set where to log errors messages from libcdio. */ - p_vcd_input = (input_thread_t *)p_this; - cdio_log_set_handler ( cdio_log_handler ); - vcd_log_set_handler ( vcd_log_handler ); - actual_dev=strdup(psz_dev); - if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) != + if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) != VCDINFO_OPEN_VCD) { free(actual_dev); return NULL; @@ -1043,7 +918,7 @@ vcd_Open( vlc_object_t *p_this, const char *psz_dev ) /**************************************************************************** * VCDReadSector: Read a sector (2324 bytes) ****************************************************************************/ -static int +static int VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd, lsn_t cur_lsn, byte_t * p_buffer ) { @@ -1052,17 +927,17 @@ VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd, uint8_t data [M2F2_SECTOR_SIZE]; } vcdsector_t; vcdsector_t vcd_sector; - - if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd), - &vcd_sector, cur_lsn, true) + + if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd), + &vcd_sector, cur_lsn, true) != 0) { msg_Warn( p_this, "Could not read LSN %d", cur_lsn ); return -1; } - + memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE); - + return( 0 ); } @@ -1081,4 +956,540 @@ VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action, } var_Change( p_input, varname, i_action, &val, NULL ); } + + +#define meta_info_add_str(title, str) \ + if ( str ) { \ + dbg_print( INPUT_DBG_META, "field: %s: %s\n", title, str); \ + input_AddInfo( p_cat, _(title), "%s", str ); \ + } + +#define meta_info_add_num(title, num) \ + dbg_print( INPUT_DBG_META, "field %s: %d\n", title, num); \ + input_AddInfo( p_cat, _(title), "%d", num ); \ + +static void InformationCreate( input_thread_t *p_input ) +{ + thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data; + input_info_category_t *p_cat; + + p_cat = input_InfoCategory( p_input, "General" ); + + meta_info_add_str( "VCD Format", vcdinfo_get_format_version_str(p_vcd->vcd)); + meta_info_add_str( "Album", vcdinfo_get_album_id(p_vcd->vcd)); + meta_info_add_str( "Application",vcdinfo_get_application_id(p_vcd->vcd)); + meta_info_add_str( "Preparer", vcdinfo_get_preparer_id(p_vcd->vcd)); + meta_info_add_num( "Vol #", vcdinfo_get_volume_num(p_vcd->vcd)); + meta_info_add_num( "Vol max #", vcdinfo_get_volume_count(p_vcd->vcd)); + meta_info_add_str( "Volume Set", vcdinfo_get_volumeset_id(p_vcd->vcd)); + meta_info_add_str( "Volume", vcdinfo_get_volume_id(p_vcd->vcd)); + meta_info_add_str( "Publisher", vcdinfo_get_publisher_id(p_vcd->vcd)); + meta_info_add_str( "System Id", vcdinfo_get_system_id(p_vcd->vcd)); + meta_info_add_num( "LIDs", vcdinfo_get_num_LIDs(p_vcd->vcd)); + meta_info_add_num( "Entries", vcdinfo_get_num_entries(p_vcd->vcd)); + meta_info_add_num( "Segments", vcdinfo_get_num_segments(p_vcd->vcd)); + meta_info_add_num( "Tracks", vcdinfo_get_num_tracks(p_vcd->vcd)); + +} + +#define add_format_str_info(val) \ + { \ + const char *str = val; \ + unsigned int len; \ + if (val != NULL) { \ + len=strlen(str); \ + if (len != 0) { \ + strncat(tp, str, TEMP_STR_LEN-(tp-temp_str)); \ + tp += len; \ + } \ + saw_control_prefix = false; \ + } \ + } + +#define add_format_num_info(val, fmt) \ + { \ + char num_str[10]; \ + unsigned int len; \ + sprintf(num_str, fmt, val); \ + len=strlen(num_str); \ + if (len != 0) { \ + strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str)); \ + tp += len; \ + } \ + saw_control_prefix = false; \ + } + +/*! + Take a format string and expand escape sequences, that is sequences that + begin with %, with information from the current VCD. + The expanded string is returned. Here is a list of escape sequences: + + %A : The album information + %C : The VCD volume count - the number of CD's in the collection. + %c : The VCD volume num - the number of the CD in the collection. + %F : The VCD Format, e.g. VCD 1.0, VCD 1.1, VCD 2.0, or SVCD + %I : The current entry/segment/playback type, e.g. ENTRY, TRACK, SEGMENT... + %L : The playlist ID prefixed with " LID" if it exists + %M : MRL + %N : The current number of the %I - a decimal number + %P : The publisher ID + %p : The preparer ID + %S : If we are in a segment (menu), the kind of segment + %T : The track number + %V : The volume set ID + %v : The volume ID + A number between 1 and the volume count. + %% : a % +*/ +static char * +VCDFormatStr(const input_thread_t *p_input, thread_vcd_data_t *p_vcd, + const char format_str[], const char *mrl, + const vcdinfo_itemid_t *itemid) +{ +#define TEMP_STR_SIZE 256 +#define TEMP_STR_LEN (TEMP_STR_SIZE-1) + static char temp_str[TEMP_STR_SIZE]; + size_t i; + char * tp = temp_str; + bool saw_control_prefix = false; + size_t format_len = strlen(format_str); + + bzero(temp_str, TEMP_STR_SIZE); + + for (i=0; ivcd), + MAX_ALBUM_LEN)); + break; + + case 'c': + add_format_num_info(vcdinfo_get_volume_num(p_vcd->vcd), "%d"); + break; + + case 'C': + add_format_num_info(vcdinfo_get_volume_count(p_vcd->vcd), "%d"); + break; + + case 'F': + add_format_str_info(vcdinfo_get_format_version_str(p_vcd->vcd)); + break; + + case 'I': + { + switch (itemid->type) { + case VCDINFO_ITEM_TYPE_TRACK: + strncat(tp, _("Track"), TEMP_STR_LEN-(tp-temp_str)); + tp += strlen(_("Track")); + break; + case VCDINFO_ITEM_TYPE_ENTRY: + strncat(tp, _("Entry"), TEMP_STR_LEN-(tp-temp_str)); + tp += strlen(_("Entry")); + break; + case VCDINFO_ITEM_TYPE_SEGMENT: + strncat(tp, _("Segment"), TEMP_STR_LEN-(tp-temp_str)); + tp += strlen(_("Segment")); + break; + case VCDINFO_ITEM_TYPE_LID: + strncat(tp, _("List ID"), TEMP_STR_LEN-(tp-temp_str)); + tp += strlen(_("List ID")); + break; + case VCDINFO_ITEM_TYPE_SPAREID2: + strncat(tp, _("Navigation"), TEMP_STR_LEN-(tp-temp_str)); + tp += strlen(_("Navigation")); + break; + default: + /* What to do? */ + ; + } + saw_control_prefix = false; + } + break; + + case 'L': + if (vcdplayer_pbc_is_on(p_vcd)) { + char num_str[40]; + sprintf(num_str, "%s %d", _("List ID"), p_vcd->cur_lid); + strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str)); + tp += strlen(num_str); + } + saw_control_prefix = false; + break; + + case 'M': + add_format_str_info(mrl); + break; + + case 'N': + add_format_num_info(itemid->num, "%d"); + break; + + case 'p': + add_format_str_info(vcdinfo_get_preparer_id(p_vcd->vcd)); + break; + + case 'P': + add_format_str_info(vcdinfo_get_publisher_id(p_vcd->vcd)); + break; + + case 'S': + if ( VCDINFO_ITEM_TYPE_SEGMENT==itemid->type ) { + char seg_type_str[10]; + + sprintf(seg_type_str, " %s", + vcdinfo_video_type2str(p_vcd->vcd, itemid->num)); + strncat(tp, seg_type_str, TEMP_STR_LEN-(tp-temp_str)); + tp += strlen(seg_type_str); + } + saw_control_prefix = false; + break; + + case 'T': + add_format_num_info(p_vcd->cur_track, "%d"); + break; + + case 'V': + add_format_str_info(vcdinfo_get_volumeset_id(p_vcd->vcd)); + break; + + case 'v': + add_format_str_info(vcdinfo_get_volume_id(p_vcd->vcd)); + break; + + default: + *tp++ = '%'; + *tp++ = format_str[i]; + saw_control_prefix = false; + } + } + return strdup(temp_str); +} + +static void +VCDCreatePlayListItem(const input_thread_t *p_input, + thread_vcd_data_t *p_vcd, + playlist_t *p_playlist, + const vcdinfo_itemid_t *itemid, + char *psz_mrl, int psz_mrl_max, + const char *psz_source, int playlist_operation, + int i_pos) +{ + mtime_t i_duration = -1; + char *p_author; + char *p_title; + char c_type; + + switch(itemid->type) { + case VCDINFO_ITEM_TYPE_TRACK: + c_type='T'; + break; + case VCDINFO_ITEM_TYPE_SEGMENT: + c_type='S'; + break; + case VCDINFO_ITEM_TYPE_LID: + c_type='P'; + break; + case VCDINFO_ITEM_TYPE_ENTRY: + c_type='E'; + break; + default: + c_type='?'; + break; + } + + snprintf(psz_mrl, psz_mrl_max, "%s%s@%c%u", VCD_MRL_PREFIX, psz_source, + c_type, itemid->num); + + p_title = + VCDFormatStr( p_input, p_vcd, + config_GetPsz( p_input, MODULE_STRING "-title-format" ), + psz_mrl, itemid ); + + playlist_AddExt( p_playlist, psz_mrl, p_title, i_duration, + 0, 0, playlist_operation, i_pos ); + + p_author = + VCDFormatStr( p_input, p_vcd, + config_GetPsz( p_input, MODULE_STRING "-author-format" ), + psz_mrl, itemid ); + + /* FIXME: This is horrible, but until the playlist interface is fixed up + something like this has to be done for the "Author" field. + */ + if( i_pos == PLAYLIST_END ) i_pos = p_playlist->i_size - 1; + free(p_playlist->pp_items[i_pos]->psz_author); + p_playlist->pp_items[i_pos]->psz_author = strdup(p_author); +} + +static int +VCDFixupPlayList( input_thread_t *p_input, thread_vcd_data_t *p_vcd, + const char *psz_source, vcdinfo_itemid_t *itemid, + bool play_single_item ) +{ + unsigned int i; + playlist_t * p_playlist; + char * psz_mrl; + unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX) + strlen(psz_source) + + strlen("@T") + strlen("100") + 1; + + psz_mrl = malloc( psz_mrl_max ); + + if( psz_mrl == NULL ) + { + msg_Warn( p_input, "out of memory" ); + return -1; + } + + p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( !p_playlist ) + { + msg_Warn( p_input, "can't find playlist" ); + free(psz_mrl); + return -1; + } + + InformationCreate( p_input ); + + if ( play_single_item ) { + /* May fill out more information when the playlist user interface becomes + more mature. + */ + VCDCreatePlayListItem(p_input, p_vcd, p_playlist, itemid, + psz_mrl, psz_mrl_max, psz_source, PLAYLIST_REPLACE, + p_playlist->i_index); + } else { + vcdinfo_itemid_t list_itemid; + list_itemid.type=VCDINFO_ITEM_TYPE_ENTRY; + + playlist_Delete( p_playlist, p_playlist->i_index); + + for( i = 0 ; i < p_vcd->num_entries ; i++ ) + { + list_itemid.num=i; + VCDCreatePlayListItem(p_input, p_vcd, p_playlist, &list_itemid, + psz_mrl, psz_mrl_max, psz_source, + PLAYLIST_APPEND, PLAYLIST_END); + } + + playlist_Command( p_playlist, PLAYLIST_GOTO, 0 ); + + } + + vlc_object_release( p_playlist ); + free(psz_mrl); + return 0; +} + +/***************************************************************************** + * Public routines. + *****************************************************************************/ +int +E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name, + vlc_value_t oldval, vlc_value_t val, void *p_data ) +{ + thread_vcd_data_t *p_vcd; + + if (NULL == p_vcd_input) return VLC_EGENERIC; + + p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data; + + if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) { + msg_Dbg( p_vcd_input, "Old debug (x%0x) %d, new debug (x%0x) %d", + p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int); + } + p_vcd->i_debug = val.i_int; + return VLC_SUCCESS; +} + +/***************************************************************************** + Open: open VCD. + read in meta-information about VCD: the number of tracks, segments, + entries, size and starting information. Then set up state variables so + that we read/seek starting at the location specified. + + On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM, + and VLC_EGENERIC for some other error. + *****************************************************************************/ +int +E_(Open) ( vlc_object_t *p_this ) +{ + input_thread_t * p_input = (input_thread_t *)p_this; + thread_vcd_data_t * p_vcd; + char * psz_source; + vcdinfo_itemid_t itemid; + bool b_play_ok; + bool play_single_item = false; + + p_input->pf_read = VCDRead; + p_input->pf_seek = VCDSeek; + p_input->pf_set_area = VCDSetArea; + p_input->pf_set_program = VCDSetProgram; + + p_vcd = malloc( sizeof(thread_vcd_data_t) ); + + if( p_vcd == NULL ) + { + LOG_ERR ("out of memory" ); + return VLC_ENOMEM; + } + + p_input->p_access_data = (void *)p_vcd; + p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" ); + + /* Set where to log errors messages from libcdio. */ + p_vcd_input = (input_thread_t *)p_this; + cdio_log_set_handler ( cdio_log_handler ); + vcd_log_set_handler ( vcd_log_handler ); + + psz_source = VCDParse( p_input, &itemid, &play_single_item ); + + if ( NULL == psz_source ) + { + free( p_vcd ); + return( VLC_EGENERIC ); + } + + dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s", + psz_source, p_input->psz_name ); + + p_vcd->p_segments = NULL; + p_vcd->p_entries = NULL; + + /* set up input */ + p_input->i_mtu = VCD_DATA_ONCE; + + 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; + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) ) + { + msg_Warn( p_input, "could not open %s", psz_source ); + goto err_exit; + } + + /* Get track information. */ + p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input), + vcdinfo_get_cd_image(p_vcd->vcd), + &p_vcd->p_sectors ); + if( p_vcd->num_tracks < 0 ) + LOG_ERR ("unable to count tracks" ); + else if( p_vcd->num_tracks <= 1 ) + LOG_ERR ("no movie tracks found" ); + if( p_vcd->num_tracks <= 1) + { + vcdinfo_close( p_vcd->vcd ); + goto err_exit; + } + + /* 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; + + + /* Initialize segment information. */ + VCDSegments( p_input ); + + /* Initialize track area information. */ + VCDTracks( p_input ); + + if( VCDEntryPoints( p_input ) < 0 ) + { + msg_Warn( p_input, "could not read entry points, will not use them" ); + p_vcd->b_valid_ep = false; + } + + if( VCDLIDs( p_input ) < 0 ) + { + msg_Warn( p_input, "could not read entry LIDs" ); + } + + b_play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid )); + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + if ( ! b_play_ok ) { + vcdinfo_close( p_vcd->vcd ); + goto err_exit; + } + + if( !p_input->psz_demux || !*p_input->psz_demux ) + { +#if FIXED + p_input->psz_demux = "vcdx"; +#else + p_input->psz_demux = "ps"; #endif + } + + p_vcd->p_intf = intf_Create( p_input, "vcdx" ); + p_vcd->p_intf->b_block = VLC_FALSE; + intf_RunThread( p_vcd->p_intf ); + + VCDFixupPlayList( p_input, p_vcd, psz_source, &itemid, play_single_item ); + + free( psz_source ); + + return VLC_SUCCESS; + err_exit: + free( psz_source ); + free( p_vcd ); + return VLC_EGENERIC; +} + +/***************************************************************************** + * Close: closes VCD releasing allocated memory. + *****************************************************************************/ +void +E_(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; + + dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" ); + vcdinfo_close( p_vcd->vcd ); + + free( p_vcd->p_entries ); + free( p_vcd->p_segments ); + + /* For reasons that are a mystery to me we don't have to deal with + stopping, and destroying the p_vcd->p_intf thread. And if we do + it causes problems upstream. + */ + if( p_vcd->p_intf != NULL ) + { + p_vcd->p_intf = NULL; + } + + free( p_vcd ); + p_input->p_access_data = NULL; + p_vcd_input = NULL; +}